Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stellar smart contract #24

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/lib/stores/contractStore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { persisted } from 'svelte-local-storage-store'
import { v4 as uuidv4 } from 'uuid'
import { Contract, StrKey } from '@stellar/stellar-sdk'
import { error } from '@sveltejs/kit'
import { get } from 'svelte/store'

/**
* @typedef {Object} SavedContract
* @property {string} id Unique identifier for this contract
* @property {string} contractId The Stellar contract ID
* @property {string} name Human-readable name for this contract
* @property {string} [description] Optional description of the contract
*/

function createContractStore() {
/** @type {import('svelte/store').Writable<{savedContracts: SavedContract[], currentContract: SavedContract|null}>} */
const { subscribe, set, update } = persisted('bpa:contractStore', {
savedContracts: [],
currentContract: null
})

return {
subscribe,

/**
* Saves a new contract to the store
* @param {SavedContract} contract Contract details to save
* @throws Will throw an error if the contract ID is invalid
*/
saveContract: (contract) =>
update(store => {
if (!StrKey.isValidContract(contract.contractId)) {
throw error(400, { message: 'Invalid contract ID' })
}

const newContract = {
...contract,
id: contract.id || uuidv4()
}

return {
...store,
savedContracts: [...store.savedContracts, newContract]
}
}),

/**
* Removes a contract from the store
* @param {string} id Unique identifier of the contract to remove
*/
removeContract: (id) =>
update(store => ({
...store,
savedContracts: store.savedContracts.filter(c => c.id !== id),
currentContract: store.currentContract?.id === id ? null : store.currentContract
})),

/**
* Sets the current active contract
* @param {SavedContract|null} contract Contract to set as current, or null to clear
*/
setCurrentContract: (contract) =>
update(store => ({
...store,
currentContract: contract
})),

/**
* Looks up a contract by its Stellar contract ID
* @param {string} contractId Stellar contract ID to look up
* @returns {SavedContract|undefined} The found contract or undefined
*/
lookup: (contractId) => {
const store = get(contractStore)
return store.savedContracts.find(contract => contract.contractId === contractId)
},

/**
* Clears all saved contracts from the store
*/
empty: () => set({ savedContracts: [], currentContract: null })
}
}

export const contractStore = createContractStore()
38 changes: 38 additions & 0 deletions src/lib/utils/contractUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { StrKey } from 'stellar-sdk';
import { Contract } from '@stellar/stellar-sdk';

/**
* Generates a contract client for interacting with a Stellar smart contract
* @param {string} contractId - The contract ID to validate and connect to
* @param {Server} server - Stellar SDK Server instance
* @returns {Promise<Contract>} A Contract instance
*/
export async function generateContractClient(contractId, server) {
try {
// Validate contract ID
if (!StrKey.isValidContract(contractId)) {
throw new Error('Invalid contract ID format');
}

try {
// Get the contract's WASM using the correct method
const contractResponse = await server.getContractWasmByContractId(contractId);

// Create contract instance
const contract = new Contract(contractId);

// You might want to add the contract's interface here
// This could involve parsing the WASM to get available methods

return contract;
} catch (serverError) {
if (serverError.response && serverError.response.status === 404) {
throw new Error(`Contract not found: ${contractId}`);
}
throw serverError;
}
} catch (error) {
console.error('Error generating contract client:', error);
throw new Error(`Failed to generate contract client: ${error.message}`);
}
Ugo-X marked this conversation as resolved.
Show resolved Hide resolved
}
1 change: 1 addition & 0 deletions src/routes/dashboard/components/SidebarMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ list of menu links that can be used to navigate throughout the dashboard.
{ route: '/dashboard/assets', text: 'Assets' },
{ route: '/dashboard/contacts', text: 'Contacts' },
{ route: '/dashboard/transfers', text: 'Transfers' },
{ route: '/dashboard/contracts', text: 'Smart Contracts' }
]
</script>

Expand Down
93 changes: 93 additions & 0 deletions src/routes/dashboard/contracts/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<script lang="ts">
import { contractStore } from '$lib/stores/contractStore';
import { generateContractClient } from '$lib/utils/contractUtils';
import SorobanRpc from 'stellar-sdk';

let contractId = '';
let contractName = '';
let error = '';
let loading = false;

const server = new SorobanRpc.Server('https://soroban-testnet.stellar.org');

async function handleLoadContract() {
loading = true;
error = '';

try {
const contract = await generateContractClient(contractId, server);
$contractStore.setCurrentContract(contract);

// Optionally save the contract
if (contractName) {
$contractStore.saveContract({
id: contractId,
name: contractName,
network: 'TESTNET' // or 'PUBLIC' for mainnet
});
}
} catch (err) {
error = err.message;
} finally {
loading = false;
}
}
</script>

<div class="container mx-auto p-4">
<h1 class="text-2xl font-bold mb-4">Stellar Smart Contract Interaction</h1>

<div class="mb-4">
<label class="block text-sm font-medium mb-1" for="contractId">
Contract ID
</label>
<input
id="contractId"
type="text"
bind:value={contractId}
placeholder="Enter contract ID (C...)"
class="w-full p-2 border rounded"
/>
</div>

<div class="mb-4">
<label class="block text-sm font-medium mb-1" for="contractName">
Contract Name (optional)
</label>
<input
id="contractName"
type="text"
bind:value={contractName}
placeholder="Enter a name for this contract"
class="w-full p-2 border rounded"
/>
</div>

<button
on:click={handleLoadContract}
disabled={loading}
class="bg-blue-500 text-white px-4 py-2 rounded"
>
{loading ? 'Loading...' : 'Load Contract'}
</button>

{#if error}
<div class="text-red-500 mt-2">{error}</div>
{/if}

<h2 class="text-xl font-bold mt-8 mb-4">Saved Contracts</h2>
{#each $contractStore.savedContracts as contract}
<div class="border p-4 rounded mb-2 flex justify-between items-center">
<div>
<span class="font-medium">{contract.name || 'Unnamed Contract'}</span>
<span class="text-sm text-gray-500 block">{contract.id}</span>
</div>
<button
on:click={() => contractId = contract.id}
class="bg-gray-200 px-3 py-1 rounded"
>
Load
</button>
</div>
{/each}
</div>