From 68c0f56c90cc3062a75004ba7f181a46986d38f2 Mon Sep 17 00:00:00 2001 From: Ugo-X Date: Tue, 1 Oct 2024 18:26:38 +0100 Subject: [PATCH 1/4] stellar smart contract --- src/lib/stores/contractStore.js | 33 +++++++ src/lib/utils/contractUtils.js | 24 +++++ .../dashboard/components/SidebarMenu.svelte | 1 + src/routes/dashboard/contracts/+page.svelte | 93 +++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 src/lib/stores/contractStore.js create mode 100644 src/lib/utils/contractUtils.js create mode 100644 src/routes/dashboard/contracts/+page.svelte diff --git a/src/lib/stores/contractStore.js b/src/lib/stores/contractStore.js new file mode 100644 index 0000000..e1d3c88 --- /dev/null +++ b/src/lib/stores/contractStore.js @@ -0,0 +1,33 @@ +import { writable } from 'svelte/store'; +import Contract from 'stellar-sdk'; + +function createContractStore() { + const { subscribe, set, update } = writable({ + savedContracts: loadSavedContracts() + }); + + return { + subscribe, + saveContract: (contract) => update(store => { + const newSavedContracts = [...store.savedContracts, contract]; + localStorage.setItem('savedContracts', JSON.stringify(newSavedContracts)); + return { ...store, savedContracts: newSavedContracts }; + }), + removeContract: (contractId) => update(store => { + const newSavedContracts = store.savedContracts.filter(c => c.id !== contractId); + localStorage.setItem('savedContracts', JSON.stringify(newSavedContracts)); + return { ...store, savedContracts: newSavedContracts }; + }), + setCurrentContract: (contract) => update(store => ({ + ...store, + currentContract: contract + })) + }; +} + +function loadSavedContracts() { + const saved = localStorage.getItem('savedContracts'); + return saved ? JSON.parse(saved) : []; +} + +export const contractStore = createContractStore(); \ No newline at end of file diff --git a/src/lib/utils/contractUtils.js b/src/lib/utils/contractUtils.js new file mode 100644 index 0000000..87bff80 --- /dev/null +++ b/src/lib/utils/contractUtils.js @@ -0,0 +1,24 @@ +import Contract from 'stellar-sdk'; + +export async function generateContractClient(contractId, server) { + try { + // Validate contract ID format + if (!contractId.match(/^C[A-Z2-7]{55}$/)) { + throw new Error('Invalid contract ID format'); + } + + // Get the contract's footprint which includes the WASM hash + const footprintResponse = await server.getFootprint(contractId); + + // Create contract instance + const contract = new Contract(contractId); + + // You might want to add the contract's interface here + // This would involve parsing the WASM to get available methods + + return contract; + } catch (error) { + console.error('Error generating contract client:', error); + throw new Error(`Failed to generate contract client: ${error.message}`); + } +} \ No newline at end of file diff --git a/src/routes/dashboard/components/SidebarMenu.svelte b/src/routes/dashboard/components/SidebarMenu.svelte index c172e89..721a8af 100644 --- a/src/routes/dashboard/components/SidebarMenu.svelte +++ b/src/routes/dashboard/components/SidebarMenu.svelte @@ -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' } ] diff --git a/src/routes/dashboard/contracts/+page.svelte b/src/routes/dashboard/contracts/+page.svelte new file mode 100644 index 0000000..3121440 --- /dev/null +++ b/src/routes/dashboard/contracts/+page.svelte @@ -0,0 +1,93 @@ + + +
+

Stellar Smart Contract Interaction

+ +
+ + +
+ +
+ + +
+ + + + {#if error} +
{error}
+ {/if} + +

Saved Contracts

+ {#each $contractStore.savedContracts as contract} +
+
+ {contract.name || 'Unnamed Contract'} + {contract.id} +
+ +
+ {/each} +
\ No newline at end of file From e727176326abb53a26e0040b0642c1e1e4ea4bd6 Mon Sep 17 00:00:00 2001 From: Ugo-X Date: Wed, 9 Oct 2024 15:53:59 +0100 Subject: [PATCH 2/4] all comments fixed --- src/lib/stores/contractStore.js | 102 ++++++++++++++++++++++++-------- src/lib/utils/contractUtils.js | 40 +++++++++---- 2 files changed, 104 insertions(+), 38 deletions(-) diff --git a/src/lib/stores/contractStore.js b/src/lib/stores/contractStore.js index e1d3c88..58c6e3f 100644 --- a/src/lib/stores/contractStore.js +++ b/src/lib/stores/contractStore.js @@ -1,33 +1,85 @@ -import { writable } from 'svelte/store'; -import Contract from 'stellar-sdk'; +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() { - const { subscribe, set, update } = writable({ - savedContracts: loadSavedContracts() - }); + /** @type {import('svelte/store').Writable<{savedContracts: SavedContract[], currentContract: SavedContract|null}>} */ + const { subscribe, set, update } = persisted('bpa:contractStore', { + savedContracts: [], + currentContract: null + }) return { subscribe, - saveContract: (contract) => update(store => { - const newSavedContracts = [...store.savedContracts, contract]; - localStorage.setItem('savedContracts', JSON.stringify(newSavedContracts)); - return { ...store, savedContracts: newSavedContracts }; - }), - removeContract: (contractId) => update(store => { - const newSavedContracts = store.savedContracts.filter(c => c.id !== contractId); - localStorage.setItem('savedContracts', JSON.stringify(newSavedContracts)); - return { ...store, savedContracts: newSavedContracts }; - }), - setCurrentContract: (contract) => update(store => ({ - ...store, - currentContract: contract - })) - }; -} -function loadSavedContracts() { - const saved = localStorage.getItem('savedContracts'); - return saved ? JSON.parse(saved) : []; + /** + * 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(); \ No newline at end of file +export const contractStore = createContractStore() \ No newline at end of file diff --git a/src/lib/utils/contractUtils.js b/src/lib/utils/contractUtils.js index 87bff80..a3811fe 100644 --- a/src/lib/utils/contractUtils.js +++ b/src/lib/utils/contractUtils.js @@ -1,22 +1,36 @@ -import Contract from 'stellar-sdk'; +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} A Contract instance + */ export async function generateContractClient(contractId, server) { try { - // Validate contract ID format - if (!contractId.match(/^C[A-Z2-7]{55}$/)) { + // Validate contract ID + if (!StrKey.isValidContract(contractId)) { throw new Error('Invalid contract ID format'); } - // Get the contract's footprint which includes the WASM hash - const footprintResponse = await server.getFootprint(contractId); - - // Create contract instance - const contract = new Contract(contractId); - - // You might want to add the contract's interface here - // This would involve parsing the WASM to get available methods - - return contract; + 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}`); From 5480e0574ad2ff9ae566c67cd72975e4b4f52210 Mon Sep 17 00:00:00 2001 From: Ugo-X Date: Wed, 23 Oct 2024 15:25:51 +0100 Subject: [PATCH 3/4] updated PR --- src/lib/utils/contractUtils.js | 62 ++++++++-------- src/routes/dashboard/contracts/+page.svelte | 80 ++++++++++----------- 2 files changed, 73 insertions(+), 69 deletions(-) diff --git a/src/lib/utils/contractUtils.js b/src/lib/utils/contractUtils.js index a3811fe..5b0bda0 100644 --- a/src/lib/utils/contractUtils.js +++ b/src/lib/utils/contractUtils.js @@ -1,38 +1,44 @@ -import { StrKey } from 'stellar-sdk'; -import { Contract } from '@stellar/stellar-sdk'; +import { StrKey, Contract } from '@stellar/stellar-sdk' +import { Server } from '@stellar/stellar-sdk/rpc' /** * 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} A Contract instance */ -export async function generateContractClient(contractId, server) { +export async function generateContractClient(contractId) { + const server = new Server('https://soroban-testnet.stellar.org') + + // Validate contract ID + if (!StrKey.isValidContract(contractId)) { + throw new Error('Invalid contract ID format') + } + try { - // Validate contract ID - if (!StrKey.isValidContract(contractId)) { - throw new Error('Invalid contract ID format'); - } + console.log('Fetching WASM for contract ID:', contractId) + + // Fetch the contract's WASM using the contract ID + const contractResponse = await server.getContractWasmByContractId(contractId) - 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; + // Log the WASM bytecode length or the data for debugging + console.log('Contract WASM length:', contractResponse.length) // Adjust if needed based on actual response structure + + // Create a contract instance (you may need to initialize this differently based on your library's requirements) + 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 // Return the contract instance + } catch (serverError) { + console.error('Error fetching contract WASM:', serverError) + + // Handle specific server error responses + if (serverError.response && serverError.response.status === 404) { + throw new Error(`Contract not found: ${contractId}`) } - } catch (error) { - console.error('Error generating contract client:', error); - throw new Error(`Failed to generate contract client: ${error.message}`); + + // Throw a general error for other server issues + throw new Error(`Failed to fetch contract WASM: ${serverError.message}`) } -} \ No newline at end of file +} diff --git a/src/routes/dashboard/contracts/+page.svelte b/src/routes/dashboard/contracts/+page.svelte index 3121440..9ac6b49 100644 --- a/src/routes/dashboard/contracts/+page.svelte +++ b/src/routes/dashboard/contracts/+page.svelte @@ -1,57 +1,55 @@
-

Stellar Smart Contract Interaction

- +

Stellar Smart Contract Interaction

+
- +
- +
-
- + - + {#if error} -
{error}
+
{error}
{/if} - -

Saved Contracts

+ +

Saved Contracts

{#each $contractStore.savedContracts as contract} -
+
{contract.name || 'Unnamed Contract'} - {contract.id} + {contract.id}
{/each} -
\ No newline at end of file +
From ac82cc113d3425872b976268564c85eb14161787 Mon Sep 17 00:00:00 2001 From: Ugo-X Date: Wed, 30 Oct 2024 22:02:23 +0100 Subject: [PATCH 4/4] Updated PR --- src/lib/stores/contractStore.js | 91 ++++++++++++--------- src/lib/utils/contractUtils.js | 66 +++++++++------ src/routes/dashboard/contracts/+page.svelte | 73 ++++++++--------- 3 files changed, 128 insertions(+), 102 deletions(-) diff --git a/src/lib/stores/contractStore.js b/src/lib/stores/contractStore.js index 58c6e3f..4a48953 100644 --- a/src/lib/stores/contractStore.js +++ b/src/lib/stores/contractStore.js @@ -1,85 +1,100 @@ -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' +import { persisted } from 'svelte-local-storage-store'; +import { StrKey } from '@stellar/stellar-sdk'; +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 + * @property {string} contractId - The Stellar contract ID + * @property {string} name - Human-readable name for this contract + * @property {string} [description] - Optional description of the contract + */ + +/** + * @typedef {Object} ContractStore + * @property {SavedContract[]} savedContracts - An array of saved contracts + * @property {SavedContract|null} currentContract - The currently active contract or null */ function createContractStore() { - /** @type {import('svelte/store').Writable<{savedContracts: SavedContract[], currentContract: SavedContract|null}>} */ + /** + * @type {import('svelte/store').Writable} + */ 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 + * @param {SavedContract} contract - Contract details to save * @throws Will throw an error if the contract ID is invalid */ - saveContract: (contract) => + saveContract: (contract) => update(store => { if (!StrKey.isValidContract(contract.contractId)) { - throw error(400, { message: 'Invalid contract ID' }) + throw new Error('Invalid contract ID'); } - - const newContract = { - ...contract, - id: contract.id || uuidv4() - } - - return { + + const newContract = { ...contract }; + const updatedStore = { ...store, savedContracts: [...store.savedContracts, newContract] - } + }; + + // Log a success message to the console + console.log('Contract saved successfully:', newContract); + + return updatedStore; }), /** * Removes a contract from the store - * @param {string} id Unique identifier of the contract to remove + * @param {string} id - Unique identifier of the contract to remove */ - removeContract: (id) => + removeContract: (id) => update(store => ({ ...store, - savedContracts: store.savedContracts.filter(c => c.id !== id), - currentContract: store.currentContract?.id === id ? null : store.currentContract + savedContracts: store.savedContracts.filter(c => c.contractId !== id), + currentContract: store.currentContract?.contractId === id ? null : store.currentContract })), /** - * Sets the current active contract - * @param {SavedContract|null} contract Contract to set as current, or null to clear + * Sets the current active contract using its ID + * @param {string|null} contractId - Contract ID to set as current, or null to clear + * @throws Will throw an error if the contract ID is not found in saved contracts */ - setCurrentContract: (contract) => - update(store => ({ - ...store, - currentContract: contract - })), + setCurrentContract: (contractId) => + update(store => { + if (contractId === null) { + return { ...store, currentContract: null }; + } + + const contract = store.savedContracts.find(c => c.contractId === contractId); + if (!contract) { + throw new Error('Contract not found'); + } + + return { ...store, currentContract: contract }; + }), /** * Looks up a contract by its Stellar contract ID - * @param {string} contractId Stellar contract ID to look up + * @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) + 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() \ No newline at end of file +export const contractStore = createContractStore(); \ No newline at end of file diff --git a/src/lib/utils/contractUtils.js b/src/lib/utils/contractUtils.js index 5b0bda0..4ebb564 100644 --- a/src/lib/utils/contractUtils.js +++ b/src/lib/utils/contractUtils.js @@ -1,5 +1,14 @@ -import { StrKey, Contract } from '@stellar/stellar-sdk' -import { Server } from '@stellar/stellar-sdk/rpc' +import { StrKey, Contract } from '@stellar/stellar-sdk'; +import { Server } from '@stellar/stellar-sdk/rpc'; + +/** + * Determines if a contract ID represents a Stellar Asset Contract (SAC) + * @param {string} contractId - The contract ID to check + * @returns {boolean} True if the contract ID is for a SAC + */ +function isStellarAssetContract(contractId) { + return contractId.startsWith('CA'); +} /** * Generates a contract client for interacting with a Stellar smart contract @@ -7,38 +16,41 @@ import { Server } from '@stellar/stellar-sdk/rpc' * @returns {Promise} A Contract instance */ export async function generateContractClient(contractId) { - const server = new Server('https://soroban-testnet.stellar.org') - + const server = new Server('https://soroban-testnet.stellar.org'); + // Validate contract ID if (!StrKey.isValidContract(contractId)) { - throw new Error('Invalid contract ID format') + throw new Error('Invalid contract ID format'); } try { - console.log('Fetching WASM for contract ID:', contractId) - - // Fetch the contract's WASM using the contract ID - const contractResponse = await server.getContractWasmByContractId(contractId) - - // Log the WASM bytecode length or the data for debugging - console.log('Contract WASM length:', contractResponse.length) // Adjust if needed based on actual response structure - - // Create a contract instance (you may need to initialize this differently based on your library's requirements) - 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 // Return the contract instance + if (isStellarAssetContract(contractId)) { + // For SAC contracts, create contract instance without fetching WASM + const contract = new Contract(contractId); + console.log('Contract:', contract); + return contract; + } + else { + // For WASM contracts, fetch the WASM first + console.log('Fetching WASM for contract ID:', contractId); + const contractResponse = await server.getContractWasmByContractId(contractId); + + console.log('Contract WASM length:', contractResponse.length); + const contract = new Contract(contractId); + console.log(contract); + + // You might want to add the contract's interface here + // This could involve parsing the WASM to get available methods + + return contract; + } } catch (serverError) { - console.error('Error fetching contract WASM:', serverError) - - // Handle specific server error responses + console.error('Error handling contract:', serverError); + if (serverError.response && serverError.response.status === 404) { - throw new Error(`Contract not found: ${contractId}`) + throw new Error(`Contract not found: ${contractId}`); } - // Throw a general error for other server issues - throw new Error(`Failed to fetch contract WASM: ${serverError.message}`) + throw new Error(`Failed to handle contract: ${serverError.message}`); } -} +} \ No newline at end of file diff --git a/src/routes/dashboard/contracts/+page.svelte b/src/routes/dashboard/contracts/+page.svelte index 9ac6b49..6508bb8 100644 --- a/src/routes/dashboard/contracts/+page.svelte +++ b/src/routes/dashboard/contracts/+page.svelte @@ -1,55 +1,54 @@
-

Stellar Smart Contract Interaction

+

Stellar Smart Contract Interaction

- +
-
{#if error} -
{error}
+
{error}
{/if} -

Saved Contracts

- {#each $contractStore.savedContracts as contract} -
+

Saved Contracts

+ {#each $contractStore.savedContracts as savedContract} +
- {contract.name || 'Unnamed Contract'} - {contract.id} + {savedContract.name || 'Unnamed Contract'} + {savedContract.contractId}