diff --git a/articleRedirects.js b/config/articleRedirects.js similarity index 100% rename from articleRedirects.js rename to config/articleRedirects.js diff --git a/contentPlugins.js b/config/contentPlugins.js similarity index 61% rename from contentPlugins.js rename to config/contentPlugins.js index 0c8e12d222c..4576c08f676 100644 --- a/contentPlugins.js +++ b/config/contentPlugins.js @@ -1,4 +1,4 @@ -const { generatePluginConfig } = require('./src/utils/pluginConfigGenerators'); +const { generatePluginConfig } = require('../src/utils/pluginConfigGenerators'); const { buildPluginsConfig, maintainPluginsConfig, @@ -13,24 +13,27 @@ module.exports = async () => { { id: 'build', globalSidebars: ['build'], - path: path.resolve(__dirname, 'docs/build/getting-started'), + path: path.resolve(__dirname, '../docs/build/getting-started'), sidebarPath: path.resolve( __dirname, - 'docs/build/getting-started/sidebars.ts', + '../docs/build/getting-started/sidebars.ts', ), routeBasePath: 'build', }, - ...generatePluginConfig(buildPluginsConfig, __dirname + '/docs/build/'), + ...generatePluginConfig( + buildPluginsConfig, + path.resolve(__dirname, '../docs/build/'), + ), { id: 'introduction-docs-stardust', path: path.resolve( __dirname, - 'docs/build/introduction-docs/stardust/docs', + '../docs/build/introduction-docs/stardust/docs', ), routeBasePath: 'introduction', sidebarPath: path.resolve( __dirname, - 'docs/build/introduction-docs/stardust/sidebars.js', + '../docs/build/introduction-docs/stardust/sidebars.js', ), versions: { current: { @@ -45,15 +48,15 @@ module.exports = async () => { const maintainPlugins = [ ...generatePluginConfig( maintainPluginsConfig, - __dirname + '/docs/maintain/', + path.resolve(__dirname, '../docs/maintain/'), ), { id: 'maintain', globalSidebars: ['maintain'], - path: path.resolve(__dirname, 'docs/maintain/getting-started'), + path: path.resolve(__dirname, '../docs/maintain/getting-started'), sidebarPath: path.resolve( __dirname, - 'docs/maintain/getting-started/sidebars.ts', + '../docs/maintain/getting-started/sidebars.ts', ), routeBasePath: 'maintain', }, @@ -62,8 +65,8 @@ module.exports = async () => { const getStartedPlugins = [ { id: 'get-started', - path: path.resolve(__dirname, 'docs/get-started'), - sidebarPath: path.resolve(__dirname, 'docs/get-started/sidebars.ts'), + path: path.resolve(__dirname, '../docs/get-started/'), + sidebarPath: path.resolve(__dirname, '../docs/get-started/sidebars.ts'), routeBasePath: 'get-started', }, ]; @@ -71,8 +74,8 @@ module.exports = async () => { const learnPlugins = [ { id: 'learn', - path: path.resolve(__dirname, 'docs/learn'), - sidebarPath: path.resolve(__dirname, 'docs/learn/sidebars.ts'), + path: path.resolve(__dirname, '../docs/learn/'), + sidebarPath: path.resolve(__dirname, '../docs/learn/sidebars.ts'), routeBasePath: 'learn', }, ]; @@ -82,8 +85,8 @@ module.exports = async () => { ...getStartedPlugins, { id: 'community', - path: path.resolve(__dirname, 'docs/community'), - sidebarPath: path.resolve(__dirname, 'docs/community/sidebars.ts'), + path: path.resolve(__dirname, '../docs/community/'), + sidebarPath: path.resolve(__dirname, '../docs/community/sidebars.ts'), routeBasePath: 'community', }, ...buildPlugins, diff --git a/common/jargon.js b/config/jargon.js similarity index 100% rename from common/jargon.js rename to config/jargon.js diff --git a/svgo.config.js b/config/svgo.config.js similarity index 100% rename from svgo.config.js rename to config/svgo.config.js diff --git a/switcherConfig.js b/config/switcherConfig.js similarity index 92% rename from switcherConfig.js rename to config/switcherConfig.js index 1cb8de7006d..4c6578a8026 100644 --- a/switcherConfig.js +++ b/config/switcherConfig.js @@ -1,13 +1,13 @@ // @ts-check const { generateSwitcherConfig, -} = require('./src/utils/pluginConfigGenerators'); +} = require('../src/utils/pluginConfigGenerators'); const { buildPluginsConfig, maintainPluginsConfig, } = require('./versionedConfig'); -/** @type {import('./src/common/components/Switcher').Config} */ +/** @type {import('../src/components/Switcher').Config} */ const config = { docs: [ ...generateSwitcherConfig(buildPluginsConfig), diff --git a/tutorials/tags.json b/config/tags.json similarity index 100% rename from tutorials/tags.json rename to config/tags.json diff --git a/config/tutorials.js b/config/tutorials.js new file mode 100644 index 00000000000..8bd51c17773 --- /dev/null +++ b/config/tutorials.js @@ -0,0 +1,252 @@ +const pluginTutorial = require('../src/plugins/tutorial'); + +module.exports = [ + [ + '@docusaurus/plugin-content-pages', + { + id: 'single-page-tutorials', + path: './docs/tutorials', + routeBasePath: '/tutorials', + }, + ], + [ + pluginTutorial, + { + title: 'Run a Wasp Node', + description: 'In this tutorial you will learn how to run a wasp node.', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-A.jpg', + route: '/wasp/how-tos/running-a-node', + tags: ['text', 'video'], + }, + ], + [ + pluginTutorial, + { + title: 'Run a Wasp Chain', + description: 'In this tutorial you will learn how to run a wasp chain.', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-B.jpg', + route: '/wasp/how-tos/setting-up-a-chain', + tags: ['text', 'video'], + }, + ], + [ + pluginTutorial, + { + title: 'Deploy a WASM Smart Contract', + description: + 'In this tutorial you will learn how to deploy a wasm smart contract.', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-C.jpg', + route: '/wasp/how-tos/setting-up-a-chain#deploying-a-wasm-contract', + tags: ['text', 'video'], + }, + ], + [ + pluginTutorial, + { + title: 'Deploy a Solidity Smart Contract Using Remix + Metamask', + description: + 'In this tutorial you will learn how to deploy a solidity smart contract on EVM using remix and metamask.', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-E.jpg', + route: '/isc/getting-started/tools#remix', + tags: ['text', 'video'], + }, + ], + [ + pluginTutorial, + { + title: 'Generate a WASM Smart Contract Using the Schema Tool', + description: + 'In this tutorial you will learn how to use schema tool to generate smart contract template code on rust and golang', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-G.png', + route: '/isc/schema/how-tos/usage', + tags: ['text', 'video'], + }, + ], + [ + pluginTutorial, + { + title: + 'Generate a WASM Smart Contract Using the Schema Tool in Typescript', + description: + 'In this tutorial you will learn how to use schema tool to generate smart contract template code on typescript', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-G.png', + route: 'https://www.youtube.com/watch?v=P5HMgmY3DMM', + tags: ['video'], + }, + ], + [ + pluginTutorial, + { + title: 'Interact with IOTA Node Extension (INX)', + description: + 'In this tutorial you will learn how to interact with the IOTA Node Extension (INX) interface based on gRPC.', + preview: '/img/tutorials/hornet-inx-interaction.png', + route: 'tutorials/hornet-inx-interaction', + tags: ['text', 'getting-started', 'shimmer', 'js'], + }, + ], + [ + pluginTutorial, + { + title: 'Tokenless Data Notarization', + description: + 'Proove that a block was part of the past Tangle, even if this part of the Tangle was already pruned from network nodes.', + preview: '/img/tutorials/proof-inclusion-of-a-block.png', + route: 'tutorials/proof-inclusion-of-a-block', + tags: ['text', 'getting-started', 'js', 'client', 'shimmer'], + }, + ], + [ + pluginTutorial, + { + title: 'Set Up a Testnet Address and Receive Funds From the Faucet', + description: + 'In this tutorial you will learn how to create a seed and address with wallet.rs and receive testnet tokens from the faucet.', + preview: '/img/tutorials/wallet-setup.png', + route: 'tutorials/wallet-setup', + tags: ['text', 'getting-started', 'node_js', 'wallet', 'shimmer'], + }, + ], + [ + pluginTutorial, + { + title: 'How to Set Up iota.js for Development', + description: + 'In this tutorial you will learn how to create a new project, generate a new address and receive x funds from the faucet.', + preview: '/img/tutorials/setup_iota-js_for_development.png', + route: 'tutorials/setup_iota-js_for_development', + tags: ['text', 'getting-started', 'client', 'shimmer', 'js'], + }, + ], + [ + pluginTutorial, + { + title: + 'Connect to Shimmer EVM Testnet and Deploy a Solidity Smart Contract', + description: + 'In this tutorial, we will connect to Shimmer EVM Testnet, connect Metamask to it, get funded and deploy a smart contract in Solidity.', + preview: '/img/tutorials/connect-shimmerevm-testnet-and-deploy.png', + route: 'tutorials/shimmerevm-testnet-setup', + tags: [ + 'text', + 'shimmer', + 'solidity', + 'getting-started', + 'wasp', + 'iscp', + 'video', + ], + }, + ], + [ + pluginTutorial, + { + title: + 'Tutorial - Deploy a Solidity Smart Contract on ShimmerEVM Testnet Using Hardhat', + description: + 'In this tutorial, you will learn how to set up Hardhat and use it to build, test and deploy a simple smart contract on ShimmerEVM.', + preview: '/img/tutorials/shimmerevm-hardhat.jpg', + route: 'tutorials/shimmerevm-testnet-hardhat', + tags: [ + 'text', + 'shimmer', + 'solidity', + 'shimmerevm', + 'hardhat', + 'iscp', + 'video', + ], + }, + ], + [ + pluginTutorial, + { + title: 'Create a Simple Voting dApp on ShimmerEVM', + description: + 'This tutorial will guide you as you write and deploy a voting dApp on ShimmerEVM. You can vote on a few options and view the results; all data will be stored on-chain.', + preview: '/img/tutorials/shimmerevm-dapp-voting.jpg', + route: 'tutorials/shimmerevm-dapp-voting', + tags: ['text', 'shimmer', 'solidity', 'iscp'], + }, + ], + [ + pluginTutorial, + { + title: 'Set Up WASP locally Using Docker', + description: + 'In this tutorial you will learn how to set up WASP and Hornet locally for Development setup.', + preview: '/img/tutorials/wasp-setup-shimmer.png', + route: 'https://youtu.be/ltem9Bh_4hA', + tags: ['text', 'shimmer', 'video', 'wasp', 'iscp'], + }, + ], + [ + pluginTutorial, + { + title: 'Create an NFT with the IOTA SDK and IPFS in NodeJs', + description: + 'In this tutorial you will learn how to create a NFT on the Shimmer network with iota-sdk and IPFS.', + preview: '/img/tutorials/create-nft-with-wallet-lib.png', + route: 'tutorials/create-nft-with-iota-sdk', + tags: [ + 'text', + 'getting-started', + 'node_js', + 'iota-sdk', + 'ipfs', + 'shimmer', + 'sdk', + ], + }, + ], + [ + pluginTutorial, + { + title: 'Send Shimmer Tokens with IOTA SDK in NodeJs', + description: + 'In this tutorial you will learn how to send Shimmer Tokens with IOTA SDK in NodeJs.', + preview: '/img/tutorials/send-shimmer-tokens-with-iota-sdk.png', + route: 'tutorials/send-shimmer-tokens-with-iota-sdk', + tags: ['text', 'iota-sdk', 'sdk', 'getting-started', 'rust', 'shimmer'], + }, + ], + [ + pluginTutorial, + { + title: 'Connect to Shimmer EVM and Deploy a Solidity Smart Contract', + description: + 'In this tutorial, we will connect to Shimmer EVM, connect Metamask to it, get funded and deploy a smart contract in Solidity.', + preview: '/img/tutorials/connect-shimmerevm-and-deploy.png', + route: 'tutorials/shimmerevm-setup', + tags: [ + 'text', + 'shimmer', + 'solidity', + 'getting-started', + 'wasp', + 'iscp', + 'video', + ], + }, + ], + [ + pluginTutorial, + { + title: + 'Tutorial - Deploy a Solidity Smart Contract on ShimmerEVM Using Hardhat', + description: + 'In this tutorial, you will learn how to set up Hardhat and use it to build, test and deploy a simple smart contract on ShimmerEVM.', + preview: '/img/tutorials/shimmerevm-hardhat.jpg', + route: 'tutorials/shimmerevm-hardhat', + tags: [ + 'text', + 'shimmer', + 'solidity', + 'shimmerevm', + 'hardhat', + 'iscp', + 'video', + ], + }, + ], +]; diff --git a/versionedConfig.js b/config/versionedConfig.js similarity index 92% rename from versionedConfig.js rename to config/versionedConfig.js index f66b73a96f0..91e7e747a3c 100644 --- a/versionedConfig.js +++ b/config/versionedConfig.js @@ -27,8 +27,13 @@ exports.buildPluginsConfig = [ subsection: 'build-layer-2', versions: [ { - label: 'v1.0.0-rc.6', - badges: ['Shimmer'], + label: 'v1.1', + badges: ['IOTA', 'Shimmer'], + }, + { + label: 'v1.3-alpha', + badges: ['Testnet'], + banner: 'unreleased', }, ], }, @@ -40,10 +45,6 @@ exports.buildPluginsConfig = [ icon: 'Identity', subsection: 'build-layer-1', versions: [ - { - label: '1.3', - badges: ['IOTA', 'Shimmer'], - }, { label: '1.2', badges: ['IOTA', 'Shimmer'], @@ -149,8 +150,13 @@ exports.maintainPluginsConfig = [ subsection: 'maintain-layer-2', versions: [ { - label: 'v1.0.0-rc.6', - badges: ['Shimmer'], + label: 'v1.1', + badges: ['IOTA', 'Shimmer'], + }, + { + label: 'v1.3-alpha', + badges: ['Testnet'], + banner: 'unreleased', }, ], }, diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_EVM-required-prior-knowledge.md b/docs/build/isc/v1.1/docs/_admonitions/_EVM-required-prior-knowledge.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_EVM-required-prior-knowledge.md rename to docs/build/isc/v1.1/docs/_admonitions/_EVM-required-prior-knowledge.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_EVM_compatibility.md b/docs/build/isc/v1.1/docs/_admonitions/_EVM_compatibility.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_EVM_compatibility.md rename to docs/build/isc/v1.1/docs/_admonitions/_EVM_compatibility.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_about-accounts.md b/docs/build/isc/v1.1/docs/_admonitions/_about-accounts.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_about-accounts.md rename to docs/build/isc/v1.1/docs/_admonitions/_about-accounts.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_deploy_a_smart_contract.md b/docs/build/isc/v1.1/docs/_admonitions/_deploy_a_smart_contract.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_deploy_a_smart_contract.md rename to docs/build/isc/v1.1/docs/_admonitions/_deploy_a_smart_contract.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_network_warning.md b/docs/build/isc/v1.1/docs/_admonitions/_network_warning.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_network_warning.md rename to docs/build/isc/v1.1/docs/_admonitions/_network_warning.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_ownership.md b/docs/build/isc/v1.1/docs/_admonitions/_ownership.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_ownership.md rename to docs/build/isc/v1.1/docs/_admonitions/_ownership.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_payable.md b/docs/build/isc/v1.1/docs/_admonitions/_payable.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_payable.md rename to docs/build/isc/v1.1/docs/_admonitions/_payable.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_remix-IDE.md b/docs/build/isc/v1.1/docs/_admonitions/_remix-IDE.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_remix-IDE.md rename to docs/build/isc/v1.1/docs/_admonitions/_remix-IDE.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_partials/_hardhat_config.md b/docs/build/isc/v1.1/docs/_partials/_hardhat_config.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_partials/_hardhat_config.md rename to docs/build/isc/v1.1/docs/_partials/_hardhat_config.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_partials/_on_off_ledger_request.md b/docs/build/isc/v1.1/docs/_partials/_on_off_ledger_request.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_partials/_on_off_ledger_request.md rename to docs/build/isc/v1.1/docs/_partials/_on_off_ledger_request.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_partials/how-tos/token/_check_storage_deposit.md b/docs/build/isc/v1.1/docs/_partials/how-tos/token/_check_storage_deposit.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_partials/how-tos/token/_check_storage_deposit.md rename to docs/build/isc/v1.1/docs/_partials/how-tos/token/_check_storage_deposit.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_partials/how-tos/token/_example_code_intro.md b/docs/build/isc/v1.1/docs/_partials/how-tos/token/_example_code_intro.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_partials/how-tos/token/_example_code_intro.md rename to docs/build/isc/v1.1/docs/_partials/how-tos/token/_example_code_intro.md diff --git a/docs/build/isc/v1.1/docs/_partials/how-tos/token/_obsolete_token_creation.md b/docs/build/isc/v1.1/docs/_partials/how-tos/token/_obsolete_token_creation.md new file mode 100644 index 00000000000..1a70e93ffaa --- /dev/null +++ b/docs/build/isc/v1.1/docs/_partials/how-tos/token/_obsolete_token_creation.md @@ -0,0 +1,5 @@ +:::caution + +This method is now obsolete, use the new [`createNativeTokenFoundry`](../../../how-tos/core-contracts/token/create-native-token.md) method instead. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/consensus.md b/docs/build/isc/v1.1/docs/explanations/consensus.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/consensus.md rename to docs/build/isc/v1.1/docs/explanations/consensus.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/context.mdx b/docs/build/isc/v1.1/docs/explanations/context.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/context.mdx rename to docs/build/isc/v1.1/docs/explanations/context.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/core-contracts.md b/docs/build/isc/v1.1/docs/explanations/core-contracts.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/core-contracts.md rename to docs/build/isc/v1.1/docs/explanations/core-contracts.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/how-accounts-work.md b/docs/build/isc/v1.1/docs/explanations/how-accounts-work.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/how-accounts-work.md rename to docs/build/isc/v1.1/docs/explanations/how-accounts-work.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/invocation.md b/docs/build/isc/v1.1/docs/explanations/invocation.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/invocation.md rename to docs/build/isc/v1.1/docs/explanations/invocation.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/sandbox.md b/docs/build/isc/v1.1/docs/explanations/sandbox.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/sandbox.md rename to docs/build/isc/v1.1/docs/explanations/sandbox.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/smart-contract-anatomy.md b/docs/build/isc/v1.1/docs/explanations/smart-contract-anatomy.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/smart-contract-anatomy.md rename to docs/build/isc/v1.1/docs/explanations/smart-contract-anatomy.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/smart-contracts.md b/docs/build/isc/v1.1/docs/explanations/smart-contracts.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/smart-contracts.md rename to docs/build/isc/v1.1/docs/explanations/smart-contracts.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/state_manager.md b/docs/build/isc/v1.1/docs/explanations/state_manager.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/state_manager.md rename to docs/build/isc/v1.1/docs/explanations/state_manager.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/states.md b/docs/build/isc/v1.1/docs/explanations/states.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/states.md rename to docs/build/isc/v1.1/docs/explanations/states.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/validators.md b/docs/build/isc/v1.1/docs/explanations/validators.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/validators.md rename to docs/build/isc/v1.1/docs/explanations/validators.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/compatibility.md b/docs/build/isc/v1.1/docs/getting-started/compatibility.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/getting-started/compatibility.md rename to docs/build/isc/v1.1/docs/getting-started/compatibility.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/languages-and-vms.md b/docs/build/isc/v1.1/docs/getting-started/languages-and-vms.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/getting-started/languages-and-vms.md rename to docs/build/isc/v1.1/docs/getting-started/languages-and-vms.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/networks-and-chains.mdx b/docs/build/isc/v1.1/docs/getting-started/networks-and-chains.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/getting-started/networks-and-chains.mdx rename to docs/build/isc/v1.1/docs/getting-started/networks-and-chains.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/quick-start.mdx b/docs/build/isc/v1.1/docs/getting-started/quick-start.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/getting-started/quick-start.mdx rename to docs/build/isc/v1.1/docs/getting-started/quick-start.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/tools.mdx b/docs/build/isc/v1.1/docs/getting-started/tools.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/getting-started/tools.mdx rename to docs/build/isc/v1.1/docs/getting-started/tools.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/ERC20.md b/docs/build/isc/v1.1/docs/how-tos/ERC20.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/ERC20.md rename to docs/build/isc/v1.1/docs/how-tos/ERC20.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/ERC721.md b/docs/build/isc/v1.1/docs/how-tos/ERC721.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/ERC721.md rename to docs/build/isc/v1.1/docs/how-tos/ERC721.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/allow.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/allow.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/allow.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/allow.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/get-allowance.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/get-allowance.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/get-allowance.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/get-allowance.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/take-allowance.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/take-allowance.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/take-allowance.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/take-allowance.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/get-balance.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/get-balance.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/get-balance.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/get-balance.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/call-view.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/call-view.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/call-view.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/call-view.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/get-randomness-on-l2.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/get-randomness-on-l2.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/get-randomness-on-l2.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/get-randomness-on-l2.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/introduction.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/introduction.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/introduction.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/introduction.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/introduction.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/introduction.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/mint-nft.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/mint-nft.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/mint-nft.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/mint-nft.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/use-as-erc721.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/use-as-erc721.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/use-as-erc721.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/use-as-erc721.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/create-foundry.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-foundry.md similarity index 94% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/create-foundry.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-foundry.md index f9636742db8..17ba120d40c 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/create-foundry.md +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-foundry.md @@ -7,8 +7,12 @@ tags: - how-to --- import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; +import ObsoleteTokenCreation from '../../../_partials/how-tos/token/_obsolete_token_creation.md'; # Create a Foundry + + + ## About Foundries The Stardust update allows you to create your own native tokens. Native tokens are minted by a [Foundry](/tips/tips/TIP-0018/#foundry-output). diff --git a/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-native-token.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-native-token.md new file mode 100644 index 00000000000..06baa4615d1 --- /dev/null +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-native-token.md @@ -0,0 +1,91 @@ +--- +description: How to Create a Native Token Foundary. +image: /img/logo/WASP_logo_dark.png +tags: + - foundry + - EVM + - how-to + - native tokens + - mint + - register +--- + +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; + +# Create a Native Token + +This guide will show you how you can efficiently mint new tokens and register them for use as ERC20 tokens with the [`createNativeTokenFoundry`](../../../reference/magic-contract/ISCAccounts.md#createnativetokenfoundry) function in one seamless operation. It will create a foundry on L1 and register it as an ERC20 on L2. This method ensures that only the foundry owner can mint tokens, maintaining security and control over the token creation process. + +## About Foundries + +The Stardust update allows you to create your own native tokens. Native tokens are minted by a [Foundry](/tips/tips/TIP-0018/#foundry-output). +The Foundry lets you specify your native token's maximum supply **once** and change the circulating supply. + +## Example Code + + + +### 2. Define the Token Scheme + +Define the [`NativeTokenScheme`](../../../reference/magic-contract/ISCTypes.md#nativetokenscheme) by specifying the `maximumSupply`. + +```solidity +NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: 0, + meltedTokens: 0, + maximumSupply: _maximumSupply +}); +``` + +### 3. Mint and Register Native Token + +Minting native tokens and registering them as ERC20 tokens using [`createNativeTokenFoundry`](../../../reference/magic-contract/ISCAccounts.md#createnativetokenfoundry) method + +```solidity +uint32 foundrySN = ISC.accounts.createNativeTokenFoundry( + _tokenName, + _tokenSymbol, + _tokenDecimals, + nativeTokenScheme, + allowance +); +``` + +## Full Example Code + +```solidity +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract MyToken { + event MintedToken(uint32 foundrySN); + + constructor( + string memory _tokenName, + string memory _tokenSymbol, + uint8 _tokenDecimals, + uint256 _maximumSupply, + uint64 _storageDeposit + ) payable { + require(msg.value == _storageDeposit * (10**12), "Please send exact funds to pay for storage deposit"); + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + + NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: 0, + meltedTokens: 0, + maximumSupply: _maximumSupply + }); + + uint32 foundrySN = ISC.accounts.createNativeTokenFoundry( + _tokenName, + _tokenSymbol, + _tokenDecimals, + nativeTokenScheme, + allowance + ); + emit MintedToken(foundrySN); + } +} +``` diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/erc20-native-token.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/erc20-native-token.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/erc20-native-token.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/token/erc20-native-token.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/introduction.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/introduction.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/token/introduction.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/mint-token.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/mint-token.md similarity index 87% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/mint-token.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/token/mint-token.md index 9e8e8d9b3c4..bd79533d844 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/mint-token.md +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/mint-token.md @@ -12,8 +12,7 @@ import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_int # Mint Native Tokens -To mint tokens from a [foundry](/tips/tips/TIP-0018/#foundry-output), you first need to be aware that only the foundry owner can mint token, -so you should execute the `ISC.accounts.mintNativeTokens` function in the same contract that [created the foundry](./create-foundry.md). +To mint tokens from a [foundry](/tips/tips/TIP-0018/#foundry-output), you first need to be aware that only the foundry owner can mint token, so you should execute the `ISC.accounts.mintNativeTokens` function in the same contract where you also [created the native token](./create-native-token.md). ## Example Code diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/register-token.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/register-token.md similarity index 92% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/register-token.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/token/register-token.md index 6a910327068..990ae5e69b3 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/register-token.md +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/register-token.md @@ -7,9 +7,12 @@ tags: - how-to --- import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; +import ObsoleteTokenCreation from '../../../_partials/how-tos/token/_obsolete_token_creation.md'; # Register Tokens + + To properly use your native tokens, you should register them as ERC20 using the `registerERC20NativeToken` function from the ISC magic contract. ## Example Code diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/create-a-basic-contract.md b/docs/build/isc/v1.1/docs/how-tos/create-a-basic-contract.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/create-a-basic-contract.md rename to docs/build/isc/v1.1/docs/how-tos/create-a-basic-contract.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/deploy-a-smart-contract.mdx b/docs/build/isc/v1.1/docs/how-tos/deploy-a-smart-contract.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/deploy-a-smart-contract.mdx rename to docs/build/isc/v1.1/docs/how-tos/deploy-a-smart-contract.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/introduction.md b/docs/build/isc/v1.1/docs/how-tos/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/introduction.md rename to docs/build/isc/v1.1/docs/how-tos/introduction.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/send-funds-from-L1-to-L2.mdx b/docs/build/isc/v1.1/docs/how-tos/send-funds-from-L1-to-L2.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/send-funds-from-L1-to-L2.mdx rename to docs/build/isc/v1.1/docs/how-tos/send-funds-from-L1-to-L2.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/test-smart-contracts.md b/docs/build/isc/v1.1/docs/how-tos/test-smart-contracts.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/test-smart-contracts.md rename to docs/build/isc/v1.1/docs/how-tos/test-smart-contracts.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/introduction.md b/docs/build/isc/v1.1/docs/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/introduction.md rename to docs/build/isc/v1.1/docs/introduction.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/.gitignore b/docs/build/isc/v1.1/docs/reference/.gitignore similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/.gitignore rename to docs/build/isc/v1.1/docs/reference/.gitignore diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/accounts.md b/docs/build/isc/v1.1/docs/reference/core-contracts/accounts.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/accounts.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/accounts.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/blob.md b/docs/build/isc/v1.1/docs/reference/core-contracts/blob.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/blob.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/blob.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/blocklog.md b/docs/build/isc/v1.1/docs/reference/core-contracts/blocklog.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/blocklog.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/blocklog.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/errors.md b/docs/build/isc/v1.1/docs/reference/core-contracts/errors.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/errors.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/errors.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/evm.md b/docs/build/isc/v1.1/docs/reference/core-contracts/evm.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/evm.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/evm.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/governance.md b/docs/build/isc/v1.1/docs/reference/core-contracts/governance.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/governance.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/governance.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/overview.md b/docs/build/isc/v1.1/docs/reference/core-contracts/overview.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/overview.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/overview.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/root.md b/docs/build/isc/v1.1/docs/reference/core-contracts/root.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/root.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/root.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/xfer.md b/docs/build/isc/v1.1/docs/reference/core-contracts/xfer.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/xfer.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/xfer.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/json-rpc-spec.md b/docs/build/isc/v1.1/docs/reference/json-rpc-spec.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/json-rpc-spec.md rename to docs/build/isc/v1.1/docs/reference/json-rpc-spec.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/magic-contract/introduction.md b/docs/build/isc/v1.1/docs/reference/magic-contract/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/magic-contract/introduction.md rename to docs/build/isc/v1.1/docs/reference/magic-contract/introduction.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/wasm-lib-data-types.mdx b/docs/build/isc/v1.1/docs/reference/wasm-lib-data-types.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/wasm-lib-data-types.mdx rename to docs/build/isc/v1.1/docs/reference/wasm-lib-data-types.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/access.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/access.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/access.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/access.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/call.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/call.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/call.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/call.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/events.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/events.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/events.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/events.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/funcdesc.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/funcdesc.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/funcdesc.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/funcdesc.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/funcs.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/funcs.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/funcs.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/funcs.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/init.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/init.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/init.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/init.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/params.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/params.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/params.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/params.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/post.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/post.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/post.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/post.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/results.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/results.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/results.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/results.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/spec.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/spec.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/spec.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/spec.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/state.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/state.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/state.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/state.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/structs.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/structs.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/structs.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/structs.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/thunks.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/thunks.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/thunks.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/thunks.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/transfers.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/transfers.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/transfers.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/transfers.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/typedefs.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/typedefs.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/typedefs.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/typedefs.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/usage.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/usage.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/usage.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/usage.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/views.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/views.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/views.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/views.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/yaml.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/yaml.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/yaml.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/yaml.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/introduction.mdx b/docs/build/isc/v1.1/docs/schema/introduction.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/introduction.mdx rename to docs/build/isc/v1.1/docs/schema/introduction.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/proxies.mdx b/docs/build/isc/v1.1/docs/schema/proxies.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/proxies.mdx rename to docs/build/isc/v1.1/docs/schema/proxies.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/getting-started.md b/docs/build/isc/v1.1/docs/solo/getting-started.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/getting-started.md rename to docs/build/isc/v1.1/docs/solo/getting-started.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/deploying-sc.md b/docs/build/isc/v1.1/docs/solo/how-tos/deploying-sc.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/deploying-sc.md rename to docs/build/isc/v1.1/docs/solo/how-tos/deploying-sc.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/error-handling.md b/docs/build/isc/v1.1/docs/solo/how-tos/error-handling.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/error-handling.md rename to docs/build/isc/v1.1/docs/solo/how-tos/error-handling.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/examples.mdx b/docs/build/isc/v1.1/docs/solo/how-tos/examples.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/examples.mdx rename to docs/build/isc/v1.1/docs/solo/how-tos/examples.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/first-example.md b/docs/build/isc/v1.1/docs/solo/how-tos/first-example.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/first-example.md rename to docs/build/isc/v1.1/docs/solo/how-tos/first-example.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/invoking-sc.md b/docs/build/isc/v1.1/docs/solo/how-tos/invoking-sc.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/invoking-sc.md rename to docs/build/isc/v1.1/docs/solo/how-tos/invoking-sc.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/test.mdx b/docs/build/isc/v1.1/docs/solo/how-tos/test.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/test.mdx rename to docs/build/isc/v1.1/docs/solo/how-tos/test.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/the-l1-ledger.md b/docs/build/isc/v1.1/docs/solo/how-tos/the-l1-ledger.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/the-l1-ledger.md rename to docs/build/isc/v1.1/docs/solo/how-tos/the-l1-ledger.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/the-l2-ledger.md b/docs/build/isc/v1.1/docs/solo/how-tos/the-l2-ledger.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/the-l2-ledger.md rename to docs/build/isc/v1.1/docs/solo/how-tos/the-l2-ledger.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/timelock.mdx b/docs/build/isc/v1.1/docs/solo/how-tos/timelock.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/timelock.mdx rename to docs/build/isc/v1.1/docs/solo/how-tos/timelock.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/view-sc.md b/docs/build/isc/v1.1/docs/solo/how-tos/view-sc.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/view-sc.md rename to docs/build/isc/v1.1/docs/solo/how-tos/view-sc.md diff --git a/docs/build/isc/v1.0.0-rc.6/sidebars.js b/docs/build/isc/v1.1/sidebars.js similarity index 98% rename from docs/build/isc/v1.0.0-rc.6/sidebars.js rename to docs/build/isc/v1.1/sidebars.js index 79e46174358..a01017561cc 100644 --- a/docs/build/isc/v1.0.0-rc.6/sidebars.js +++ b/docs/build/isc/v1.1/sidebars.js @@ -151,23 +151,28 @@ module.exports = { }, { type: 'doc', - label: 'Create a Foundry', - id: 'how-tos/core-contracts/token/create-foundry', + label: 'Create a Native Token', + id: 'how-tos/core-contracts/token/create-native-token', }, { type: 'doc', - label: 'Mint a Native Token', + label: 'Mint Native Tokens', id: 'how-tos/core-contracts/token/mint-token', }, { type: 'doc', - label: 'Register Token as ERC20', - id: 'how-tos/core-contracts/token/register-token', + label: 'Custom ERC20 Functions', + id: 'how-tos/core-contracts/token/erc20-native-token', }, { type: 'doc', - label: 'Custom ERC20 Functions', - id: 'how-tos/core-contracts/token/erc20-native-token', + label: 'Create a Foundry', + id: 'how-tos/core-contracts/token/create-foundry', + }, + { + type: 'doc', + label: 'Register Token as ERC20', + id: 'how-tos/core-contracts/token/register-token', }, ], }, diff --git a/docs/build/isc/v1.3-alpha/docs/_admonitions/_EVM-required-prior-knowledge.md b/docs/build/isc/v1.3-alpha/docs/_admonitions/_EVM-required-prior-knowledge.md new file mode 100644 index 00000000000..c1e17089a98 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_admonitions/_EVM-required-prior-knowledge.md @@ -0,0 +1,14 @@ +:::note Required Prior Knowledge + +This guide assumes you are familiar with the concept +of [tokens](https://en.wikipedia.org/wiki/Cryptocurrency#Crypto_token) +in [blockchain](https://en.wikipedia.org/wiki/Blockchain), +[Ethereum Request for Comments (ERCs)](https://eips.ethereum.org/erc)(also known as Ethereum Improvement Proposals ( +EIP)) +, [NFTs](/learn/protocols/stardust/core-concepts/multi-asset-ledger#non-fungible-tokens-nfts), [Smart Contracts](/learn/smart-contracts/introduction) +and have already tinkered with [Solidity](https://docs.soliditylang.org/en/v0.8.16/). + +You should also have basic knowledge on how to [create](../how-tos/create-a-basic-contract.md) and [deploy](../how-tos/deploy-a-smart-contract.mdx) +a smart contract. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/_admonitions/_EVM_compatibility.md b/docs/build/isc/v1.3-alpha/docs/_admonitions/_EVM_compatibility.md new file mode 100644 index 00000000000..1f20154e1ea --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_admonitions/_EVM_compatibility.md @@ -0,0 +1,7 @@ +:::info EVM Compatibility + +The ISC EVM layer is also designed to be as compatible as possible with existing Ethereum +[tools](../getting-started/tools.mdx) and functionalities. However, please make sure you have checked out the current +[properties and limitations](../getting-started/compatibility.md). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/_admonitions/_about-accounts.md b/docs/build/isc/v1.3-alpha/docs/_admonitions/_about-accounts.md new file mode 100644 index 00000000000..4095981384d --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_admonitions/_about-accounts.md @@ -0,0 +1,5 @@ +:::info Accounts in ISC + +Learn more about the [different types of accounts](../explanations/how-accounts-work.md). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/_admonitions/_deploy_a_smart_contract.md b/docs/build/isc/v1.3-alpha/docs/_admonitions/_deploy_a_smart_contract.md new file mode 100644 index 00000000000..de4579b6d81 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_admonitions/_deploy_a_smart_contract.md @@ -0,0 +1,5 @@ +:::tip Deploy a Smart Contract + +Deploy a Solidity Smart Contract following our [how to Deploy a Smart Contract guide](/isc/how-tos/deploy-a-smart-contract#remix). + +::: diff --git a/docs/build/isc/v1.3-alpha/docs/_admonitions/_network_warning.md b/docs/build/isc/v1.3-alpha/docs/_admonitions/_network_warning.md new file mode 100644 index 00000000000..e7a18ce4286 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_admonitions/_network_warning.md @@ -0,0 +1,6 @@ +:::caution Only Available on Shimmer + +At the moment, Smart Contracts are only available on [Shimmer](/build/networks-endpoints/#shimmer) and +its [Public Testnet](/build/networks-endpoints/#public-testnet) network. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/_admonitions/_ownership.md b/docs/build/isc/v1.3-alpha/docs/_admonitions/_ownership.md new file mode 100644 index 00000000000..fa86ee2f72f --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_admonitions/_ownership.md @@ -0,0 +1,7 @@ +:::info Ownership + +You might want to look into making the function ownable with, for example, +[OpenZeppelin](https://docs.openzeppelin.com/contracts/5.x/access-control#ownership-and-ownable) +so only owners of the contract can call certain functionalities of your contract. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/_admonitions/_payable.md b/docs/build/isc/v1.3-alpha/docs/_admonitions/_payable.md new file mode 100644 index 00000000000..2975d1d26d4 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_admonitions/_payable.md @@ -0,0 +1,10 @@ +:::info Payable + +Instead of making the function payable, you could let the contract pay for the storage deposit. +If so, you will need to change the `require` statement to check if the contract's balance has enough funds: + +```solidity +require(address(this).balance > _storageDeposit); +``` + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/_admonitions/_remix-IDE.md b/docs/build/isc/v1.3-alpha/docs/_admonitions/_remix-IDE.md new file mode 100644 index 00000000000..5cfa57d5e69 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_admonitions/_remix-IDE.md @@ -0,0 +1,6 @@ +:::tip Remix + +This guide will use the [Remix IDE](https://remix.ethereum.org/), but you can use this contract with any IDE you are +familiar with. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/_partials/_hardhat_config.md b/docs/build/isc/v1.3-alpha/docs/_partials/_hardhat_config.md new file mode 100644 index 00000000000..d6257484a0b --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_partials/_hardhat_config.md @@ -0,0 +1,52 @@ +import CodeBlock from '@theme/CodeBlock'; +import { Networks } from '@theme/constant'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +{` +networks: { + 'shimmerevm-testnet': { + url: '${Networks['shimmer_testnet'].evm.rpcUrls[0]}', + chainId: ${parseInt(Networks['shimmer_testnet'].evm.chainId)}, + accounts: [YOUR PRIVATE KEY], + }, +} +`} + + + + + + +{` +networks: { + 'iotaevm-testnet': { + url: '${Networks['iota_testnet'].evm.rpcUrls[0]}', + chainId: ${parseInt(Networks['iota_testnet'].evm.chainId)}, + accounts: [YOUR PRIVATE KEY], + }, +} +`} + + + + + + +{` +networks: { + 'shimmerevm': { + url: '${Networks['shimmer'].evm.rpcUrls[0]}', + chainId: ${parseInt(Networks['shimmer'].evm.chainId)}, + accounts: [YOUR PRIVATE KEY], + }, +} +`} + + + + \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/_partials/_on_off_ledger_request.md b/docs/build/isc/v1.3-alpha/docs/_partials/_on_off_ledger_request.md new file mode 100644 index 00000000000..45d59c458c3 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_partials/_on_off_ledger_request.md @@ -0,0 +1,13 @@ +### On-Ledger Requests + +An on-ledger request is a Layer 1 transaction that validator nodes retrieve from the Tangle. The Tangle acts as an +arbiter between users and chains and guarantees that the transaction is valid, making it the only way to transfer assets +to a chain or between chains. + +### Off-Ledger Requests + +If all necessary assets are in the chain already, it is possible to send a request directly to that chain's validator +nodes. +This way, you don’t have to wait for the Tangle to process the message, significantly reducing the overall confirmation +time. +Due to the shorter delay, off-ledger requests are preferred over on-ledger requests unless you need to deposit assets to the chain. \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/_partials/how-tos/token/_check_storage_deposit.md b/docs/build/isc/v1.3-alpha/docs/_partials/how-tos/token/_check_storage_deposit.md new file mode 100644 index 00000000000..f3b043b7ba5 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_partials/how-tos/token/_check_storage_deposit.md @@ -0,0 +1,10 @@ +### 1. Check the Storage Deposit + +Check if the amount paid to the contract is the same as the required [storage deposit](/learn/protocols/stardust/core-concepts/storage-deposit) + and set the allowance. + +```solidity +require(msg.value == _storageDeposit*(10**12), "Please send exact funds to pay for storage deposit"); +ISCAssets memory allowance; +allowance.baseTokens = _storageDeposit; +``` \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/_partials/how-tos/token/_example_code_intro.md b/docs/build/isc/v1.3-alpha/docs/_partials/how-tos/token/_example_code_intro.md new file mode 100644 index 00000000000..daf06c0839b --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_partials/how-tos/token/_example_code_intro.md @@ -0,0 +1,9 @@ +import Ownership from '../../../_admonitions/_ownership.md'; +import Payable from '../../../_admonitions/_payable.md'; +import CheckStorageDeposit from './_check_storage_deposit.md' + + + + + + diff --git a/docs/build/isc/v1.3-alpha/docs/_partials/how-tos/token/_obsolete_token_creation.md b/docs/build/isc/v1.3-alpha/docs/_partials/how-tos/token/_obsolete_token_creation.md new file mode 100644 index 00000000000..1a70e93ffaa --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/_partials/how-tos/token/_obsolete_token_creation.md @@ -0,0 +1,5 @@ +:::caution + +This method is now obsolete, use the new [`createNativeTokenFoundry`](../../../how-tos/core-contracts/token/create-native-token.md) method instead. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/consensus.md b/docs/build/isc/v1.3-alpha/docs/explanations/consensus.md new file mode 100644 index 00000000000..539e7c15adb --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/consensus.md @@ -0,0 +1,53 @@ +--- +description: IOTA Smart Contracts consensus is how Layer 2 validators agree to change the chain state in the same way. +image: /img/logo/WASP_logo_dark.png +tags: + - smart contracts + - consensus + - validator committee + - validators + - validator nodes + - explanation +--- + +# Consensus + +To update the chain, its committee must reach a _consensus_, meaning that more than two thirds of its validators have to +agree to change the state in the exact same way. +This prevents a single malicious node from wreaking havoc over the chain, but there are also more mundane reasons for +individual nodes to act up. + +Smart contracts are deterministic. All honest nodes will produce the same output — but only if they have received the +same input. Each validator node has its point of access to the Tangle, so it may look different to different nodes, as +new transactions take time to propagate through the network. Validator nodes will receive smart contract requests with +random delays in a random order, and, finally, all computers run on their own always slightly skewed clocks. + +## Batch Proposals + +As the first step, each node provides its vision, a _batch proposal_. The proposal contains a local timestamp, a list of +unprocessed requests, and the node's partial signature of the commitment to the current state. + +Then the nodes must agree on which batch proposals they want to work on. In short, nodes A, B, and C have to confirm +that they plan to work on proposals from A, B, and C, and from no one else. As long as there are more than two thirds of +honest nodes, they will be able to find an _asynchronous common subset_ of the batch proposals. From that point, nodes +have the same input and will produce the same result independently. + +## The Batch + +The next step is to convert the raw list of batch proposals into an actual batch. All requests from all proposals are +counted and filtered to produce the same list of requests in the same order. +The partial signatures of all nodes are combined into a full signature that is then fed to a pseudo-random function that +sorts the smart contract requests. +Validator nodes can neither affect nor predict the final order of requests in the batch. (This protects ISC +from [MEV attacks](https://ethereum.org/en/developers/docs/mev/)). + +## State Anchor + +After agreeing on the input, each node executes every smart contract request in order, independently producing the same +new block. Each node then crafts a state anchor, a Layer 1 transaction that proves the commitment to this new chain +state. The timestamp for this transaction is derived from the timestamps of all batch proposals. + +All nodes then sign the state anchor with their partial keys and exchange these signatures. This way, every node obtains +the same valid combined signature and the same valid anchor transaction, which means that any node can publish this +transaction to Layer 1. In theory, nodes could publish these state anchors every time they update the state; in +practice, they do it only every approximately ten seconds to reduce the load on the Tangle. diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/context.mdx b/docs/build/isc/v1.3-alpha/docs/explanations/context.mdx new file mode 100644 index 00000000000..ac2507210f4 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/context.mdx @@ -0,0 +1,50 @@ +--- +description: The call context is a predefined parameter to each smart contract function, which allows you to access the functionality that the call environment provides. +tags: + - WasmLib + - smart contract setup + - Func and View functions + - ScFuncContext + - ScViewContext + - Schema Tool +image: /img/logo/WASP_logo_dark.png +--- + +# Call Context + +Understanding the call context is vital in leveraging the Wasm code within a sandboxed host environment effectively. The following section explains the distinction between different function calls and the role of WasmLib in setting up a smart contract. + +## Function Calls: Func and View + +Smart contract function calls come in two types, each having specific access levels to the smart contract state: + +### Funcs + +Func functions grants full mutable access, resulting in a state update. They accommodate both on-ledger and off-ledger requests, finalized once the state update is registered in the Tangle ledger. + +### Views + +View functions allow limited immutable access, **no state update occurs**. Views are ideal for quickly querying the contract's current state, they only facilitate off-ledger calls. + +## Using Func and View + +WasmLib offers distinct contexts for these function types, namely `ScFuncContext` for Func and `ScViewContext` for View, controlling the accessible functionality and enforcing usage constraints through compile-time type-checking. + +## Smart Contract Setup with WasmLib + +Setting up a smart contract requires the following: + +### Defining Funcs and Views + +Outline available Funcs and Views and communicate them to the host through WasmLib. +It ensures the correct dispatch of function calls and maintains necessary restrictions. + +### Parameter and Return Value Determination + +Establish the parameters and return values for each function. ISC uses simple dictionaries to store details, necessitating consistent (de)serialization handled adeptly by WasmLib. + +### Utilizing Schema Tool + +Although you can use the WasmLib directly, the Schema Tool is recommended for automatically generating and updating the smart contract framework in a type-safe manner, using the preferred language. + +Grasping these concepts will facilitate a secure and efficient smart contract setup, steering clear of potential pitfalls while making the most of what WasmLib offers. diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/core-contracts.md b/docs/build/isc/v1.3-alpha/docs/explanations/core-contracts.md new file mode 100644 index 00000000000..acfdbf5e22c --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/core-contracts.md @@ -0,0 +1,37 @@ +--- +description: There currently are 6 core smart contracts that are always deployed on each chain, root, _default, accounts, blob, blocklog, and governance. +image: /img/banner/banner_wasp_core_contracts_overview.png +tags: + - smart contracts + - core + - initialization + - request handling + - on-chain ledger + - accounts + - data + - receipts + - reference +--- + +# Core Contracts + +![Wasp Node Core Contracts Overview](/img/banner/banner_wasp_core_contracts_overview.png) + +There are currently 7 core smart contracts that are always deployed on each +chain. These are responsible for the vital functions of the chain and +provide infrastructure for all other smart contracts: + +- [`root`](../reference/core-contracts/root.md): Responsible for the initialization of the chain, maintains registry of deployed contracts. + +- [`accounts`](../reference/core-contracts/accounts.md): Manages the on-chain ledger of accounts. + +- [`blob`](../reference/core-contracts/blob.md): Responsible for the registry of binary objects of arbitrary size. + +- [`blocklog`](../reference/core-contracts/blocklog.md): Keeps track of the blocks and receipts of requests that were processed by the chain. + +- [`governance`](../reference/core-contracts/governance.md): Handles the administrative functions of the chain. For example: rotation of the committee of validators of the chain, fees and other chain-specific configurations. + +- [`errors`](../reference/core-contracts/errors.md): Keeps a map of error codes to error messages templates. These error codes are used in request receipts. + +- [`evm`](../reference/core-contracts/evm.md): Provides the necessary infrastructure to accept Ethereum + transactions and execute EVM code. diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/how-accounts-work.md b/docs/build/isc/v1.3-alpha/docs/explanations/how-accounts-work.md new file mode 100644 index 00000000000..8847cb2c883 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/how-accounts-work.md @@ -0,0 +1,102 @@ +--- +description: 'IOTA Smart Contracts chains keep a ledger of on-chain account balances. On-chain accounts are identified +by an AgentID.' +image: /img/tutorial/accounts.png +tags: + +- smart contracts +- on-chain account +- ownership +- accounts Contract +- explanation + +--- +# How Accounts Work + +On the L1 Ledger, like with any _DLT_, we have **trustless** and **atomic** transfers of assets between addresses on the +ledger. + +Tokens controlled by an address can be moved to another address by providing a valid signature using the private key +that controls the source address. + +## L1 Addresses + +In IOTA Smart Contracts, [each chain has a L1 address](../explanations/states.md#digital-assets-on-the-chain) (also known as the _Chain +ID_) which enables it to control L1 assets (base tokens, native tokens and NFTs). +The chain acts as a custodian of the L1 assets on behalf of different entities, thus providing a _L2 Ledger_. + +## L2 Accounts + +The L2 ledger is a collection of _on-chain accounts_ (sometimes called just _accounts_). +L2 accounts can be owned by different entities, identified by a unique _Agent ID_. +The L2 ledger is a mapping of Agent ID => balances of L2 assets. + +## Types of Accounts + +### L1 Address + +Any L1 address can be the owner of a L2 account. +The Agent ID of an L1 address is just the address, + +e.g. `iota1pr7vescn4nqc9lpvv37unzryqc43vw5wuf2zx8tlq2wud0369hjjugg54mf`. + +Tokens in an address account can only be moved through a request signed by the private key of the L1 address. + +### Smart Contract + +Any _smart contract_ can be the owner of a L2 account. Recall that a smart +contract is uniquely identified in a chain by a [_hname_](smart-contract-anatomy.md#identifying-a-smart-contract). +However, the hname is not enough to identify the account since a smart contract on another chain could own it. + +Thus, the Agent ID of a smart contract is composed as the contract hname plus the [_chain +ID_](states.md#digital-assets-on-the-chain), with syntax `@`. For +example: `cebf5908@tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd`. + +Note that this allows trustless transfers of assets between smart contracts on the same or different chains. + +Tokens in a smart contract account can only be moved by that smart contract. + +### The Common Account + +The chain owns a unique L2 account, called the _common account_. +The common account is controlled by the chain owner (defined in the chain root contract) and is used to store funds +collected by fees or sent to the chain L1 address. + +The Agent ID of the common account is `@
`. + +### Ethereum Address + +An L2 account can also be owned by an Ethereum address. See [EVM](../introduction.md) for more information. +The Agent ID of an Ethereum address is just the address prefixed with `0x`, +e.g. `0xd36722adec3edcb29c8e7b5a47f352d701393462`. + +Tokens in an Ethereum account can only be moved by sending an Ethereum transaction signed by the same address. + +## The Accounts Contract + +The [`accounts` core contract](../reference/core-contracts/accounts.md) is responsible for managing the L2 ledger. +By calling this contract, it is possible to: + +- [View current account balances](../how-tos/core-contracts/basics/get-balance.md) +- [Deposit funds to the chain](../how-tos/send-funds-from-L1-to-L2.mdx) +- [Withdraw funds from the chain](../how-tos/core-contracts/basics/send-assets-to-l1.mdx) + +## Example + +The following diagram illustrates an example situation. +The IDs and hnames are shortened for simplicity. + +[![Example situation. Two chains are deployed, with three smart contracts and one address.](/img/tutorial/accounts.png)](/img/tutorial/accounts.png) + +Two chains are deployed, with IDs `chainA` and `chainB`. +`chainA` has two smart contracts on it (with hnames `3037` and `2225`), and `chainB` has one smart contract (`7003`). + +There is also an address on the L1 Ledger: `iota1a2b3c4d`. +This address controls 1337 base tokens and 42 `Red` native tokens on the L1 Ledger. + +The same address also controls 42 base tokens on `chainA` and 8 `Green` native tokens on `chainB`. + +So, the owner of the private key behind the address controls three different accounts: the L1 account and one L2 account +on each chain. + +Smart contract `7003@chainB` has five base tokens on its native chain and controls eleven base tokens on chain A. diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/invocation.md b/docs/build/isc/v1.3-alpha/docs/explanations/invocation.md new file mode 100644 index 00000000000..28756fd0713 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/invocation.md @@ -0,0 +1,108 @@ +--- +description: 'Smart contracts can be invoked through their entry points, from outside via a request, or from inside via a +call.' +image: /img/logo/WASP_logo_dark.png +tags: + +- smart contracts +- requests +- on-ledger +- off-ledger +- calls +- invocation +- explanation + +--- + +import OnOffLedgerRequest from '../_partials/_on_off_ledger_request.md'; + +# Calling a Smart Contract + +## Entry Points + +Like any other computer program, a smart contract will lie dormant until someone or something instructs it to activate. +In the case of smart contracts, the most common way to activate them is to call one of +their [entry points](./smart-contract-anatomy.md#entry-points). It is the same as calling a program's function. It will +take a set of instructions of the smart contract and execute it over the current chain's state. _View entry points_ can +only read the state, while _full entry points_ can read and write to it. + +To invoke a smart contract from outside the chain, the _sender_ (some entity that needs to be identified by a +private/public key pair) has to wrap the call to the entry point into a _request_. +The request has to be cryptographically signed and submitted to the [consensus](./consensus.md) procedure to let the +chain's committee evaluate it and engrave the outcome of its execution into a new state update. + +Upon receiving a request, the committee will execute the wrapped call fully or reject the request with all its potential +changes, never modifying the state halfway. This means that every single request is an atomic operation. + +### Synchronous Composability + +After being invoked by a request, the smart contract code is allowed to invoke entry points of other smart contracts on +the same chain. This means it can _call_ other smart contracts. + +Smart contract calls are deterministic and synchronous, meaning they always produce the same result and execute all +instructions immediately after another. +If a smart contract calls another smart contract, the resulting set of instructions is also deterministic and +synchronous. This means that for a request, it makes no difference if a smart contract's entry point contains the whole +set of instructions or if it is composed by multiple calls to different smart contracts of the chain. + +Being able to combine smart contracts in this way is called _synchronous composability_. + +--- + +## Requests + +A request contains a call to a smart contract and a signature of the sender. The sender also owns the assets and funds +processed within the request. +Unlike calls between smart contracts, requests are not executed immediately. +Instead, they must wait until the chain's _validator_ nodes include them in a request batch. +This means that requests have a delay and are executed in an unpredictable order. + +### Asynchronous Composability + +Requests are not sent by humans exclusively. Smart contracts can also create requests. +For example, a user can send a request to a smart contract that, in turn, sends a request to a decentralized third-party +exchange which would will the user's funds from one currency to another and send them back through another request. + +This is called _asynchronous composability_. + + + +--- + +## Gas + +Gas expresses the "cost" of running a request in a chain. Each operation (arithmetics, write to disk, dispatch events, +etc.) has an associated gas cost. The amount of gas required for a transaction depends on the complexity of the +operation. For example, simple transfers may require less gas, while interacting with smart contracts for actions such +as token swaps can require more due to the higher computational work involved. + +For users to specify how much they're willing to pay for a request, they need to specify a `GasBudget` in the request. +This gas budget is the "maximum operations that this request can execute" and will be charged as a fee based on the +chain's current [fee policy](../reference/core-contracts/governance.md#fee-policy). + +The funds to cover the gas used will be charged directly from the user's on-chain account. + +--- + +## Allowance + +An allowance is a feature within smart contracts that controls how much one address can spend on behalf +of another address. Before a third party can withdraw tokens from your account, you must explicitly set an allowance for +that third party's address, specifying the maximum amount of tokens they are allowed to transfer. This mechanism is used +in various decentralized finance (DeFi) applications, where you might allow a smart contract to interact with your +tokens to participate in staking, lending, or trading activities. The original token owner can adjust or revoke the +allowance at any time, providing control over how your tokens are used by others. + +Any funds sent to the chain are credited to the sender's account. If you want a contract to use +those funds, you must specify an `Allowance` in the request. Contracts can then claim any of the allowed funds using +the sandbox `TransferAllowedFunds` function. + +The Allowance property looks like the following: + +```go +{ + BaseTokens: uint64 + NativeTokens: [{TokenID, uint256}, ...] + NFTs: [NFTID, ...] +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/sandbox.md b/docs/build/isc/v1.3-alpha/docs/explanations/sandbox.md new file mode 100644 index 00000000000..d5ff9a7add4 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/sandbox.md @@ -0,0 +1,45 @@ +--- +description: 'Smart Contracts can only interact with the world by using the Sandbox interface which provides limited and +deterministic access to the state through a key/value storage abstraction.' +image: /img/sandbox.png +tags: + +- smart contracts +- sandbox +- interface +- storage abstraction +- explanation + +--- + +# Sandbox Interface + +A smart contract's access to the world has to be restricted. Imagine a smart contract that would directly tap into a +weather forecast website: as the weather changes, the result of the contract's execution will also change. This smart +contract is not deterministic, meaning that you cannot reproduce the result yourself to verify it because the result for +each execution could be different. + +The access to the chain's state has to be curated, too. The chain owner and developers of individual smart contracts are +not necessarily the same entity. A single malicious contract could ruin the whole chain if not limited to its own space. +Instead of working on the state as a whole, each smart contract can only modify a part of it. + +The only way for smart contracts to access data is to use the sandbox interface, which is deterministic. It provides +their internal state as a list of key/value pairs. + +![Sandbox](/img/sandbox.png) + +Besides reading and writing to the contract state, the Sandbox interface allows smart contracts to access: + +- The [ID](how-accounts-work.md) of the contract. +- The details of the current request or view call. +- The current request allowance and a way to claim the allowance. +- The balances owned by the contract. +- The ID of whoever had deployed the contract. +- The timestamp of the current block. +- Cryptographic utilities like hashing, signature verification, and so on. +- The [events](../schema/how-tos/events.mdx) dispatch. +- Entropy that emulates randomness in an unpredictable yet deterministic way. +- Logging. Used for debugging in a test environment. + +The Sandbox API available in "view calls" is slightly more limited than the one available in normal "execution calls". +For example, besides the state access being read-only for a view, they cannot issue requests, emit events, etc. diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/smart-contract-anatomy.md b/docs/build/isc/v1.3-alpha/docs/explanations/smart-contract-anatomy.md new file mode 100644 index 00000000000..aa5539626a9 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/smart-contract-anatomy.md @@ -0,0 +1,77 @@ +--- +description: Each smart contract instance has a program with a collection of entry points and a state. +image: /img/tutorial/SC-structure.png +tags: + - smart contracts + - structure + - state + - entry points + - Wasm + - explanation +--- + +# Anatomy of a Smart Contract + +Smart contracts are programs that are immutably stored in the chain. + +Through _VM abstraction_, the ISC virtual machine is agnostic about the interpreter used to execute each smart contract. +It can support different _VM types_ (i.e., interpreters) simultaneously on the same chain. +For example, it is possible to have [Wasm](../getting-started/languages-and-vms.md#wasm-vm-for-isc) and [EVM/Solidity](../getting-started/languages-and-vms.md#evmsolidity-based-smart-contracts) smart +contracts coexisting on the same chain. + +![Smart Contract Structure](/img/tutorial/SC-structure.png) + +## Identifying a Smart Contract + +The ISC [core contracts](core-contracts.md) and WASM contracts on the chain are identified by a _hname_ (pronounced +"aitch-name"), which is a `uint32` value calculated as a hash of the smart contract's instance name (a string). +For example, the hname of the [`root`](../reference/core-contracts/root.md) core contract +is `0xcebf5908`. This value uniquely identifies this contract in every chain. This does not apply to EVM contracts. + +## State + +The smart contract state is the data owned by the smart contract and stored on the chain. +The state is a collection of key/value pairs. +Each key and value are byte arrays of arbitrary size (there are practical limits set by the underlying database, of +course). +You can think of the smart contract state as a partition of the chain's data state, which can only be written by the +smart contract program itself. + +The smart contract also owns an account on the chain, stored as part of the chain state. +The smart contract account represents the balances of base tokens, native tokens, and NFTs controlled by the smart +contract. + +The smart contract program can access its state and account through an interface layer called the _Sandbox_. +Only the smart contract program can change its data state and spend from its +account. Tokens can be sent to the smart contract account by any other agent on +the ledger, be it a wallet with an address or another smart contract. + +See [Accounts](./how-accounts-work.md) for more information on sending and receiving +tokens. + +## Entry Points + +Each smart contract has a program with a collection of _entry points_. +An entry point is a function through which you can invoke the program. + +There are two types of entry points: + +- _Full entry points_ (or simply _entry points_): These functions can modify + (mutate) the smart contract's state. +- _View entry points_ (or _views_): These are read-only functions. They are only used + to retrieve the information from the smart contract state. They cannot + modify the state, i.e., they are read-only calls. + +## Execution Results + +After a request to a Smart Contract is executed (a call to a full entry point), a _receipt_ will be added to +the [`blocklog`](../reference/core-contracts/blocklog.md) core contract. The receipt details the +execution results +of said request: whether it was successful, the block it was included in, and other information. +Any events dispatched by the smart contract in context of this execution will also be added to the receipt. + +## Error Handling + +Smart contract calls can fail: for example, if they are interrupted for any reason (e.g., an exception) or if it +produces an error (missing parameter or other inconsistency). +Any gas spent will be charged to the sender, and the error message or value is stored in the receipt. diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/smart-contracts.md b/docs/build/isc/v1.3-alpha/docs/explanations/smart-contracts.md new file mode 100644 index 00000000000..b7b194d8749 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/smart-contracts.md @@ -0,0 +1,54 @@ +--- +description: 'Smart contracts are applications you can trust that run on a distributed network with multiple validators +all executing and validating the same code.' +image: /img/banner/banner_wasp_core_concepts_smart_contracts.png +tags: + +- smart contracts +- blockchain +- parallel +- scaling +- explanation + +--- + +# Smart Contracts + +![Wasp Node Smart Contracts](/img/banner/banner_wasp_core_concepts_smart_contracts.png) + +## What Are Smart Contracts? + +Smart contracts are software applications that run on a distributed network with multiple validators executing and +validating the same code. This ensures the application behaves as expected and that there is no tampering in the +program's execution. + +### Applications You Can Trust + +As you can be certain that the executed code is always the same (and will not change), this results in +applications you can trust. This allows you to use smart contracts for applications with a trust issue. The +smart contract rules define what the contract can and can not do, making it a decentralized and predictable +decision-maker. + +You can use smart contracts for all kinds of purposes. A recurring reason to use a smart contract is to automate +specific +actions without needing a centralized entity to enforce this specific action. A good example is a smart contract +that can exchange a certain amount of IOTA tokens for land ownership. The smart contract will accept +both the IOTA tokens and the land ownership, and will predictably exchange them between both parties without the risk of +one of the parties not delivering on their promise. **With a smart contract, code is law**. + +### Scalable Smart Contracts + +Anyone willing to pay the fees for deploying a smart contract on a public blockchain can deploy one. Once your smart +contract has been deployed to the chain, you no longer have the option to change it, and you can be sure that your +smart contract application will be there as long as that blockchain exists. Smart contracts can communicate with one +another, and you can invoke programmed public functions on a smart contract to trigger actions on a smart contract, or +address the state of a smart contract. + +Because smart contracts do not run on a single computer but on many validators, a network of validators can only +process so many smart contracts at once, even if the software has been written optimally. This means smart contracts are +expensive to execute, and do not scale well on a single blockchain, often resulting in congested networks and costly +fees for executing functions on smart contracts. **By allowing many blockchains executing smart contracts to run in +parallel** and communicate with one another, **IOTA Smart Contracts solves this scalability problem.** + +At the same time, ISC provides advanced means of communication between its chains and preserves the ability to create +complex, composed smart contracts. diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/state_manager.md b/docs/build/isc/v1.3-alpha/docs/explanations/state_manager.md new file mode 100644 index 00000000000..dcbbf0c9e06 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/state_manager.md @@ -0,0 +1,209 @@ +--- +description: State manager is Wasp component, which is responsible for keeping the store up to date. +image: /img/logo/WASP_logo_dark.png +tags: + - state manager + - pruning + - snapshot + - write ahead log + - WAL +--- + +# State Manager + +State manager aims at keeping the state of the node up to date by retrieving missing data and ensuring that it is +consistently stored in the DB. It services requests by other Wasp components (consensus, _mempool_), which mainly +consist of ensuring that the required state is available in the node: that it may be retrieved from the permanent +store of the node (the database; DB). An obvious way to obtain the latest state is to obtain all of the blocks, +that resulted in making that state. So to obtain state index `n`, state manager first must commit block index `0` +(origin block), then block index `1`, then block index `2` etc. up to block index `n` precisely in that order. +There are two ways for state manager to obtain blocks (other than origin block): + +1. Receive them directly from this node's consensus when the new state[^1] is decided. State manager has no influence + to this process. +2. Receive them from neighbouring nodes upon request, provided the block is available there. + +Independently of the way the block is received, it is stored in state manager's cache (for quicker access) and WAL +(to ensure availability). Therefore it may happen that the block can be retrieved from there. + +[^1] A block is a difference between two consecutive states. To make state index `n`, block index `n` must be obtained +and committed on top of state index `n-1`. Although state manager manipulates blocks, in this description sometimes +"state" and "block" will be used interchangeably as "obtaining block" or "committing block" is essentially the same as +"obtaining state" or "committing state" respectively, having in mind that previous state is already obtained or committed. Block +and state has some other common properties, e.g. block index `n`, which applied to state index `n-1` produces state index `n`, +contains the same commitment as state index `n`. + +## Snapshot + +Once in a while there might be a need to add a new node to the network. This node has no knowledge of chain's history +and it still needs to have the newest state of the chain (to catch up the chain). If the chain has been running for a while, +it might have gone through many sate transitions and downloading that many blocks may take a long period of time. To avoid that, +some nodes in the network can be configured to dump a complete state of the chain at some time into a file periodically +(see `snapshots.period` parameter). This file is called a snapshot. Loading a snapshot to DB produces the same state as downloading +and committing all the blocks that produced that state. However as those blocks aren't downloaded, they are not available in the DB, +except a block with the same state index as snapshot. + +The snapshot format is as follows: + +1. number `4` in 4 byte unsigned integer little endian format representing the length of state index, +2. state index in 4 byte unsigned integer little endian format, +3. number `40` in 4 byte unsigned integer little endian format representing the length of state commitment: `20` bytes for trie root and + `20` bytes for hash of a block, which was last committed to make this state (block with the same index as state), +4. trie root in `20` bytes, +5. the mentioned block's hash in `20` bytes, +6. number `0` in 1 byte unsigned integer format representing snapshot version, +7. bytes representing mentioned block, +8. bytes representing trie of the state. + +The node that makes a snapshot can serve it over http and new nodes can use this to speed up the catch up. Serving the snapshots +over http is beyond the scope of Wasp and should be done in addition. Wasp is only responsible for making snapshots in local +(configurable by `snapshots.localPath` parameter) folder and obtaining them on start when needed from the same local folder or from +configured (by `snapshots.networkPaths` parameter) URLs. A folder, referenced in the `snapshots.networkPaths` parameter must contain +`INDEX` file with new line separated list of snapshot file names. + +If a chain starts with an empty database (usually if the database hasn't been created yet or was deleted), the node checks if +it can load a snapshot: it scans the local folder and all the network addresses for available snapshot files. In the local folder, it reads +all the files with names that satisfy the search pattern `*-*.snap`. In each network location, Wasp reads all the files listed in `INDEX` +file of that location. Wasp reads a state index and a commitment from the contents of these files. File names are not used to obtain +this information, and full snapshot files are not (down)loaded yet. The node chooses +the one with the largest state index and loads it to the store among all available snapshot files. If several files have the same largest state index, +the node loads them one by one, starting from the local ones until one snapshot is loaded correctly. If loading fails for all candidates, +the node will start with an empty database. + +You can use the `snapshots.snapshotsToLoad` parameter to load a specific snapshot. In that case, the node searches for snapshots with +the block hash provided in the parameter. Once again, if loading all found files fails, the node starts with an empty database. + +After a snapshot is loaded, earlier blocks (ones with a smaller state index than the snapshot) cannot be retrieved and committed to the DB +(this is discussed in [Obtaining blocks section](#obtaining-blocks)). This constraint can cause problems (especially in reorg) +if the loaded snapshot is too recent. To avoid that, making snapshots is delayed by `snapshots.delay` states. E.g., if `snapshots.period` +is `100` and `snapshots.delay` is `20`, then snapshot index `100` will be produced. When block index `120` is committed, snapshot index +`200` will be produced, when snapshot index `220` is committed, etc... For the data to be available after this delay, `snapshot.delay` +value must be considerably smaller than `stateManager.pruningMinStatesToKeep`. + +## Obtaining blocks + +Requests to the state manager contain the state commitment and the state manager must ensure, that block (state) with this +commitment is present in the DB. It is possible that to satisfy the request state manager needs to retrieve +several blocks. However this cannot be done in one step as only the commitment of the requested block is known. For this +reason state (block) contains a commitment of the previous block. Previous block must be committed prior to committing the +requested block. And this logic can be extended up to the block, which is already present in the DB, or until the origin +state is reached. + +E.g., let's say, that the last state in the DB is state index `10` and request to have state index `12` is received. +State manager does this in following steps: + +1. Block index `12` is obtained, and commitment of block index `11` is known. +2. As the commitment of block (state) index `11` is known, the block may be requested and obtained. After obtaining block + index `11` commitment of block index `10` is known. +3. Using block index `10` commitment the DB is checked to make sure that it is already present. +4. As block index `10` is already committed, block index `11` is committed. This makes state `11` present in the DB. +5. As state `11` is already committed, block index `12` is committed. This makes state `12` present in the DB and completes + the request. + +To obtain blocks, state manager sends requests to 5 other randomly chosen nodes. If the block is not received (either messages +got lost or these nodes do not have the requested block), 5 other randomly chosen nodes are queried. This process is repeated +until the block is received (usually from other node but may also be from this node's consensus) or the request is no longer +valid. + +If difference between state indexes of requested state and available in the DB state is large, this chain can get very long. +In order to limit its length, if requested block index is a) smaller than state index of snapshot, which was loaded on node +start, or b) smaller than largest state index among the pruned blocks (see [Pruning](#pruning)), the node panics. If this panicking +continues, the administrator may decide to delete the DB and start the node from (possibly configured) snapshot. + +## Block cache + +Block cache is in memory block storage. It keeps a limited amount (configured by `stateManager.blockCacheMaxSize`) of blocks +for limited amount of time (configured by `stateManager.blockCacheBlocksInCacheDuration`) to make the retrieval +quicker. E.g., in the last step of example of the previous section block index `12` must be committed. It is obtained in +the step 1, but as several steps of the algorithm are spread over time with requests to other nodes in between, and +several requests to obtain the same block may be present, it is not feasible to store it in request. However it would +be wasteful to fetch it twice on the same request. So the block is stored in cache in step 1 of the algorithm and +retrieved from cache later in the last step. + +The block is kept in the cache no longer that predetermined amount of time (configured by `stateManager.blockCacheBlocksInCacheDuration`). +If upon writing to cache blocks in cache limit is exceeded, block, which is in cache the longest, is removed from cache. + +## Block write ahead log (WAL) + +Upon receiving a block, its contents is dumped into a file and stored in a file system. The set of such files is WAL. + +The primary motivation behind creating it was in order not to deadlock the chain. Upon deciding on next state committee +nodes send the newest block to state manager and at the same time one of the nodes send the newest transaction to L1. +In an unfavourable chain of events it might happen that state managers of the committee nodes are not fast enough to commit +the block to the DB (see algorithm in [Obtaining blocks section](#obtaining-blocks)), before the node crashes. This leaves +the nodes in the old state as none of the nodes had time to commit the block. However the L1 reports the new state as +the latest although none of the nodes can be transferred to it. The solution is to put the block into WAL as soon as +possible so it won't be lost. + +Currently upon receiving the new confirmed block from node's consensus, state manager is sure that its predecessor is in the DB, +because consensus sends other requests before sending the new block, so WAL isn't that crucial any more. However, it is useful +in several occasions: + +1. Storing preliminary block, which is sent by consensus of other nodes. +2. When the node is catching up many states and block cache limit is too small to store all the blocks, WAL is used to avoid + fetching the same block twice. +3. In case of adding new node to the network to avoid catch up taking a lot of time when snapshots are not available, + the new node can be configured (`wal.loadToStore=true`) to load the DB with blocks from WAL on startup. WAL can be copied + from some other node. This is also true for any catch up over many states. + +## Pruning + +In order to limit the DB size, old states are deleted (pruned) from it on a regular basis. The amount of states to keep is +configured by two parameters: one in the configuration of the node (`stateManager.pruningMinStatesToKeep`) and one in the governance contract +(`BlockKeepAmount`). The resulting limit of previous states to keep is the larger of the two. Every time a block is committed +to the DB, states which are over the limit are pruned. However, to avoid freezing State manager for too long, no more than +`stateManager.pruningMaxStatesToDelete` blocks are pruned in a single run. The algorithm ensures that oldest states are pruned +first to avoid gaps between available states on the event of some failure. + +Pruning may be disabled completely via node configuration to make an archive node: node that contains all the state ever +obtained by the chain. Note, that such node will require a lot of resources to maintain: mainly disk storage. + +## Parameters + +### State manager + +The following parameters may be provided in section `stateManager`: + +- `blockCacheMaxSize`: the limit of the blocks in block cache. Default is 1k. +- `blockCacheBlocksInCacheDuration`: the limit of the time block stays in block cache. Default is 1 hour. +- `blockCacheBlockCleaningPeriod`: how often state manager should find and delete blocks, that stayed in block cache + for too long. Default is every minute. +- `stateManagerGetBlockRetry`: how often requests to retrieve the needed blocks from other nodes should be repeated. + Default is every 3 seconds. +- `stateManagerRequestCleaningPeriod`: how often state manager should find and delete requests, that are no longer valid. + Default is every second. +- `stateManagerTimerTickPeriod`: how often state manager should check if some maintenance (cleaning requests or block cache, + resending requests for blocks) is needed. Default is every second. There is no point in making this value larger than + any of `blockCacheBlockCleaningPeriod`, `stateManagerGetBlockRetry` or `stateManagerRequestCleaningPeriod`. +- `pruningMinStatesToKeep` : minimum number of old states to keep in the DB. Note that if `BlockKeepAmount` in + governance contract is larger than this value, then more old states will be kept. + Default is 10k. 0 (and below) disables pruning. +- `pruningMaxStatesToDelete`: maximum number of states to prune in one run. This is needed in order not to grab + state manager's time for pruning for too long. Default is 1k. + +### Snapshots + +The following parameters may be provided in section `snapshots`: + +- `snapshotsToLoad`: the comma sepparated list of `:` pairs, where chain `` must be started using snapshot with block hash ``. + The list can also contain `` entry. This hash will be used for other chains, which are not configured separately. There is + no point in having several `` or `:` entries with the same `` as only the last such entry is taken into + account. Note that if the chain is configured to start from some snapshot and the snapshot is not available (or another error occurs + during snapshot loading), the chain will start with an empty DB. The default is an empty list, which means that the newest available snapshot + will be loaded for every chain. +- `period`: how often state snapshots should be made: 1000 meaning "every 1000th state", 0 meaning "making snapshots is disabled". + Snapshots are disabled by default. +- `delay`: how many states to delay making the snapshot; it must be considerably smaller than `stateManager.pruningMinStatesToKeep`. + The default is 20. +- `localPath`: the path to the snapshots folder in this node's disk. Default is `waspdb/snap`. +- `networkPaths`: the comma-separated list of URLs that serve snapshots. The URLs may have the HTTP (e.g., `http://server.org/path/`) or the HTTPS + (e.g., `https://server.org/path/`) scheme for remote locations or a file path (e.g., `file://path/to/folder`) scheme for local snapshot locations. + The scheme is compulsory in the URL. The list is empty by default. + +### WAL + +The following parameters may be provided in section `wal`: + +- `loadToStore`: load blocks from WAL to the store on node start-up. This function is off (`false`) by default. +- `enabled`: whether the WAL is enabled. It is enabled by default. +- `path`: the path to the WAL folder. Default is `waspdb/wal`. diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/states.md b/docs/build/isc/v1.3-alpha/docs/explanations/states.md new file mode 100644 index 00000000000..819068b9aaf --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/states.md @@ -0,0 +1,122 @@ +--- +description: 'The state of the chain consists of balances of native IOTA digital assets and a collection of key/value +pairs which represents use case-specific data stored in the chain by its smart contracts outside the UTXO ledger.' +image: /img/chain0.png +tags: + +- state +- transitions +- balances +- digital assets +- UTXO +- transitions +- explanation +--- + +# State, Transitions, and State Anchoring + +## State of the Chain + +The state of the chain consists of: + +- A ledger of accounts owning IOTA _digital assets_ (base tokens, native tokens, and NFTs). The chain acts as a custodian + for those funds on behalf of each account's owner. +- A collection of arbitrary key/value pairs (the _data state_) that contains use case-specific data stored by the smart + contracts in the chain. + +The chain's state is an append-only (immutable) _data structure_ maintained by the distributed consensus of its +validators. + +## Digital Assets on the Chain + +Each native L1 account in the IOTA UTXO ledger is represented by an address and controlled by an entity holding the +corresponding private/public key pair. +In the UTXO ledger, an account is a collection of UTXOs belonging to the address. + +Each ISC L2 chain has a L1 account, called the _chain account_, holding all tokens entrusted to the chain in a single +UTXO, the _state output_. +It is similar to how a bank holds all deposits in its vault. This way, the chain (the entity controlling the state +output) becomes a custodian for the assets owned by its clients, similar to how the bank’s client owns the money +deposited in the bank. + +The consolidated assets held in the chain are the _total assets on-chain_, which are contained in the state output of +the chain. + +The chain account is controlled by a _chain address_, also known as _chain ID_. +It is a special kind of L1 address, an _alias address_, which abstracts the controlling entity (the state controller +address) from the identity of the chain: the controlling entity of the chain may change, while the chain ID stays the +same. + +## The Data State + +The data state of the chain consists of a collection of key/value pairs. +Each key and each value are arbitrary byte arrays. + +In its persistent form, the data state is stored in a key/value database outside the UTXO ledger and maintained by the +validator nodes of the chain. +The state stored in the database is called the _solid state_. + +While a smart contract request is being executed, the _virtual state_ is an in-memory collection of key/value pairs that +can become solid upon being committed to the database. +An essential property of the virtual state is the possibility of having several virtual states in parallel as +candidates, with a possibility for one of them to be solidified. + +The data state has a state hash, a timestamp, and a state index. +The state hash is usually a Merkle root, but it can be any hashing function of all data in the data state. + +The data state hash and on-chain assets are contained in a single atomic unit on the L1 ledger: the state UTXO. +Each state mutation (state transition) of the chain is an atomic event that changes the on-chain assets and the data +state, consuming the previous state UTXO and producing a new one. + +## Anchoring the State + +The data state is stored outside the ledger, on the distributed database maintained by _validator_ nodes. +_Anchoring the state_ means placing the hash of the data state into the state UTXO and adding it to the L1 UTXO ledger. +The UTXO ledger guarantees that there is _exactly one_ such output for each chain on the ledger at every moment. +We call this output the _state output_ (or state anchor) and the containing transaction the _state transaction_ (or +anchor transaction) of the chain. +The state output is controlled (i.e., can be unlocked/consumed) by the entity running the chain. + +With the anchoring mechanism, the UTXO ledger provides the following guarantees to the IOTA Smart Contracts chain: + +- There is a global consensus on the state of the chain +- The state is immutable and tamper-proof +- The state is consistent (see below) + +The state output contains: + +- The identity of the chain (its L1 alias address) +- The hash of the data state +- The state index, which is incremented with each new state output + +## State Transitions + +The data state is updated by mutations of its key/value pairs. +Each mutation either sets a value for a key or deletes a key (and the associated value). +Any update to the data state can be reduced to a partially ordered sequence of mutations. + +A _block_ is a collection of mutations to the data state that is applied in a state transition: + +```go +next data state = apply(current data state, block) +``` + +The state transition in the chain occurs atomically in a L1 transaction that consumes the previous state UTXO and +produces the next one. The transaction includes the movement of the chain's assets and the update of the state hash, + +At any moment in time, the data state of the chain is a result of applying the historical sequence of blocks, starting +from the empty data state. + +![State transitions](/img/chain0.png) + +On the L1 UTXO ledger, the state's history is represented as a sequence (chain) of UTXOs, each holding the chain’s +assets in a particular state and the anchoring hash of the data state. +Note that not all the state's transition history may be available: due to practical reasons, older transactions may be +pruned in a snapshot process. +The only thing guaranteed is that the tip of the chain of UTXOs is always available (which includes the latest data +state hash). + +The ISC virtual machine (VM) computes the blocks and state outputs that anchor the state, which ensures that the state +transitions are calculated deterministically and consistently. + +![Chain](/img/chain1.png) diff --git a/docs/build/isc/v1.3-alpha/docs/explanations/validators.md b/docs/build/isc/v1.3-alpha/docs/explanations/validators.md new file mode 100644 index 00000000000..97ed59a19c0 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/explanations/validators.md @@ -0,0 +1,49 @@ +--- +description: Each chain is run by a network of validator nodes which run a consensus on the chain state update. +image: /img/logo/WASP_logo_dark.png +tags: + - validators + - validator nodes + - access nodes + - consensus + - state update + - explanation +--- + +# Validators + +Each chain is run by that chain's _committee of validators_. This committee owns a key that is split between all of its +validators. Each key share is useless on its own, but a collective signature gives validators complete control over the +chain. + +The committee of validators is responsible for executing the smart contracts in the chain and thus calculating a _state +update_. +All validators execute exactly the same code and reach a consensus on the state update. +Once the next state is computed and validated, it is committed to each validator's database, a new _block_ is added to +the chain (containing the state mutations), and the _state hash_ is saved in the L1 ledger. + +Depending on the governance model, chain owners can rotate the committee of validators. +By rotating the committee of validators, validators can be deleted, added, or replaced. + +ISC does not define how to select validators to form a committee: it could be a solitary choice of the chain's owner, or +it could be a public competition between candidates. +ISC does not define how validators are rewarded either. + +## Access Nodes + +It is possible to have some nodes act as _access nodes_ to the chain without being part of the committee of +validators. +All nodes in the subnet (validators and non-validators) are connected through statically assigned trust +relationships and each node is also connected to the IOTA L1 node to receive updates on the chain’s L1 +account. + +Any node can optionally provide access to smart contracts for external callers, allowing them to: + +- Query the state of the chain (i.e., _view calls_) +- Send off-ledger requests directly to the node (instead of sending an on-ledger request as a L1 transaction) + +It is common for validator nodes to be part of a private subnet and have only a group of access nodes exposed to the +outside world, protecting the committee from external attacks. + +The management of validator and access nodes is done through +the [`governance` core contract](../reference/core-contracts/governance.md). diff --git a/docs/build/isc/v1.3-alpha/docs/getting-started/compatibility.md b/docs/build/isc/v1.3-alpha/docs/getting-started/compatibility.md new file mode 100644 index 00000000000..93168c9f134 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/getting-started/compatibility.md @@ -0,0 +1,47 @@ +--- +description: Compatibility between the ISC EVM layer and existing Ethereum smart contracts and tooling. +image: /img/logo/WASP_logo_dark.png +tags: + - smart contracts + - EVM + - Ethereum + - Solidity + - limitations + - compatibility + - fees + - reference +--- + +# EVM Compatibility in IOTA Smart Contracts + +The [`evm`](../reference/core-contracts/evm.md) [core contract](../reference/core-contracts/overview.md) +provides EVM support in IOTA Smart Contracts. It stores the EVM state (account balances, state, code, +etc.) and provides a way to execute EVM code to manipulate the state. + +The EVM core contract runs on top of the ISC layer, which provides the rest of the machinery needed to run smart +contracts, such as signed requests, blocks, state, proofs, etc. + +However, the ISC EVM layer is also designed to be as compatible as possible with existing Ethereum tools +like [MetaMask](https://metamask.io/), which assume that the EVM code runs on an Ethereum blockchain composed of +Ethereum blocks containing Ethereum transactions. Since ISC works in a fundamentally different way, +providing 100% compatibility is not possible. We do our best to emulate the behavior of an Ethereum node, so the +Ethereum tools think they are interfacing with an actual Ethereum node, but some differences in behavior are inevitable. + +## Properties and Limitations + +Here are some of the most important properties and limitations of EVM support in IOTA Smart Contracts: + +### No Enforced Block Time + +There is no guaranteed _block time_. A new EVM "block" will be created only when an ISC block is created, and ISC does +not enforce an average block time. This means that block times are variable; a new block will be created as soon as needed. +The average block time on [ShimmerEVM](/build/networks-endpoints#shimmerevm) is 2.8 seconds. + +### The Magic Contract + +A [dedicated Ethereum contract](../how-tos/core-contracts/introduction.md) exists to manage Layer 1 tokens and ISC +functionalities, introducing commands like `isc.send(...)` for token transfers. + +### Gas Fees + +Gas fees are set by the chain. diff --git a/docs/build/isc/v1.3-alpha/docs/getting-started/languages-and-vms.md b/docs/build/isc/v1.3-alpha/docs/getting-started/languages-and-vms.md new file mode 100644 index 00000000000..64bacc1c8b4 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/getting-started/languages-and-vms.md @@ -0,0 +1,87 @@ +import EVMCompatibility from '../_admonitions/_EVM_compatibility.md' +import NetworkWarning from '../_admonitions/_network_warning.md' + +# Supported Virtual Machines & Languages + + + +The current release of IOTA Smart Contracts has support for [EVM/Solidity](#evmsolidity-based-smart-contracts) smart +contracts, as well as experimental [Wasm](#wasm-vm-for-isc) smart contracts, providing compatibility with +existing smart contracts and tooling from other EVM based chains like Ethereum. This allows us to offer the existing +ecosystem around EVM/Solidity a familiar alternative. + +## EVM Smart Contracts + +### What is EVM/Solidity? + +[EVM](https://ethereum.org/en/developers/docs/evm/) stands for "Ethereum Virtual Machine" and is currently the tried and +tested virtual machine running most smart contract networks. + +[Solidity](https://soliditylang.org/) is the programming language of choice for the EVM. It was created for this +specific purpose. + +The main benefit of using EVM/Solidity is its sheer amount of resources from years of development. The IOTA +Smart Contracts implementation is fully compatible with all of them. If you have experience developing on other EVM based chains, you will feel right at home. Any existing contracts you've written will need no +changes to function on IOTA Smart Contracts. + +### How IOTA Smart Contracts Work With EVM + +Every deployed ISC chain automatically includes a core contract +called [`evm`](../reference/core-contracts/evm.md). This core contract is responsible for running EVM code and +storing the EVM state. + +The Wasp node also provides a standard JSON-RPC service, which allows you to interact with the EVM layer using existing +tooling like [MetaMask](https://metamask.io/), [Remix](https://remix.ethereum.org/) or [Hardhat](https://hardhat.org/). +Deploying EVM contracts is as easy as pointing your tools to the JSON-RPC endpoint. + + + +## Wasm VM for ISC + +:::warning Experimental + +The Wasm _VM_ is in experimental state, showcasing ISC's "VM plugin" architecture. + +Experiment but avoid using it for production applications; opt for [EVM](quick-start.mdx). + +::: + +IOTA Smart Contracts (ISC) provide a sandboxed environment through an API, facilitating secure and deterministic +interactions with ISC functions. This API supports any Virtual Machine (VM) aiming to build a system for smart contract + code execution on ISC. + +![Wasp node ISC Host](/img/wasm_vm/IscHost.png) + +You can use a [WebAssembly (Wasm)](https://webassembly.org/) VM as a compilation target, facilitated by the open-source +[Wasmtime runtime](https://wasmtime.dev/). This setup encourages dynamic smart contract operations compiled to Wasm code, +promoting security and adaptability with different programming languages. + +![Wasm VM](/img/wasm_vm/WasmVM.png) + +The Wasm VM operates with self-contained `WasmLib` libraries linked to individual Wasm codes, optimizing the ISC sandbox +functionality and smart contract state storage access. + +### Supported Functionalities + +The ISC sandbox environment offers: + +- Smart contract metadata and state data access. +- Request data retrieval for function calls. +- Token management within the contract. +- Utility functions from the host. +- Smooth initiation of other smart contract functions. +- Logging facility. + +### Supported Languages + +The WasmLib started with [Rust](https://www.rust-lang.org/) support, expanding to include [Go](https://golang.org/) +and [TypeScript](https://www.typescriptlang.org/) with the help of respective Wasm code generators: + +| Language | Wasm code generator | +|------------|----------------------------------------------------| +| Go | [TinyGo](https://tinygo.org/) | +| Rust | [wasm-pack](https://rustwasm.github.io/wasm-pack/) | +| TypeScript | [AssemblyScript](https://www.assemblyscript.org/) | + +These generators maintain a common subset of their host language, aiming for a unified coding style to simplify the +initiation into smart contract creation, welcoming developers with a C-style language background to quickly adapt. \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/getting-started/networks-and-chains.mdx b/docs/build/isc/v1.3-alpha/docs/getting-started/networks-and-chains.mdx new file mode 100644 index 00000000000..cd1d3902ea0 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/getting-started/networks-and-chains.mdx @@ -0,0 +1,72 @@ +--- +description: Networks and endpoints in the IOTA ecosystem. +tags: + - mainnet + - shimmer + - devnet + - public testnet + - reference + - Endpoints +--- +import { AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; +import { Networks } from '@theme/constant'; +import NetworkInfo from '@theme/NetworkInfo'; + +# Networks & Chains +## IOTA EVM Testnet + + + +[The IOTA EVM Testnet](https://explorer.evm.testnet.iotaledger.net/) runs as a layer 2 on top +of the [IOTA Testnet](/build/networks-endpoints#iota-testnet). This network uses ISC to facilitate +an Ethereum Virtual Machine and has an enshrined bridge to layer 1. + +:::info + +This network is subject to occasional resets (no data retention) which are usually announced with a one-week grace period. + +::: + + + +:::note + +The other values (network name and currency symbol) can be whatever value you like. + +::: + +## ShimmerEVM + +[ShimmerEVM](https://explorer.evm.shimmer.network/) is the L2 EVM running on top of the Shimmer network. + + + + + +## ShimmerEVM Testnet + + + +[The ShimmerEVM Testnet](https://explorer.evm.testnet.shimmer.network/) runs as a layer 2 on top +of the [Shimmer Testnet](/build/networks-endpoints#shimmer-testnet). This network uses ISC to facilitate +an Ethereum Virtual Machine and has an enshrined bridge to layer 1. + +:::info + +This network is subject to occasional resets (no data retention) which are usually announced with a one-week grace period. + +::: + + + +:::note + +The other values (network name and currency symbol) can be whatever value you like. + +::: + +## Core Contracts + +[ShimmerEVM](#shimmerEVM) and the testnet networks have 7 +[core contracts](../reference/core-contracts/overview.md) deployed, as well as the +[Magic Contract](../reference/magic-contract/introduction.md). diff --git a/docs/build/isc/v1.3-alpha/docs/getting-started/quick-start.mdx b/docs/build/isc/v1.3-alpha/docs/getting-started/quick-start.mdx new file mode 100644 index 00000000000..ebe821bdd0c --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/getting-started/quick-start.mdx @@ -0,0 +1,77 @@ +--- +description: This guide will help you quickly get started with the [Public Testnet](/build/networks-endpoints/#public-testnet) +image: /img/logo/WASP_logo_dark.png +tags: + - quickstart + - developer + - using + - EVM + - Ethereum + - Solidity + - metamask + - JSON + - RPC +--- + +import MetamaskButtons from '../../../../_partials/_metamask_buttons.mdx'; +import { Networks } from '@theme/constant'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import Link from '@docusaurus/Link'; + +# EVM Testnets Quickstart Guide + +This guide will help you quickly get started with our [EVM Testnets](/build/networks-endpoints), where you can deploy and interact with EVM-compatible smart contracts. + +## Prerequisites + +- [MetaMask](https://metamask.io/) browser extension installed + +## Setup MetaMask + +Click this button: + + + +:::tip + +Please read [the MetaMask section in the tools guide](tools.mdx#metamask) for a detailed guide. + +::: + +## Get Testnet Tokens + +:::tip Fund your testnet account + +If you want to fund your EVM testnet account, please refer to our [How To Get Funds guide](../how-tos/send-funds-from-L1-to-L2.mdx). + +::: + +1. Go to the [IOTA EVM](https://evm-toolkit.evm.testnet.iotaledger.net) or [ShimmerEVM](https://evm-toolkit.evm.testnet.shimmer.network/) Testnet Toolkit. +2. Connect your MetaMask wallet by clicking "Connect Wallet" or paste an EVM address. +3. Select the account you want to receive testnet tokens. +4. Click "Send funds" to get testnet tokens. + +## Deploy and Interact with Smart Contracts + +You can now use your testnet tokens and simulated bridged tokens to deploy and interact with smart contracts on the testnets. Utilize popular development tools and frameworks, such as [Hardhat](https://hardhat.org/), or [Remix](https://remix.ethereum.org/), to build, test, and deploy your smart contracts. + +## Explore the Public Testnet + +Visit the corresponding Testnet Block Explorer to monitor the chain, track transactions, and explore deployed smart contracts. + + + +Explorer + + +Explorer + + + +## Additional Resources + +- [GitHub issues page for Wasp](https://github.com/iotaledger/wasp/issues) +- [Firefly](https://firefly.iota.org) + +With this quickstart guide, you should now be able to set up and start exploring the [Testnet](/build/networks-endpoints). As you begin to deploy and interact with smart contracts, remember to provide feedback on any issues or improvements you discover to help make our EVM even better. Happy developing! diff --git a/docs/build/isc/v1.3-alpha/docs/getting-started/tools.mdx b/docs/build/isc/v1.3-alpha/docs/getting-started/tools.mdx new file mode 100644 index 00000000000..13709a276d4 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/getting-started/tools.mdx @@ -0,0 +1,123 @@ +--- +description: 'Existing EVM tooling is compatible and can be used directly with an IOTA Smart Contracts chain running EVM. +You can configure hardhat, metamask, remix, Ether.js and Web3.js among others.' +image: /img/logo/WASP_logo_dark.png +tags: + +- smart contracts +- chain +- EVM +- Solidity +- tooling +- wasp-cli +- hardhat +- metamask +- JSON-RPC +- reference + +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import {AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; +import HardhatConfig from '../_partials/_hardhat_config.md'; +import { Networks } from '@theme/constant'; +import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; +import { ChainId } from '@theme/ChainId'; +import NetworkInfo from '@theme/NetworkInfo'; + +# Compatible Tools + +EVM on IOTA Smart Contracts has been integrated in a way that the existing EVM tooling is compatible and can be used +directly with an IOTA Smart Contracts chain running EVM as long as you take a couple of things into account. + +## Tooling Considerations + +1. Please make sure you use the correct JSON-RPC endpoint URL in your tooling for your chain. If you're running your own chain, you can find the JSON-RPC +endpoint URL in the Wasp dashboard (`[URL]/wasp/dashboard` when using `node-docker-setup`). +2. Please ensure you use the correct `Chain ID` configured while starting the JSON-RPC service. If you did not explicitly define this while starting the service, the default Chain ID will be +for ShimmerEVM or for the EVM Testnet. +3. Fees are handled on the IOTA Smart Contracts chain level, not the EVM level. The chain will reject any requests with a different gas price than specified by the chain. + +:::caution + +Re-using an existing Chain ID is not recommended and can be a security risk. For production usage, register a unique Chain +ID on [Chainlist](https://chainlist.org/) and use that instead of the default. **It is not possible to change the EVM +chain ID after deployment.** + +::: + +## MetaMask + +[MetaMask](https://metamask.io/) is a popular EVM wallet which runs in a browser extension that allows you to +interact with EVM chains and their applications (dApps). + +To use your EVM chain with MetaMask, simply open up MetaMask and click on the network drop-down list at the very top. At +the bottom of this list, you will see the option `Add network`. On the new page you will see a list of popular network with the option `Add a network manually`. +For example this would be the configs to add our different [EVM chains](/build/networks-endpoints): + + + + + + + + + + + + + + + + +Ensure that your `RPC Url` and `Chain ID` are set correctly and match the dashboard values. The `Network Name` can be +whatever you see fit. Click "Save" to add the chain to MetaMask. + +If you wish to use additional EVM chains with Metamask, you can add more Custom RPC networks, as long as they have a +unique `Chain ID` and `RPC Url`. Once you have done this, you can start using MetaMask to manage your EVM wallet or +issue/sign transactions with any dApp running on that network. + +### Remix + +If you also want to use the [Remix IDE](https://remix.ethereum.org/) to deploy any regular Solidity Smart Contract, you +should set the environment as **Injected Provider - Metamask**, which should then connect with your MetaMask wallet. + +Click on the _Deploy & Run transactions_ button in the menu on the left and select `Injected Web3` from +the `Environment` dropdown. + +![Select Injected Provider from the Environment dropdown](/img/evm/remix-injected-provider-metamask.png) + + + +Metamask will ask to connect to Remix, and once connected, it will set the `Environment` to `Injected Web3` with +the "Custom (Chain ID) network". + +![Environment will be set to Injected Web3](/img/evm/remix-injected-provider-set.png)] + +## Hardhat + +[Hardhat](https://hardhat.org/) is a command line toolbox that allows you to deploy, test, verify, and interact with +Solidity smart contracts on an EVM chain. EVM chains running on IOTA Smart Contracts are compatible with Hardhat; simply +make sure you add the correct network parameters to your `hardhat.config.js`, for example: + + + + + +:::caution + +Currently, there is no validation service available for EVM/Solidity smart contracts on IOTA Smart Contracts, which is +often offered through block explorer APIs. + +::: + +## Ethers.js/Web3.js + +If you input the correct configuration parameters for the JSON-RPC endpoint to talk +to, [Ethers.js](https://docs.ethers.io/) and [Web3.js](https://web3js.readthedocs.io/) are also compatible with EVM +chains on IOTA Smart Contracts. Alternatively, you can let both interact through MetaMask instead so that it uses the +network configured in MetaMask. For more information on this, read their documentation. + +## Other Tooling + +Most tools available will be compatible if you enter the correct `Chain ID` and `RPC Url`. diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/ERC20.md b/docs/build/isc/v1.3-alpha/docs/how-tos/ERC20.md new file mode 100644 index 00000000000..9bbd6929beb --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/ERC20.md @@ -0,0 +1,93 @@ +--- +description: Solidity smart contract ERC20. +image: /img/logo/WASP_logo_dark.png +tags: + - smart contracts + - EVM + - Solidity + - ERC20 + - eip-20 + - token creation + - mint tokens + - how to +--- + +import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; +import PriorKnowledge from '../_admonitions/_EVM-required-prior-knowledge.md'; +import RemixIDE from '../_admonitions/_remix-IDE.md'; + +# Create ERC20 Custom Tokens + +## Required Prior Knowledge + + + +## About ERC20 + +ERC20 is a standard for fungible tokens and is defined in +the [EIP-20 Token Standard](https://eips.ethereum.org/EIPS/eip-20) by Ethereum. + +With the ERC20 standard, you can create your own tokens and transfer them to the EVM on IOTA Smart Contracts without +fees. + + + +## 1. Create the Smart Contract + +Create a new Solidity file, for example, `ERC20.sol` in the contracts folder of +your [Remix IDE](https://remix.ethereum.org/) and add this code snippet: + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.7; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract ExampleERC20Token is ERC20 { + constructor() ERC20("ExampleERC20Token", "EET") { + _mint(msg.sender, 1000000 * 10 ** decimals()); + } +} +``` + +This imports all functions from the [OpenZeppelin ERC20](https://docs.openzeppelin.com/contracts/4.x/erc20) smart +contract and creates a new ERC20 token with your name and Symbol. + +:::tip OpenZeppelin + +OpenZeppelin provides many audited smart contracts and is a good point to start and learn. + +::: + +:::note Customize Your Token + +You can change the token name `ExampleERC20Token` and the token symbol `EET` for anything you want. + +::: + + + +## 2. Add Your Custom Tokens to MetaMask + +Once you have deployed your contract, you can add your new custom token to your Metamask account. + +1. Open Metamask, and click on the transaction that created the contract. From there, you can simply click + on `View on block explorer` to visit the transaction details. Alternatively, you can copy the transaction ID and + visit the [ShimmerEVM Explorer](https://explorer.evm.testnet.shimmer.network/) + or [ShimmerEVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/) and use the search bar to find transaction. + +!['View on block explorer](/img/evm/how-tos/ERC20/metamask-get-transaction-or-go-to-block-explorer.png) + +2. Copy the contract address from the transaction details, and import your custom ERC20 tokens into MetaMask. + +![Copy contract address](/img/evm/how-tos/ERC20/metamask-import-tokens.png) + +## 3. Have some Fun + +Now you should see your token in MetaMask. You can send them to your friends without any fees or gas costs. + +![Copy contract address](/img/evm/how-tos/ERC20/metamask-erc20-balance.png) + +You also can ask in the [Discord Chat Server](https://discord.iota.org) to send them around and discover what the +community is building on IOTA Smart Contracts. diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/ERC721.md b/docs/build/isc/v1.3-alpha/docs/how-tos/ERC721.md new file mode 100644 index 00000000000..0b66f129e59 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/ERC721.md @@ -0,0 +1,127 @@ +--- +description: Create and deploy a Solidity smart contract to mint NFTs using the ERC721 standard. +image: /img/evm/ozw-721.png +tags: + - smart contracts + - EVM + - Solidity + - ERC721 + - eip-721 + - token creation + - mint tokens + - how to +--- +import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; +import PriorKnowledge from '../_admonitions/_EVM-required-prior-knowledge.md'; +import RemixIDE from '../_admonitions/_remix-IDE.md'; + +# Create ERC721 NFTs + +:::info EVM-only NFT + +Please keep in mind that this is an EVM-only NFT. It's not tied to L1 native assets. Also, these are different from L1 +NFTs. + +::: + + + +## About ERC721 + +Non-fungible tokens or NFTs are a type of token that can represent any unique object, including a real-world asset on a +decentralized network. NFTs are commonly represented by the ([ERC721 standard](https://eips.ethereum.org/EIPS/eip-721)). +You can use the +openzepplin +lib [`@openzeppelin/contracts/token/ERC721/ERC721.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol) +to streamline your development experience. + +You can also use the ([OpenZepplin Contracts Wizard](https://wizard.openzeppelin.com/#erc721)) to generate and customize +your smart contracts. + + + +## Create the Smart Contract + +The following is an example NFT Smart Contract called "ShimmerEVMSampleNFT". + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts@5.0.1/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts@5.0.1/access/Ownable.sol"; + +contract ShimmerEVMSampleNFT is ERC721, Ownable { + uint256 private _nextTokenId; + + constructor(address initialOwner) + ERC721("ShimmerEVMSampleNFT", "SSNFT") + Ownable(initialOwner) + {} + + function _baseURI() internal pure override returns (string memory) { + return "https://example.com/nft/"; + } + + function safeMint(address to) public onlyOwner { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + } +} +``` + +As you can see above, the contract uses standard methods for the most part. You should pay attention to the following: + +- `pragma solidity ^0.8.20;`: This line means the contract uses solidity compiler version `0.8.20` or above. +- `contract ShimmerEVMSampleNFT is ERC721, ERC721URIStorage, Ownable`: This line defines the contract's name, and what + other contracts it implements. +- `ERC721("ShimmerEVMSampleNFT", "SNFT") {}`: This line defines the token name and symbol. You can name it + whatever you want. We recommend using the same name for the token and the contract. +- `return "https://example.com/nft/";`: You should define the base URI of your NFTs. That means the URL you provide here + will be used for all your tokens. Since this contract uses auto-incremental token IDs, your token URI will look + something like `https://example.com/nft/0`, `https://example.com/nft/1`, `https://example.com/nft/2`, and so on. +- `function safeMint(address to, string memory uri) public onlyOwner {`: The `safeMint` function will + require that you manually input a token's `to` address and a `uri` every time you want to mint. This should work for + regular use cases. + +### Customize on OpenZeppelin + +You can customize your contract depending on how you want it to behave. You should consider the following topics +and questions: + +1. **Ownership** — Who owns it? How is it stored? +2. **Creation** — Method or Type of Creation. +3. **Transfer & Allowance** — How will tokens be transferred? How will they be available to other addresses and + accounts? +4. **Burn** — Do you want to destroy it? If yes, how? + +You can click on `Copy to Clipboard` and paste it into the IDE of your choice, download it, or click on `Open in Remix` +directly. + + +:::note Set the Initial Owner + +Before you can deploy this contract, you will need to set the `Initial Owner` address; this can be your own ShimmerEVM address. + +!["Set the initial owner" img.png](/img/evm/how-tos/ERC721/set-initial-owner.png) + +::: + + + +### Mint Your Custom NFTs + +So far, you have [created](#create-the-smart-contract) and deployed the contract. But, you probably want to mint some NFTs. +To do, you should: + +1. Open the contract (listed under `Deployed Contracts`). +2. Insert your target ShimmerEVM in beside the `safeMint` button and then click the button. + + ![Safe mint](/img/evm/how-tos/ERC721/safe-mint.png) +3. Confirm the transaction on Metamask. + + ![Confirm in metamask](/img/evm/how-tos/ERC721/confirm-in-metamask.png) + +If you visit your address in the [ShimmerEVM Explorer](https://explorer.evm.testnet.shimmer.network/) or [ShimmerEVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/) +you should see your NFTs listed under `Tokens`. + diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/allowance/allow.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/allowance/allow.md new file mode 100644 index 00000000000..edf7027f439 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/allowance/allow.md @@ -0,0 +1,64 @@ +--- +description: How to allow native assets and base token +image: /img/logo/WASP_logo_dark.png +tags: + - allow + - allowance + - EVM + - magic + - solidity +--- + +# Allow + +The allowance concept is well known from the EVM contracts like ERC20. +In ISC, we have a similar concept for our native assets. You might want to use this, for example, to [send native assets to L1](../send-assets-to-l1.mdx) (which includes sending tokens to other L1 chain accounts). + +## Example Code + +### 1. Create the `allow` Function + +Create a function which allows an address or contract to access a specific ID of your account: + +```solidity +function allow(address _address, bytes32 _allowanceNFTID) public { +``` + +### 2. Create the `ISCAssets` object + +Create an `ISCAssets` object to pass as allowance: + +```solidity +NFTID[] memory nftIDs = new NFTID[](1); +nftIDs[0] = NFTID.wrap(_allowanceNFTID); +ISCAssets memory assets; +assets.nfts = nftIDs; +``` + +### 3. Use the Assets as Allowance + +With that asset, you can call `allow` to allow address to take our NFT: + +```solidity +ISC.sandbox.allow(_address, assets); +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract Allowance { + function allow(address _address, bytes32 _allowanceNFTID) public { + NFTID[] memory nftIDs = new NFTID[](1); + nftIDs[0] = NFTID.wrap(_allowanceNFTID); + ISCAssets memory assets; + assets.nfts = nftIDs; + ISC.sandbox.allow(_address, assets); + } +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/allowance/get-allowance.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/allowance/get-allowance.md new file mode 100644 index 00000000000..353df44011c --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/allowance/get-allowance.md @@ -0,0 +1,79 @@ +--- +description: How to get the allowance of native assets and base token +image: /img/logo/WASP_logo_dark.png +tags: + - allowance + - EVM + - magic + - solidity +--- + +# Get Allowance + +## Example Code + +There are multiple ways to check for an allowance. + +### `getAllowanceFrom()` + +`getAllowanceFrom()` fetches the funds currently allowed by the given address to the caller: + +```soliditiy +function getAllowanceFrom(address _address) public { + ISCAssets assets = ISC.sandbox.getAllowanceFrom(_address); + emit AllowanceFrom(assets) +} +``` + +### `getAllowanceTo()` + +`getAllowanceTo()` fetches the funds currently allowed by the caller to the given address: + +```soliditiy +function getAllowanceTo(address _target) public { + ISCAssets assets = ISC.sandbox.getAllowanceTo(_target); + emit AllowanceTo(assets) +} +``` + +### `getAllowance()` + +`getAllowance()` gets the funds currently allowed between the given addresses: + +```soliditiy +function getAllowance(address _from, address _to) public { + ISCAssets assets = ISC.sandbox.getAllowance(_from, _to); + emit Allowance(assets) +} +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract allowance { + event AllowanceFrom(ISCAssets assets) + event AllowanceTo(ISCAssets assets) + event Allowance(ISCAssets assets) + + function getAllowanceFrom(address _address) public { + ISCAssets assets = ISC.sandbox.getAllowanceFrom(_address); + emit AllowanceFrom(assets) + } + + function getAllowanceTo(address _target) public { + ISCAssets assets = ISC.sandbox.getAllowanceTo(_target); + emit AllowanceTo(assets) + } + + function getAllowance(address _from, address _to) public { + ISCAssets assets = ISC.sandbox.getAllowance(_from, _to); + emit Allowance(assets) + } +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/allowance/take-allowance.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/allowance/take-allowance.md new file mode 100644 index 00000000000..b41689fb898 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/allowance/take-allowance.md @@ -0,0 +1,56 @@ +--- +description: How to take the allowance of native assets and base token +image: /img/logo/WASP_logo_dark.png +tags: + - allowance + - EVM + - magic + - solidity +--- + +# Take allowed Funds + +After having [allowed](./allow.md) native assets, you can take the ones you need. + +## Example Code + +The following example will take the NFT which was allowed in the [allow how-to guide](./allow.md). + +### Create the `ISCAssets` + +First, you need to recreate the `ISCAssets` with the NFTID. + +```solidity +NFTID[] memory nftIDs = new NFTID[](1); +nftIDs[0] = NFTID.wrap(_allowanceNFTID); +ISCAssets memory assets; +assets.nfts = nftIDs; +``` + +### Call `takeAllowedFunds()` + +After that, you can call `takeAllowedFunds()` to take the allowance of the specified address/contract + +```solidity +ISC.sandbox.takeAllowedFunds(_address, NFTID); +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract allowance { + function takeAllowedFunds(address _address, bytes32 NFTID) { + NFTID[] memory nftIDs = new NFTID[](1); + nftIDs[0] = NFTID.wrap(_allowanceNFTID); + ISCAssets memory assets; + assets.nfts = nftIDs; + ISC.sandbox.takeAllowedFunds(_address, NFTID); + } +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/get-balance.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/get-balance.md new file mode 100644 index 00000000000..aa25f559ac0 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/get-balance.md @@ -0,0 +1,74 @@ +--- +description: How to get the balance of L1 assets on L2 +image: /img/logo/WASP_logo_dark.png +tags: + - native assets + - balance + - EVM + - how-to +--- + +# Get Balance + +Once you have your L1 assets on L2, you might want to check their balance. This guide explains how to do so by calling the three functions `getL2BalanceBaseTokens`, `getL2BalanceNativeTokens`and `getL2NFTAmount` for the corresponding token types. + + +## Example Code + +1. Get the [AgentID](../../../explanations/how-accounts-work.md) from the sender by calling `ISC.sandbox.getSenderAccount()`. + +```solidity +ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); +``` + +2. To get the base token balance, you can call `getL2BalanceBaseTokens` using the `agentID`. + +```solidity +uint64 baseBalance = ISC.accounts.getL2BalanceBaseTokens(agentID); +``` + +3. To get the native token balance of a specific `NativeTokenID`, use `ISC.accounts.getL2BalanceNativeTokens` with the `id` and `agentID`. + +```solidity +NativeTokenID memory id = NativeTokenID({ data: nativeTokenID}); +uint256 nativeTokens = ISC.accounts.getL2BalanceNativeTokens(id, agentID); +``` + +4. To get the number of NFTs, use `ISC.accounts.getL2NFTAmount` with the `agentID`. + +```solidity +uint256 nfts = ISC.accounts.getL2NFTAmount(agentID); +``` + +### Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract GetBalance { + event GotAgentID(bytes agentID); + event GotBaseBalance(uint64 baseBalance); + event GotNativeTokenBalance(uint256 nativeTokenBalance); + event GotNFTIDs(uint256 nftBalance); + + function getBalance(bytes memory nativeTokenID) public { + ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); + emit GotAgentID(agentID.data); + + uint64 baseBalance = ISC.accounts.getL2BalanceBaseTokens(agentID); + emit GotBaseBalance(baseBalance); + + NativeTokenID memory id = NativeTokenID({ data: nativeTokenID}); + uint256 nativeTokens = ISC.accounts.getL2BalanceNativeTokens(id, agentID); + emit GotNativeTokenBalance(nativeTokens); + + uint256 nfts = ISC.accounts.getL2NFTAmount(agentID); + emit GotNativeTokenBalance(nfts); + } +} +``` + diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx new file mode 100644 index 00000000000..4fb8baa24da --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx @@ -0,0 +1,70 @@ +--- +description: The ISC Magic Contract allows EVM contracts to access ISC functionality. +image: /img/logo/WASP_logo_dark.png +tags: + - configure + - using + - EVM + - magic + - Ethereum + - Solidity +--- + +import AboutAccounts from '../../../_admonitions/_about-accounts.md'; + +# Send Assets and Tokens to L1 + + + +:::info + +ShimmerEVM has 18 decimal places, while Shimmer has 6. This means that any decimals beyond the 6th will be ignored by Shimmer, even though you can see them on ShimmerEVM. Please keep this in mind while sending your tokens to L1. + +::: + +This guide will show you how to use the ISC sandbox interface to send assets from L2 to L1. This includes base tokens, native tokens, and NFTs. Before you can send these assets, you need to know how you get them on L2 and how you allow a contract to use them. + +Note that assets on L1 require a storage deposit; therefore, the number of base tokens sent to L1 should cover at least the storage deposit required to hold the assets on L1. + +## Explanation + +First, you will find out what assets this contract is allowed to take from the caller by calling the `ISC.sandbox.getAllowanceFrom()` function. + +```solidity +ISCAssets memory allowance = ISC.sandbox.getAllowanceFrom(msg.sender); +``` + +Then you take the allowance, which will transfer the assets from the caller to the contract. + +```solidity +ISC.sandbox.takeAllowedFunds(msg.sender, allowance); +``` + +Finally, you can send the assets to the specified L1 address. This will create an output to hold said assets. You can use additional options to add the [timelock](/learn/protocols/stardust/core-concepts/output-unlock-conditions/#timelock) and [expiration](/learn/protocols/stardust/core-concepts/output-unlock-conditions/#expiration) unlock conditions to the output. + +```solidity +ISCSendMetadata memory metadata; +ISCSendOptions memory options; +ISC.sandbox.send(to, allowance, false, metadata, options); +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract L1Assets { + function withdraw(L1Address memory to) public { + ISCAssets memory allowance = ISC.sandbox.getAllowanceFrom(msg.sender); + ISC.sandbox.takeAllowedFunds(msg.sender, allowance); + + ISCSendMetadata memory metadata; + ISCSendOptions memory options; + ISC.sandbox.send(to, allowance, false, metadata, options); + } +} +``` \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/call-view.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/call-view.md new file mode 100644 index 00000000000..d66fe7c9726 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/call-view.md @@ -0,0 +1,96 @@ +--- +description: With call and callView you can interact with any core contract +image: /img/logo/WASP_logo_dark.png +tags: + - magic contract + - core + - EVM + - Ethereum + - Solidity + - ISC +--- + +# Interact with any Core contract + +## About `call` and `callView` + +The magic contract provides you with a solidity interface to the core contracts. Some functions like [`getL2BalanceBaseTokens`](../../reference/magic-contract/ISCAccounts.md#getl2balancebasetokens) are wrapped in the magic contract directly, others you need to call yourself. You can do that with the [`call`](../../reference/magic-contract/ISCSandbox.md#call) and [`callView`](../../reference/magic-contract/ISCSandbox.md#callview) functions. + +:::info WASM + +You can also use `call` and `callView` to interact with WASM contracts. + +::: + +## Example Code + +1. Get the [`AgentID`](../../explanations/how-accounts-work.md) from the sender by calling ISC.sandbox.getSenderAccount(). + +```solidity +ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); +``` + +2. Initialize the parameters for the call by creating a new [`ISCDict`](../../reference/magic-contract/ISCTypes.md#iscdict). As you can see in the docs, [`getl2balancenativetokens`](../../reference/magic-contract/ISCAccounts.md#getl2balancenativetokens) takes two parameters.: the Agent ID and the native token ID. So, you have to create a dictionary with two key-value pairs. The key of the first pair (Agent ID) has to be `a` and the key for the second pair (native token ID) `N`. + +```solidity +ISCDict memory params = ISCDict(new ISCDictItem[](2)); +params.items[0] = ISCDictItem("a", agentID.data); +params.items[1] = ISCDictItem("N", nativeTokenID); +``` + +3. Now, you can use [`callView`](../../reference/magic-contract/ISCSandbox.md#callview) to call our contract. The first parameter is the core contract `hname`, which we can get with the helper utility [`hn`](../../reference/magic-contract/ISCUtil.md#hn), and the second parameter is the function we want to call. The last parameter is the dictionary with all function parameters. + +```solidity +ISCDict memory result = ISC.sandbox.callView( + ISC.util.hn("accounts"), + ISC.util.hn("balanceNativeToken"), + params +); +``` + +4. Next, you can either return or emit the result. + +```solidity +emit NativeTokenBalance(bytesToUint(result.items[0].value)); +``` + +:::info Return Dictionary + +Keep in mind that the call and callView functions will always return a dictionary. The values of this dictionary are always of type byte, so you need to take care of converting it yourself. + +::: + +### Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract NativeTokenBalance { + event NativeTokenBalance(uint balance); + + function getNativeTokenBalance(bytes memory nativeTokenID) public { + ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); + + ISCDict memory params = ISCDict(new ISCDictItem[](2)); + params.items[0] = ISCDictItem("a", agentID.data); + params.items[1] = ISCDictItem("N", nativeTokenID); + + ISCDict memory result = ISC.sandbox.callView( + ISC.util.hn("accounts"), + ISC.util.hn("balanceNativeToken"), + params + ); + + emit NativeTokenBalance(bytesToUint(result.items[0].value)); + } + + function bytesToUint(bytes memory b) internal pure virtual returns (uint256) { + require(b.length <= 32, "Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/get-randomness-on-l2.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/get-randomness-on-l2.md new file mode 100644 index 00000000000..3bf4b3b35e1 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/get-randomness-on-l2.md @@ -0,0 +1,127 @@ +--- +description: You can use the ISC Magic Contract in EVM contracts to access ISC functionality, such as randomness. +image: /img/logo/WASP_logo_dark.png +tags: + - magic contract + - randomness + - EVM + - Ethereum + - Solidity + - ISC +--- + +# Get Randomness on L2 + +ISC introduces a feature not found on many other smart contract protocols: randomness. + +In the ISC protocol, for each state update, each validator proposes a batch of smart contract requests that they would like to process next. They commit to their proposals with a signature, after which a common subset of requests is found, and a combined signature is produced. + +This combined signature is unpredictable, and not only serves as protection against MEV by pseudo-randomly ordering requests, but also provides a source of verifiable entropy for randomness on L2. + +This guide will show you how you can use this entropy to generate random values in your contracts. + +:::info A note about entropy + +While entropy is random for each smart contract request, entropy is constant within a request. This means multiple calls to get entropy within the same request will return the same value. + +::: + +## Explanation + +When you want to generate multiple random values within a single request, you need to take into account that entropy is constant within a request. In this contract we use an increasing nonce in addition to the entropy, to make sure we are generating unique values: + +```solidity +uint256 private _nonce; + +function getNonce() internal returns (bytes32) { + return bytes32(_nonce++); +} +``` + +### Generating Integers + +To then generate a random integer, you can take the entropy and a unique nonce and hash them together: + +```solidity +bytes32 entropy = ISC.sandbox.getEntropy(); +bytes32 nonce = getNonce(); +bytes32 digest = keccak256(bytes.concat(entropy, nonce)); +``` + +And then cast the digest to an integer: + +```solidity +uint256 value = uint256(digest); +``` + +### Generating bytes + +Similarly to generating a random integer, you can generate any sequence of random bytes by taking the entropy and a unique nonce and hash them together: + +```solidity +bytes32 entropy = ISC.sandbox.getEntropy(); +bytes32 nonce = getNonce(); +bytes32 digest = keccak256(bytes.concat(entropy, nonce)); +``` + +And then repeatidly hash the digest and copy it in a sequence of bytes until you reach the required length. + +```solidity +bytes memory value = new bytes(length); +for (uint i = 0; i < length; i += 32) { + digest = keccak256(bytes.concat(digest)); + for (uint j = 0; j < 32 && i + j < length; j++) { + value[i + j] = digest[j]; + } +} +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract Random { + event Int(uint256); + event Bytes(bytes); + + uint256 private _nonce; + + function getNonce() internal returns (bytes32) { + return bytes32(_nonce++); + } + + function getInt() public returns (uint256) { + bytes32 entropy = ISC.sandbox.getEntropy(); + bytes32 nonce = getNonce(); + bytes32 digest = keccak256(bytes.concat(entropy, nonce)); + + uint256 value = uint256(digest); + + emit Int(value); + return value; + } + + function getBytes(uint length) public returns (bytes memory) { + bytes32 entropy = ISC.sandbox.getEntropy(); + bytes32 nonce = getNonce(); + bytes32 digest = keccak256(bytes.concat(entropy, nonce)); + + bytes memory value = new bytes(length); + for (uint i = 0; i < length; i += 32) { + digest = keccak256(bytes.concat(digest)); + for (uint j = 0; j < 32 && i + j < length; j++) { + value[i + j] = digest[j]; + } + } + + emit Bytes(value); + return value; + } +} + +``` \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/introduction.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/introduction.md new file mode 100644 index 00000000000..d8983b4e246 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/introduction.md @@ -0,0 +1,79 @@ +--- +description: The ISC Core Contracts allows VMs to access ISC functionality. +image: /img/logo/WASP_logo_dark.png +tags: + - configure + - using + - EVM + - magic + - Ethereum + - Solidity + - metamask + - JSON + - RPC +--- + +# The Core Contracts + +The [core contracs](../../explanations/core-contracts.md) are contracts deployed on every chain and are vital to interact with L1 and the chain itself. They can be called in Solidity through the [ISC Magic Contract](../../reference/magic-contract/introduction.md). + +## The ISC Magic Contract + +The Magic contract is an EVM contract deployed by default on every ISC chain, in the EVM genesis block, at +address `0x1074000000000000000000000000000000000000`. +The implementation of the Magic contract is baked-in in +the [`evm`](../../reference/core-contracts/evm.md) [core contract](../../reference/core-contracts/overview.md); +i.e. it is not a pure-Solidity contract. + +The Magic contract has several methods, which are categorized into specialized +interfaces: `ISCSandbox`, `ISCAccounts`, `ISCUtil` and so on. +You can access these interfaces from any Solidity contract by importing +the [ISC library](https://www.npmjs.com/package/@iota/iscmagic): + +```bash npm2yarn +npm install @iota/iscmagic +``` + +You can import it into your contracts like this: + +```solidity +import "@iota/iscmagic/ISC.sol"; +``` + +The Magic contract also provides proxy ERC20 contracts to manipulate ISC base +tokens and native tokens on L2. + +:::info Reference Docs + +If you need further info about magic contracts interfaces you can check out the [magic contract docs](../../reference/magic-contract/introduction.md). + +::: + +## Call a Function + +:::info Ease of use + +To make it easier for developers to use the core contracts, you should, in most cases, run the functions from the magic contract directly. For example, to get the native token balance, you could [call the `balanceNativeToken()`](./call-view.md) directly with `callView`, or use [`getl2balancenativetokens`](./basics/get-balance.md) of the magic contract, or (the suggested way) register your native token as [`ERC20`](../../reference/magic-contract/ERC20NativeTokens.md) and call the standard [`balanceof`](../../reference/magic-contract/ERC20NativeTokens.md#balanceof) function. What you use also depends on what you optimize for. For example, to save gas, it could be interesting for you to call core contracts from your favorite web3 library directly and compute other things off-chain. + +::: + +In the example below, `ISC.sandbox.getEntropy()` calls the +[`getEntropy`](https://github.com/iotaledger/wasp/blob/develop/packages/vm/core/evm/iscmagic/ISCSandbox.sol#L20) +method of the `ISCSandbox` interface, which, in turn, +calls [ISC Sandbox's](../../explanations/sandbox.md) `GetEntropy`. + +```solidity +pragma solidity >=0.8.5; + +import "@iota/iscmagic/ISC.sol"; + +contract MyEVMContract { + event EntropyEvent(bytes32 entropy); + + // this will emit a "random" value taken from the ISC entropy value + function emitEntropy() public { + bytes32 e = ISC.sandbox.getEntropy(); + emit EntropyEvent(e); + } +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/nft/introduction.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/nft/introduction.md new file mode 100644 index 00000000000..506f0dfef13 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/nft/introduction.md @@ -0,0 +1,17 @@ +--- +description: How to handle native NFTs on L2 and use them as ERC721 +image: /img/logo/WASP_logo_dark.png +tags: + - native + - NFT + - EVM + - how-to +--- +import DocCardList from '@theme/DocCardList'; + +# Native NFT and ERC721 + +The IOTA L1 can create NFTs, also called native NFTs. To use these NFTs on L2, you have +an ERC20 contract called `ERC721NFTs`, which contains all L1 NFTs owned by the chain. The following guides will show you how to [mint your own L1 NFT from L2](./mint-nft.md) and [use](./use-as-erc721.md) it with the `ERC721NFTs` contract. + + \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/nft/mint-nft.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/nft/mint-nft.md new file mode 100644 index 00000000000..d889d7972a2 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/nft/mint-nft.md @@ -0,0 +1,152 @@ +--- +description: How to mint L1 NFT +image: /img/logo/WASP_logo_dark.png +tags: + - NFT + - EVM + - how-to +--- +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; + +# Mint an NFT +## About NFTs + +The Stardust update allows you to create your own NFTs. You can also use [IRC27](/tips/tips/TIP-0027) for NFTs. This guide will show you how to create an IRC27 L1 NFT using a L2 smart contract. + +## Example Code + + + +2. Get the senders AgentID: + +```solidity +ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); +``` + +3. Create an `IRC27Metadata` struct with all the needed data: + +```solidity +IRC27NFTMetadata memory metadata = IRC27NFTMetadata({ + standard: "IRC27", + version: "v1.0", + mimeType: _mimeType, + uri: _uri, + name: _name +}); +``` + +4. Create all the data for the core contract call. To do so, you should create a new `ISCDict` with 2 parameters like specified in the reference docs for [`mintNFT`](../../../reference/core-contracts/accounts.md#mintnfti-immutabledata-a-agentid-c-collectionid-w-withdrawonmint) +* `I` is the immutable metadata we fill with the IRC27 metadata and +* `a` is the AgendID of the owner of the NFT + +```solidity +ISCDict memory params = ISCDict(new ISCDictItem[](2)); +params.items[0] = ISCDictItem("I", bytes(IRC27NFTMetadataToString(metadata))); +params.items[1] = ISCDictItem("a", agentID.data); +``` + +:::info IRC27NFTMetadataToString + +The full example below calls the `IRC27NFTMetadataToString` function, which simply converts the IRC27Metadata struct into a string. + +::: + +5. Call the magic contract `call` function with all the parameters. You should specify the core contract you want to call, which in this case is the [`account`](../../../reference/core-contracts/accounts.md) contract, and the function for [minting an NFT](../../../reference/core-contracts/accounts.md#mintnfti-immutabledata-a-agentid-c-collectionid-w-withdrawonmint) + +```solidity +ISCDict memory ret = ISC.sandbox.call( + ISC.util.hn("accounts"), + ISC.util.hn("mintNFT"), + params, + allowance +); +``` + +6. The call return value will contain a `mintID` which we can use in, for example, another contract function to get the actual L1 NFT ID once it is created using the [`accounts.NFTIDbyMintID`](../../../reference/core-contracts/accounts.md#nftidbymintidd-mintid) function + +```solidity +function getNFTIDFromMintID(bytes memory mintID) public view returns (bytes memory) { + ISCDict memory params = ISCDict(new ISCDictItem[](1)); + params.items[0] = ISCDictItem("D", mintID); + + ISCDict memory ret = ISC.sandbox.callView( + ISC.util.hn("accounts"), + ISC.util.hn("NFTIDbyMintID"), + params + ); + return ret.items[0].value; +} +``` + +### Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract NFTContract { + event MintedNFT(bytes mintID); + + function mintNFT(string memory _name, string memory _mimeType, string memory _uri, uint64 _storageDeposit) public payable { + require(msg.value == _storageDeposit*(10**12), "Please send exact funds to pay for storage deposit"); + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + + ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); + + IRC27NFTMetadata memory metadata = IRC27NFTMetadata({ + standard: "IRC27", + version: "v1.0", + mimeType: _mimeType, + uri: _uri, + name: _name + }); + + ISCDict memory params = ISCDict(new ISCDictItem[](2)); + params.items[0] = ISCDictItem("I", bytes(IRC27NFTMetadataToString(metadata))); + params.items[1] = ISCDictItem("a", agentID.data); + + ISCDict memory ret = ISC.sandbox.call( + ISC.util.hn("accounts"), + ISC.util.hn("mintNFT"), + params, + allowance + ); + emit MintedNFT(ret.items[0].value); + } + + function getNFTIDFromMintID(bytes memory mintID) public view returns (bytes memory) { + ISCDict memory params = ISCDict(new ISCDictItem[](1)); + params.items[0] = ISCDictItem("D", mintID); + + ISCDict memory ret = ISC.sandbox.callView( + ISC.util.hn("accounts"), + ISC.util.hn("NFTIDbyMintID"), + params + ); + return ret.items[0].value; + } + + function IRC27NFTMetadataToString(IRC27NFTMetadata memory metadata) + public + pure + returns (string memory) + { + return string.concat( + '{"standard": "', + metadata.standard, + '", "version": "', + metadata.version, + '", "type": "', + metadata.mimeType, + '", "uri": "', + metadata.uri, + '", "name": "', + metadata.name, + '"}'); + } +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/nft/use-as-erc721.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/nft/use-as-erc721.md new file mode 100644 index 00000000000..2263adca84c --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/nft/use-as-erc721.md @@ -0,0 +1,33 @@ +--- +description: How to use a native NFT like an ERC721 NFT +image: /img/logo/WASP_logo_dark.png +tags: + - NFT + - EVM + - how-to +--- + +# Use as ERC721 +## About the `ERC721NFTs` contract + +The `ERC721NFTs` contract is a hardcoded contract at address `0x1074030000000000000000000000000000000000`. Every L1 NFT owned by the chain can be accessed through it. In this example, we will show you how to use it by using `transferFrom`. + +## Example Code + +1. ERC721 uses the `tokenID` for almost all interactions with it. So first, you should convert the `NFTID` to a `tokenID`: + +```solidity +uint256 tokenID = uint256(NFTID.unwrap(nftID)); +``` + +:::info Token ID to NFT ID + +You can use the ISCTypes.asNFTID() function to convert a Token ID to an NFT ID, by either using it on a token ID `tokenID.asNFTID();` or passing it to function `ISCTypes.asNFTID(tokenID)`. + +::: + +2. Transfer the token with ID `tokenID`, by using the `ERC20NFTs` contract, which is exposed in the library as `ISC.nfts`, and calling the standard `transferFrom` function: + +```solidity +ISC.nfts.transferFrom(msg.sender, _destination, tokenID); +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/create-foundry.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/create-foundry.md new file mode 100644 index 00000000000..17ba120d40c --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/create-foundry.md @@ -0,0 +1,71 @@ +--- +description: How to create a L1 foundry +image: /img/logo/WASP_logo_dark.png +tags: + - foundry + - EVM + - how-to +--- +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; +import ObsoleteTokenCreation from '../../../_partials/how-tos/token/_obsolete_token_creation.md'; + +# Create a Foundry + + + +## About Foundries + +The Stardust update allows you to create your own native tokens. Native tokens are minted by a [Foundry](/tips/tips/TIP-0018/#foundry-output). +The Foundry allows you to specify your native token's maximum supply **once** and change the circulating supply. +This guide will show you how to create an L1 foundry using a L2 smart contract. + +## Example Code + + + +### 2. Define the Token Scheme + +Define the `NativeTokenScheme` by specifying its `mintedTokens`, `meltedTokens` and `maximumSupply`: + +```solidity +NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: _mintedTokens, + meltedTokens: _meltedTokens, + maximumSupply: _maximumSupply +}); +``` + +### 3. Create the Foundry + +Create the foundry by calling the `ISC.accounts.foundryCreateNew(nativeTokenScheme, allowance)` function: + +```solidity +uint32 foundrySN = ISC.accounts.foundryCreateNew(nativeTokenScheme, allowance); +``` + +### Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract CreateFoundry { + event CreatedFoundry(uint32 foundrySN); + + function createFoundry(uint _mintedTokens, uint _meltedTokens, uint _maximumSupply, uint64 _storageDeposit) public payable { + require(msg.value == _storageDeposit*(10**12), "Please send exact funds to pay for storage deposit"); + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: _mintedTokens, + meltedTokens: _meltedTokens, + maximumSupply: _maximumSupply + }); + uint32 foundrySN = ISC.accounts.foundryCreateNew(nativeTokenScheme, allowance); + emit CreatedFoundry(foundrySN); + } +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/create-native-token.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/create-native-token.md new file mode 100644 index 00000000000..06baa4615d1 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/create-native-token.md @@ -0,0 +1,91 @@ +--- +description: How to Create a Native Token Foundary. +image: /img/logo/WASP_logo_dark.png +tags: + - foundry + - EVM + - how-to + - native tokens + - mint + - register +--- + +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; + +# Create a Native Token + +This guide will show you how you can efficiently mint new tokens and register them for use as ERC20 tokens with the [`createNativeTokenFoundry`](../../../reference/magic-contract/ISCAccounts.md#createnativetokenfoundry) function in one seamless operation. It will create a foundry on L1 and register it as an ERC20 on L2. This method ensures that only the foundry owner can mint tokens, maintaining security and control over the token creation process. + +## About Foundries + +The Stardust update allows you to create your own native tokens. Native tokens are minted by a [Foundry](/tips/tips/TIP-0018/#foundry-output). +The Foundry lets you specify your native token's maximum supply **once** and change the circulating supply. + +## Example Code + + + +### 2. Define the Token Scheme + +Define the [`NativeTokenScheme`](../../../reference/magic-contract/ISCTypes.md#nativetokenscheme) by specifying the `maximumSupply`. + +```solidity +NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: 0, + meltedTokens: 0, + maximumSupply: _maximumSupply +}); +``` + +### 3. Mint and Register Native Token + +Minting native tokens and registering them as ERC20 tokens using [`createNativeTokenFoundry`](../../../reference/magic-contract/ISCAccounts.md#createnativetokenfoundry) method + +```solidity +uint32 foundrySN = ISC.accounts.createNativeTokenFoundry( + _tokenName, + _tokenSymbol, + _tokenDecimals, + nativeTokenScheme, + allowance +); +``` + +## Full Example Code + +```solidity +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract MyToken { + event MintedToken(uint32 foundrySN); + + constructor( + string memory _tokenName, + string memory _tokenSymbol, + uint8 _tokenDecimals, + uint256 _maximumSupply, + uint64 _storageDeposit + ) payable { + require(msg.value == _storageDeposit * (10**12), "Please send exact funds to pay for storage deposit"); + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + + NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: 0, + meltedTokens: 0, + maximumSupply: _maximumSupply + }); + + uint32 foundrySN = ISC.accounts.createNativeTokenFoundry( + _tokenName, + _tokenSymbol, + _tokenDecimals, + nativeTokenScheme, + allowance + ); + emit MintedToken(foundrySN); + } +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/erc20-native-token.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/erc20-native-token.md new file mode 100644 index 00000000000..eef11254681 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/erc20-native-token.md @@ -0,0 +1,45 @@ +--- +description: How to use the custom functionality of ERC20NativeToken +image: /img/logo/WASP_logo_dark.png +tags: + - native token + - erc20 + - EVM + - how-to +--- + +# Custom ERC20 Functions + +Once you [registered your native token as ERC20](./erc20-native-token.md) you can use it like any other ERC20 token, with functions like +`transfer`, `balanceOf`, etc. But, as the ERC20 token maps the native token on L2, there are some additional ISC features +you can take advantage of. + +## Example Code + +### Get Your `nativeTokenID` + +You can use the `erc20NativeTokensAddress` function and the Foundry serial number to get the contract address: + +```solidity +ERC20NativeTokens token = ERC20NativeTokens( + ISC.sandbox.erc20NativeTokensAddress(_foundrySN) +); +``` + +* `nativeTokenID` will give you the native token ID of the ERC20 token: + +```solidity +NativeTokenID memory id =token.nativeTokenID(); +``` + +### Full Example Code + +```solidity +function nativeTokenID(uint32 _foundrySN) public view returns (bytes memory) { + ERC20NativeTokens token = ERC20NativeTokens( + ISC.sandbox.erc20NativeTokensAddress(_foundrySN) + ); + NativeTokenID memory id =token.nativeTokenID(); + return id.data; +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/introduction.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/introduction.md new file mode 100644 index 00000000000..83fb4021e47 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/introduction.md @@ -0,0 +1,18 @@ +--- +description: How to handle native tokens on L2 and use them as ERC20 +image: /img/logo/WASP_logo_dark.png +tags: + - native token + - EVM + - how-to +--- +import DocCardList from '@theme/DocCardList'; + +# Native Token and ERC20NativeToken + +The IOTA L1 has functionality to create L1 tokens, also called native tokens. To use these native tokens on L2, you have +a ERC20 contract called `ERC20NativeToken`. The following guides will show you how to [create a foundry](create-foundry.md) +that can [mint your own L1 token from L2](mint-token.md), and [register](register-token.md) it as `ERC20NativeToken`, +so it can be used like any other ERC20 token with some additional features. + + \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/mint-token.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/mint-token.md new file mode 100644 index 00000000000..bd79533d844 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/mint-token.md @@ -0,0 +1,41 @@ +--- +description: How to mint native token on an L1 foundry. +image: /img/logo/WASP_logo_dark.png +tags: + - foundry + - EVM + - how-to + - native tokens + - mint +--- +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; + +# Mint Native Tokens + +To mint tokens from a [foundry](/tips/tips/TIP-0018/#foundry-output), you first need to be aware that only the foundry owner can mint token, so you should execute the `ISC.accounts.mintNativeTokens` function in the same contract where you also [created the native token](./create-native-token.md). + +## Example Code + + + +### 2. Mint the Native Token + +Mint the native token specifying the foundry serial number, the amount to mint and the allowance. + +```solidity +ISC.accounts.mintNativeTokens(_foundrySN, _amount, allowance); +``` + +## Full Example Code + +```solidity +event MintedNativeTokens(uint32 foundrySN, uint amount); + +function mintNativeTokens(uint32 _foundrySN, uint _amount, uint64 _storageDeposit) public payable { + require(msg.value == _storageDeposit*(10**12), "Please send exact funds to pay for storage deposit"); + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + ISC.accounts.mintNativeTokens(_foundrySN, _amount, allowance); + emit MintedNativeTokens(_foundrySN, _amount); +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/register-token.md b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/register-token.md new file mode 100644 index 00000000000..990ae5e69b3 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/core-contracts/token/register-token.md @@ -0,0 +1,56 @@ +--- +description: How to register a native token as ERC20 +image: /img/logo/WASP_logo_dark.png +tags: + - ERC20 + - EVM + - how-to +--- +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; +import ObsoleteTokenCreation from '../../../_partials/how-tos/token/_obsolete_token_creation.md'; + +# Register Tokens + + + +To properly use your native tokens, you should register them as ERC20 using the `registerERC20NativeToken` function from the ISC magic contract. + +## Example Code + + + + +### 2. Register the Native Tokens + +Register the native tokens specifying: +* the foundry serial number +* a name +* a symbol +* it's decimals +* the allowance. +```solidity +ISC.sandbox.registerERC20NativeToken(_foundrySN, _name, _symbol, _decimals, allowance); +``` + +### 3. Get the Contract's Address + +Get the ERC20 contract address with `erc20NativeTokensAddress`: + +```solidity +address erc20address = ISC.sandbox.erc20NativeTokensAddress(_foundrySN); +``` + +### Full Example Code + +```solidity +event ERC20Address(address erc20address); + +function registerERC20NativeToken(uint32 _foundrySN, string calldata _name, string calldata _symbol, uint8 _decimals, uint64 _storageDeposit) public payable { +require(msg.value == _storageDeposit*(10**12), "Please send exact funds to pay for storage deposit"); +ISCAssets memory allowance; +allowance.baseTokens = _storageDeposit; +ISC.sandbox.registerERC20NativeToken(_foundrySN, _name, _symbol, _decimals, allowance); +address erc20address = ISC.sandbox.erc20NativeTokensAddress(_foundrySN); +emit ERC20Address(erc20address); +} +``` diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/create-a-basic-contract.md b/docs/build/isc/v1.3-alpha/docs/how-tos/create-a-basic-contract.md new file mode 100644 index 00000000000..d060b3732ff --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/create-a-basic-contract.md @@ -0,0 +1,53 @@ +--- +description: Basic smart contract example. +image: /img/logo/WASP_logo_dark.png +tags: + - smart contracts + - how to + - basic contract +--- +import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; + +# Basic Smart Contract Example + +[Solidity](https://docs.soliditylang.org/en/v0.8.16/) smart contracts on IOTA Smart Contracts are compatible with +Solidity smart contracts on any other network. Most smart contracts will work directly without any modification. To get +a rough indication of what a simple Solidity smart contract looks like, see the example below: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.6; + +contract Counter { + uint private count; + + constructor() { + count = 0; + } + + function increment() public { + count += 1; + } + + function decrement() public { + require(count > 0, "Count is already zero"); + count -= 1; + } + + function getCount() public view returns (uint) { + return count; + } +} + +``` + +This contract simply updates a `count` variable. It has +three [entry points](../explanations/smart-contract-anatomy.md#entry-points): + +* `increment` and `decrement`: Two full entry points that can alter + the [state](../explanations/smart-contract-anatomy.md#state), i.e. the `count variable`. +* `getCount`: A view only entry point, which simply renders the current `count` state. + +For more information, please visit the [official Solidity documentation](https://docs.soliditylang.org/). + + \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/deploy-a-smart-contract.mdx b/docs/build/isc/v1.3-alpha/docs/how-tos/deploy-a-smart-contract.mdx new file mode 100644 index 00000000000..9fbf20161e0 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/deploy-a-smart-contract.mdx @@ -0,0 +1,184 @@ +--- +tags: +- Smart Contract Deployment +- Shimmer EVM +- Remix IDE +- Hardhat +- Shimmer EVM Testnet +image: /img/logo/WASP_logo_dark.png +description: 'Learn how to deploy smart contracts to Shimmer EVM and Shimmer EVM Testnet using popular tools like Remix and Hardhat.' +--- +import {AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; +import HardhatConfig from '../_partials/_hardhat_config.md'; +import MetamaskButtons from '../../../../_partials/_metamask_buttons.mdx'; +import { Networks } from '@theme/constant'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Deploy a Smart Contract + +You can deploy your smart contracts to any of your [EVM chains](/build/networks-endpoints/) using popular tools like [Remix](#remix) +and [Hardhat](#hardhat). + +:::tip Get a Basic Contract + +This guide will deploy the `Counter` contract you can find in +the [How to Create a Basic Solidity Contract Guide](create-a-basic-contract.md). + +::: + + + + +Deploying a Solidity smart contract using Remix is a straightforward process that doesn't require any installation or +setup of development environments on your machine. Remix is a powerful, browser-based IDE that allows you to write, +compile, and deploy smart contracts. + +### 1. Connect to Metamask + +Before you get started, make sure you have connected Metamask to your network of choice. + +:::tip Networks & Endpoints + +You can check the connection details in the [Networks & Endpoints section](/build/networks-endpoints/). + +::: + + + +### 2. Access Remix IDE + +Open your web browser and navigate to [Remix IDE](https://remix.ethereum.org/). + +### 3. Create Your Smart Contract + +1. In the `File Explorer` tab on the left, click the `Create New File` icon. +2. Name your file `Counter.sol`. +3. Copy the Solidity code for the [basic counter smart contract](create-a-basic-contract.md) and paste it into + the `Counter.sol` file you just created in Remix. + +### 4. Compile Your Smart Contract + +1. Navigate to the `Solidity Compiler` tab on the left sidebar. +2. Select the appropriate compiler version that matches the version specified in your contract (`^0.8.6` or similar). + You might need to enable "Auto compile" or click the "Compile" button manually. +3. If there are errors, Remix will display them, and you'll need to correct them before proceeding. + +### 5. Deploy Your Smart Contract + +1. Switch to the "Deploy & Run Transactions" tab on the left sidebar. +2. In the "Environment" dropdown, select and select `Injected Web3` from the `Environment` dropdown. + + ![Select Injected Provider from the Environment dropdown](/img/evm/remix-injected-provider-metamask.png) + +3. After selecting the environment, make sure the contract Counter is selected in the `Contract` dropdown. +4. Click the `Deploy` button. If you're using an Ethereum network, confirm the transaction in your Web3 wallet. + +### 6. Interact with Your Deployed Contract + +Once deployed, the contract instance will appear under the `Deployed Contracts` section. +Here, you can interact with your contract by calling its functions. For the Counter contract, you'll see buttons to call +its `increment`, `decrement`, and `getCount` functions directly from Remix. + + + + +The first thing you'll need to deploy a smart contract using [Hardhat](https://hardhat.org/) is to set up a Hardhat +project. Here's a step-by-step guide: + +### Requirements + +* [Node.js](https://nodejs.org/). +* [npm](https://www.npmjs.com/) or [yarn](https://yarnpkg.com/). + +### 1. Set Up Hardhat + +1. Open a new terminal window. +2. Create a new directory for your project, and navigate into it. For example: + ```bash + mkdir deploy-a-basic-contract && + cd deploy-a-basic-contract + ``` +3. Create a new node project by running: + ```bash + npm init -y + ``` +4. Install Hardhat by running: + ```bash + npm install --save-dev hardhat + ``` +5. Create a Hardhat Project by running the following command: + ```bash + npx hardhat + ``` + + Select "Create a basic sample project" when prompted and answer the setup questions (you can just press enter to + accept defaults). + +### 2. Add Your Contract + +1. Inside the `contracts` folder, create a new file called `Counter.sol` and paste the content of + the [Counter Basic Contract](create-a-basic-contract.md). + +### 3. Create a Deployment Script + +1. Navigate to the `scripts` folder. +2. Create a new file called `deploy.js` with the following code: + + ```javascript + async function main() { + const Counter = await ethers.getContractFactory("Counter"); + const counter = await Counter.deploy(); + + await counter.deployed(); + + console.log("Counter deployed to:", counter.address); + } + + main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); + ``` + +### 4. Compile and Deploy Your Contract + +1. Add your preferred network parameters to the `hardhat.config.js`, for example: + + + +:::caution + +Currently, there is no validation service available for EVM/Solidity smart contracts on IOTA Smart Contracts, which is +often offered through block explorer APIs. + +::: + +2. Compile your contract by running the following command: + + ```bash + npx hardhat compile + ``` + +3. If you have no compilation errors, you can deploy your contract by running the following command: + + ```bash + npx hardhat run scripts/deploy.js --network shimmerevm-testnet + ``` + + **Expected output**: + + ```bash + Counter deployed to: 0x123456789ABCDEFGHIJK123456789ABCDEFGHIJK + ``` + ***** `0x123456789ABCDEFGHIJK123456789ABCDEFGHIJK` is the contract unlock address. + +4. You can verify your contract by visiting + the [ShimmerEVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/), + and searching for the address from the previous step. If you access the `Contract` tab, you should be able to see + your code and interact with your contract. + + + \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/introduction.md b/docs/build/isc/v1.3-alpha/docs/how-tos/introduction.md new file mode 100644 index 00000000000..cb6c63bbc87 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/introduction.md @@ -0,0 +1,29 @@ +--- +description: 'Explore the how-to guides for IOTA Smart Contracts, offering step-by-step instructions on various topics and functionalities.' +image: /img/logo/WASP_logo_dark.png +tags: + + - EVM + - Solidity + - smart contracts + - Ethereum + - explanation + - how-to guides + - instructions + - code examples +--- + +# About How-to Guides + +This section has several how-to guides that provide step-by-step instructions on various topics and functionalities. You +can use these guides to understand and implement specific tasks or features within your application. Whether you are a +beginner or an experienced developer, the how-to guides offer clear and concise explanations, making integrating IOTA smart contracts +functionality into your projects easier. + +To make the most of the how-to guides in this section, identify the specific topic or functionality you want to explore. +Whether you want to [get funds on L2](send-funds-from-L1-to-L2.mdx), [add ISC specific functionality](introduction.md), +or [send funds to L1](./core-contracts/basics/send-assets-to-l1.mdx), you can find dedicated guides that walk you through the process. + +With the how-to guides in the IOTA SDK, you can overcome implementation hurdles and gain a deeper understanding +of the IOTA ecosystem. These guides empower you with the knowledge and practical examples to seamlessly integrate IOTA +functionality into your projects. diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/send-funds-from-L1-to-L2.mdx b/docs/build/isc/v1.3-alpha/docs/how-tos/send-funds-from-L1-to-L2.mdx new file mode 100644 index 00000000000..1a9a469d7ea --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/send-funds-from-L1-to-L2.mdx @@ -0,0 +1,102 @@ +--- +description: How to send funds from L1 to L2. +image: /img/logo/WASP_logo_dark.png +tags: + - configure + - using + - EVM + - Ethereum + - Solidity + - deploy + - hardhat + - metamask + - JSON + - RPC + - how to +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import {AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; +import MetamaskButtons from '../../../../_partials/_metamask_buttons.mdx'; +import { Networks } from '@theme/constant'; + +# Send Funds From L1 to L2 + +There are multiple types of assets available on both IOTA L1 and L2, here we discuss a few of them, and how to get them +onto L2. + +:::tip Testnet + +If you want to fund your EVM Testnet account using the EVM Toolkit, please refer to our [Testnet Quickstart Guide](../getting-started/quick-start.mdx) + +::: + +## Fund an Ethereum Account on a IOTA Smart Contracts Chain + +To send EVM transactions, you need to have an Ethereum address that owns tokens on the ISC chain (L2). These tokens will +be used to cover gas fees. + + + + +You can use your [Firefly Wallet](https://firefly.iota.org/) to easily send L1 SMR to your L2 ShimmerEVM account. + +#### Requirements + +* [Shimmer Tokens](/get-started/introduction/shimmer/shimmer-token/) or [IOTA Tokens](/get-started/introduction/iota/iota-token/) +* [Firefly Wallet](https://firefly.iota.org/) +* [Metamask](https://metamask.io/) + +1. The first thing you will need to do is add the EVM to Metamask by hitting the following button. + + + +2. Once you have added the EVM to Metamask, you can get your address: + + ![Copy your Metamask address](/img/evm/how-tos/get-funds/copy-your-address.png) + +3. Next, you will need to open your [Firefly Wallet](https://firefly.iota.org/) and click on `Send Assets`. + + ![Click send assets](/img/evm/how-tos/get-funds/firefly/select-send-assets.png) + +4. Select the EVM chain you want to use in the network dropdown. + + ![Select the EVM network](/img/evm/how-tos/get-funds/firefly/select-shimmer-evm.png) + +5. Enter the amount of tokens you want to transfer, and the Metamask address from step 2, and click on `Next` + + ![Enter the amount of tokens and metamask address](/img/evm/how-tos/get-funds/firefly/enter-your-desired-amount-and-metamask-address.png) + +6. Review the transaction details and click on `Send`. + + ![Hit Send](/img/evm/how-tos/get-funds/firefly/hit-send.png) + + + + + +You can use your [Bloom Wallet](https://bloomwallet.io/) to easily send L1 base token to your L2 EVM account. + +1. First, you will need to open your [Bloom Wallet](https://firefly.iota.org/) and click on `Send`. + + ![Click send](/img/evm/how-tos/get-funds/bloom/select-send.png) + +2. Select an account with base tokens. + + ![Select an account with base tokens](/img/evm/how-tos/get-funds/bloom/select-the-smr-token.png) + +3. Bloom will automatically create an EVM address for you, so you can send funds to that address from the +EVM dropdown. Alternatively, you can input any other EVM address. + + ![Select you EVM Address](/img/evm/how-tos/get-funds/bloom/enter-the-recipient-address.png) + +4. Enter the amount of base tokens you want to transfer. + + ![Enter the amount of base tokens you want to transfer](/img/evm/how-tos/get-funds/bloom/enter-the-amount.png) + +5. Review the transaction details and click on `Confirm`. + + ![Hit Send](/img/evm/how-tos/get-funds/bloom/review-and-confirm-the-transaction.png) + + + \ No newline at end of file diff --git a/docs/build/isc/v1.3-alpha/docs/how-tos/test-smart-contracts.md b/docs/build/isc/v1.3-alpha/docs/how-tos/test-smart-contracts.md new file mode 100644 index 00000000000..7b032b6d9bf --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/how-tos/test-smart-contracts.md @@ -0,0 +1,108 @@ +--- +keywords: +- Smart Contract Testing +- Automated Testing +- Unit Tests +- Integration Tests +- Testing Frameworks +- ShimmerEVM Testnet +- Solidity Testing +description: Learn how to test smart contracts before deploying them on public networks to avoid vulnerabilities and ensure functionality aligns with requirements using unit, and integration testing, alongside frameworks and testing with the IOTA Sandbox and the ShimmerEVM Testnet. +--- + +# Testing Smart Contracts + +Once you have deployed a smart contract on a public network, altering it to fix an error can be hard, and it goes +against the principle of immutability, which can create trust issues with users. And, even if it were simple, you could +only fix an error or vulnerability after it is discovered. So, your contract and its users may be at risk if a third +party detects a vulnerability before you do. + +The best way to avoid these overheads and vulnerabilities is to test your contracts thoroughly before deploying them. +You can use [unit](#unit-tests) and [integration](#integration-tests) tests, as well +as [manual testing](#manual-testing), to ensure your contracts behave as expected. + +## Automated Testing + +You can use various tools to automatically test your smart contract’s code and for any error in execution. The great +benefit of automated testing is that it requires minimal human intervention, and it can be built right into your +deployment pipelines. + +Automated testing also allows you to run repetitive and time-consuming tasks without testing each case manually and +avoid human errors, which can happen when you manually input tons of data. + +However, you must be careful, as automated testing can lead to false positives or miss certain edge cases. + +### Unit Tests + +In a nutshell, unit testing ensures that each function and component works correctly by evaluating each independently. +You can use unit tests to ensure that functions return the expected values and modify your contract's state properly. +They should be simple, quick to run and provide helpful feedback if anything goes wrong. This makes them an ideal tool +to ensure your contracts run smoothly after any modifications. + +#### Unit Testing Guidelines + +##### Understand the logic behind your contract’s workflow + +Before you can write any tests, you should understand how your contract is supposed to behave. You should know its +functionalities and how users will access them. Your tests should cover different functions a user may call when +interacting with the contract and check that functions are disabled when they should be. + +#### Evaluate your contract’s assumptions + +It is important to verify that every internal decision the contract takes matches your assumptions on how it should +behave. This forces you to think about edge cases rather than only thinking of the “happy path” you want your users to +take. You can write negative tests to assert how your contract would respond to invalid or malicious inputs. + +##### Measure Code Coverage + +Code coverage is a key metric when it comes to understanding the effectiveness of your tests. It measures the number of +lines, statements, and branches that are actually executed during your unit tests. If you don’t have thorough code +coverage, your test may give what is commonly known as a “false negative”, where your contract passed all your tests, +but your tests didn’t evaluate all the possible vulnerabilities. + +#### Unit Testing Frameworks + +The quality of your unit test will depend on the quality of the tools you use to write and execute them. You should use +a testing framework that is regularly maintained and updated, provides features that are relevant to your contract, and +is popular amongst other developers. + +:::tip Solo + +If you want to test ISC-specific functionalities, like the [magic contract](./core-contracts/introduction.md), you should use +the [Solo Framework](../solo/getting-started.md). + +::: + +* [Waffle](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#writing-tests) +* [Remix](https://remix-ide.readthedocs.io/en/latest/unittesting.html#write-tests) +* [Hardhat](https://hardhat.org/hardhat-runner/docs/guides/test-contracts) +* [Brownie](https://eth-brownie.readthedocs.io/en/v1.0.0_a/tests.html) +* [Ape](https://docs.apeworx.io/ape/stable/userguides/testing.html) +* [Foundry](https://book.getfoundry.sh/forge/writing-tests) + +### Integration Tests + +Integration tests are beneficial when your contract adopts a modular architecture or interfaces with other contracts +during its execution. While [unit tests](#unit-tests) focus on testing functions in isolation, trying each cog in the +machine individually, so to speak, integration tests evaluate how these functions work together as a whole, testing the +machine as a whole. You should use integration tests to detect any issues arising from interactions between different +functions in your contracts' cross-contract calls and ensure that inherited or extended functions are working as +expected. + +#### Tools + +You can use the [ShimmerEVM Testnet](/build/networks-endpoints/#testnet-evm) to conduct integration tests without +incurring any fees or the [IOTA Sandbox](/iota-sandbox/getting-started/) if you want to run the tests locally. + +## Manual Testing + +Once you have a complete batch of [automated tests](#automated-testing), manually testing your contract to ensure it +behaves as expected in the real world is still good practice. However, to avoid incurring fees or deploying a faulty +contract, you can manually test your contract using a sandboxed local network and the Shimmer EVM Testnet. + +Testing using the [IOTA Sandbox](/iota-sandbox/getting-started/) serves well for the first stage of automated and manual +integration tests, as you have complete control over the entire local network. Once you are confident about how your +contract behaves locally, you can deploy and test on the [ShimmerEVM Testnet](/build/networks-endpoints/#testnet-evm), +which replicates the ShimmerEVM network but also enables cost and risk-free interactions. + + diff --git a/docs/build/isc/v1.3-alpha/docs/introduction.md b/docs/build/isc/v1.3-alpha/docs/introduction.md new file mode 100644 index 00000000000..c644eb4da1a --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/introduction.md @@ -0,0 +1,77 @@ +--- +description: 'The current release of IOTA Smart Contracts also has experimental support for EVM/Solidity, providing +limited compatibility with existing smart contracts and tooling from other EVM based chains like Ethereum.' +image: /img/logo/WASP_logo_dark.png +tags: + + - EVM + - Solidity + - smart contracts + - Ethereum + - explanation + +--- +import NetworkWarning from './_admonitions/_network_warning.md' +import OnOffLedgerRequest from './_partials/_on_off_ledger_request.md'; + +# Introduction + + + +Smart contracts are deterministic applications that run on a distributed network with multiple +[validators](explanations/validators.md) that execute and validate the same code. +Their deterministic and distributed nature makes them predictable, stable and trustworthy. + +## Scalable Smart Contracts + +Due to the distributed nature of smart contracts, i.e. they run on a network of validators instead of a single computer, +the execution of smart contract is resource intensive as it has to deal with the overhead of the communication between validators in the network. +This can lead to relatively high [fees](#gas) for smart contract execution, as well as scalability issues when running on +a single blockchain. However, the IOTA Smart Contract Protocol allows **many blockchains that execute smart contracts to +run in parallel** and communicate with one another, therefore solving the scalability problem. Enabling interoperability and horizontal scaling of dApps. + +At the same time, ISC provides advanced means of communication between its chains and preserves the ability to create +complex, composed smart contracts. + +## ISC Architecture + +IOTA Smart Contracts (ISC) function as a Layer 2 extension to the IOTA Multi-Asset Ledger. +As validator nodes execute the smart contracts, they tally these state changes and write them into the chain. +In turn ISC chains, each with their state and smart contracts, update their state collectively and interact with Layer 1 +and other L2 chains, offering a sophisticated multi-chain architecture. + +![IOTA Smart Contacts multichain architecture](/img/multichain.png 'Click to see the full-size image.') + +_IOTA Smart Contacts multichain architecture._ + +[Explore the comprehensive overview of IOTA Smart Contracts in the ISC white paper](https://files.iota.org/papers/ISC_WP_Nov_10_2021.pdf). + +## Supported VMs + +The IOTA Smart Contracts currently +supports [EVM/Solidity](getting-started/languages-and-vms.md#evmsolidity-based-smart-contracts) +smart contracts, as well as an **experimental** [Wasm VM](getting-started/languages-and-vms.md#wasm-vm-for-isc). + +## Sandbox Interface + +ISC Smart contracts can access the [Sandbox interface](explanations/sandbox.md). +This interface provides access to the chain state, native assets, allows interaction with other contracts/chains, as +well as various utilities like cryptographic functions and event dispatching. + +![Sandbox](/img/sandbox.png) + +## Calling a Smart Contract + +### Entry Points and Requests + +Smart contracts are activated through entry points, similar to function calls. Entry points can be view-only or allow state +modifications. They are triggered by requests, signed by senders. Smart contracts on the same chain can +synchronously invoke each other, ensuring deterministic results. However, requests between chains are asynchronous and +may involve delays. + +### Gas + +Running a request consumes 'gas'. Gas units are a measurement of "how expensive" a computation is to execute. You can specify a `GasBudget` +for each request, with costs charged to your on-chain account. + + diff --git a/docs/build/isc/v1.3-alpha/docs/reference/.gitignore b/docs/build/isc/v1.3-alpha/docs/reference/.gitignore new file mode 100644 index 00000000000..31a1d0913e6 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/.gitignore @@ -0,0 +1,3 @@ +magic-contract/* +!magic-contract/introduction.md +iscutils diff --git a/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/accounts.md b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/accounts.md new file mode 100644 index 00000000000..e445e0db13a --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/accounts.md @@ -0,0 +1,365 @@ +--- +description: 'The `accounts` contract keeps the ledger of on-chain accounts.' +image: /img/logo/WASP_logo_dark.png +tags: + - core contracts + - accounts + - deposit + - withdraw + - assets + - balance + - reference +--- + +# The `accounts` Contract + +The `accounts` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts +chain. + +This contract keeps a consistent ledger of on-chain accounts in its state, +i.e. [the L2 ledger](../../explanations/how-accounts-work.md). + +--- + +## Entry Points + +The `accounts` contract provides functions to deposit and withdraw tokens, information about the assets deposited on the +chain, and the functionality to create and use foundries. + +### `deposit()` + +A no-op that has the side effect of crediting any transferred tokens to the sender's account. + +:::note Gas Fees + +As with every call, the gas fee is debited from the L2 account right after executing the request. + +::: + +### `withdraw()` + +Moves tokens from the caller's on-chain account to the caller's L1 address. The number of +tokens to be withdrawn must be specified via the allowance of the request. + +:::note Contract Account + +Because contracts does not have a corresponding L1 address it does not make sense to +have them call this function. It will fail with an error. + +::: + +:::note Storage Deposit + +A call to withdraw means that a L1 output will be created. Because of this, the withdrawn +amount must be able to cover the L1 storage deposit. Otherwise, it will fail. + +::: + +### `transferAllowanceTo(a AgentID)` + +Transfers the specified allowance from the sender's L2 account to the given L2 account on +the chain. + +:::note + +When a transfer is made into an EVM account, an EVM tx will be created on the EVM side from the zero address (0x0000...) to the target account. +Information about what is being transferred will be encoded in the transaction's data using the following format: + +``` + + +``` + +The encoding used for this data can be found on [TIP-51](https://github.com/jorgemmsilva/tips/blob/b46d7bc36a0f7d4c2a1ad32ba25ec2abb4835cb3/tips/TIP-0051/tip-0051.md) + +::: + +#### Parameters + +- `a` (`AgentID`): The target L2 account. + +### `transferAccountToChain(g GasReserve)` + +Transfers the specified allowance from the sender SC's L2 account on +the target chain to the sender SC's L2 account on the origin chain. + +#### Parameters + +- `g` (`uint64`): Optional gas amount to reserve in the allowance for + the internal call to transferAllowanceTo(). Default 100 (MinGasFee). + +:::note Important Detailed Information + +[Read carefully before using this function.](xfer.md) + +::: + +### `foundryCreateNew(t TokenScheme) s SerialNumber` + +Creates a new foundry with the specified token scheme, and assigns the foundry to the sender. + +You can call this end point from the CLI using `wasp-cli chain create-foundry -h` + +#### Parameters + +- `t` ([`iotago::TokenScheme`](https://github.com/iotaledger/iota.go/blob/develop/token_scheme.go)): The token scheme + for the new foundry. + +The storage deposit for the new foundry must be provided via allowance (only the minimum required will be used). + +#### Returns + +- `s` (`uint32`): The serial number of the newly created foundry + +### `foundryModifySupply(s SerialNumber, d SupplyDeltaAbs, y DestroyTokens)` + +Mints or destroys tokens for the given foundry, which must be controlled by the caller. + +#### Parameters + +- `s` (`uint32`): The serial number of the foundry. +- `d` (positive `big.Int`): Amount to mint or destroy. +- `y` (optional `bool` - default: `false`): Whether to destroy tokens (`true`) or not (`false`). + +When minting new tokens, the storage deposit for the new output must be provided via an allowance. + +When destroying tokens, the tokens to be destroyed must be provided via an allowance. + +### `foundryDestroy(s SerialNumber)` + +Destroys a given foundry output on L1, reimbursing the storage deposit to the caller. The foundry must be owned by the +caller. + +:::warning + +This operation cannot be reverted. + +::: + +#### Parameters + +- `s` (`uint32`): The serial number of the foundry. + +### `mintNFT(I ImmutableData, a AgentID, C CollectionID, w WithdrawOnMint)` + +Mints an NFT with ImmutableData `I` that will be owned by the AgentID `a`. +It's possible to mint as part of a collection `C` (the caller must be the owner of the collection NFT to mint new NFTs as part of said collection). +The mint can be done directly to any L1 address (it is not necessary for the target to have an account on the chain) + +#### Parameters + +- `I` (`[]byte`): ImmutableData for the NFT. +- `a` (`AgentID`): AgentID that will be the owner of the NFT. +- `C` (optional `NFTID` - default empty): collectionID (NFTID) for the NFT. +- `w` (optional `bool` - default `false`): whether to withdrawal the NFT in the minting step (can only be `true` when the targetAgentID is a L1 address). + +#### Returns + +- `D` (`MintID`): the internal ID of the NFT at the time of minting that can be used by users/contracts to obtain the resulting NFTID on the next block + +--- + +## Views + +### `balance(a AgentID)` + +Returns the fungible tokens owned by the given Agent ID on the chain. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID. + +#### Returns + +A map of [`TokenID`](#tokenid) => `big.Int`. An empty token ID (a string of zero length) represents the L1 base token. + +### `balanceBaseToken(a AgentID)` + +Returns the amount of base tokens owned by any AgentID `a` on the chain. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID. + +#### Returns + +- `B` (`uint64`): The amount of base tokens in the account. + +### `balanceNativeToken(a AgentID, N TokenID)` + +Returns the amount of native tokens with Token ID `N` owned by any AgentID `a` on the chain. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID. +- `N` ([`TokenID`](#tokenid)): The Token ID. + +#### Returns + +- `B` (`big.Int`): The amount of native tokens in the account. + +### `totalAssets()` + +Returns the sum of all fungible tokens controlled by the chain. + +#### Returns + +A map of [`TokenID`](#tokenid) => `big.Int`. An empty token ID (a string of zero length) represents the L1 base token. + +### `accounts()` + +Returns a list of all agent IDs that own assets on the chain. + +#### Returns + +A map of `AgentiD` => `0x01`. + +### `getNativeTokenIDRegistry()` + +Returns a list of all native tokenIDs that are owned by the chain. + +#### Returns + +A map of [`TokenID`](#tokenid) => `0x01` + +### `foundryOutput(s FoundrySerialNumber)` + +#### Parameters + +- `s` ([`FoundrySerialNumber`](#foundryserialnumber)): The Foundry serial number. + +#### Returns + +- `b`: [`iotago::FoundryOutput`](https://github.com/iotaledger/iota.go/blob/develop/output_foundry.go) + +### `accountNFTs(a AgentID)` + +Returns the NFT IDs for all NFTs owned by the given account. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID + +#### Returns + +- `i` ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) + of [`iotago::NFTID`](https://github.com/iotaledger/iota.go/blob/develop/output_nft.go)): + The NFT IDs owned by the account + +### `accountNFTAmount(a AgentID)` + +Returns the number of NFTs owned by the given account. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID + +#### Returns + +- `A` (`uint32`) Amount of NFTs owned by the account + +### `accountNFTsInCollection(a AgentID)` + +Returns the NFT IDs for all NFTs in the given collection that are owned by the given account. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID +- `C` (`NFTID`): The NFT ID of the collection + +#### Returns + +- `i` ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) + of [`iotago::NFTID`](https://github.com/iotaledger/iota.go/blob/develop/output_nft.go)): + The NFT IDs in the collection owned by the account + +### `accountNFTAmountInCollection(a AgentID)` + +Returns the number of NFTs in the given collection that are owned by the given account. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID +- `C` (`NFTID`): The NFT ID of the collection + +#### Returns + +- `A` (`uint32`) Amount of NFTs in the collection owned by the account + +### `accountFoundries(a AgentID)` + +Returns all foundries owned by the given account. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID + +#### Returns + +A map of [`FoundrySerialNumber`](#foundryserialnumber) => `0x01` + +### `nftData(z NFTID)` + +Returns the data for a given NFT with ID `z` that is on the chain. + +#### Returns + +- `e`: [`NFTData`](#nftdata) + +### `NFTIDbyMintID(D MintID)` + +Returns the NFTID `z` for a given MintID `D`. + +#### Parameters + +- `D` (`MintID`): MintID producted at the time the NFT was minted + +#### Returns + +- `z` (`NFTID`): The ID of the NFT + +### `getAccountNonce(a AgentID)` + +Returns the current account nonce for a give AgentID `a`. +The account nonce is used to issue off-ledger requests. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID. + +#### Returns + +- `n` (`uint64`): The account nonce. + +## Schemas + +### `FoundrySerialNumber` + +``` +FoundrySerialNumber = uint32 +``` + +### `TokenID` + +``` +TokenID = [38]byte +``` + +### `NFTID` + +``` +NFTID = [32]byte +``` + +### `MintID` + +``` +MintID = [6]byte +``` + +### `NFTData` + +`NFTData` is encoded as the concatenation of: + +- The issuer ([`iotago::Address`](https://github.com/iotaledger/iota.go/blob/develop/address.go)). +- The NFT metadata: the length (`uint16`) followed by the data bytes. +- The NFT owner (`AgentID`). diff --git a/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/blob.md b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/blob.md new file mode 100644 index 00000000000..67e516e2a0a --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/blob.md @@ -0,0 +1,108 @@ +--- +description: The `blobs` contract maintains a registry of _blobs_ (a collection of arbitrary binary data) referenced from smart contracts via their hashes. +image: /img/logo/WASP_logo_dark.png +tags: + - core contracts + - bloc + - binary data + - store + - get + - entry points + - views + - reference +--- + +# The `blob` Contract + +The `blob` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts chain. + +The objective of the `blob` contract is to maintain an on-chain registry of _blobs_. +A blob is a collection of named chunks of binary data. + +``` +: +: +... +: +``` + +Both names and chunks are arbitrarily long byte slices. + +Blobs can be used to store arbitrary data like, for example, a collection of Wasm binaries needed to deploy a smart contract. + +Each blob in the registry is referenced by its hash. The hash is deterministically calculated from the concatenation of all pieces: + +``` +blobHash = hash( fieldName1 || binaryChunk1 || fieldName2 || binaryChunk2 || ... || fieldNameN || binaryChunkN) +``` + +Usually, field names are short strings, but their interpretation is use-case specific. + +Two predefined field names are interpreted by the VM while deploying smart contracts from binary: + +- _fieldname_ = `"v"` is interpreted as the _VM type_. +- _fieldname_ = `"p"` is interpreted as the _smart contract program binary_. + +If the field `"v"` is equal to the string `"wasmtime"`, the binary chunk of `"p"` is interpreted as WebAssembly binary, executable by the Wasmtime interpreter. + +The blob describing a smart contract may contain extra fields (ignored by the VM), for example: + +``` +"v" : VM type +"p" : smart contract program binary +"d" : data schema for data exchange between smart contract and outside sources and consumers +"s" : program sources in .zip format +``` + +--- + +## Entry Points + +### `storeBlob()` + +Stores a new blob in the registry. + +#### Parameters + +The key/value pairs of the received parameters are interpreted as the field/chunk pairs of the blob. + +#### Returns + +- `hash` (`[32]byte`): The hash of the stored blob. + +--- + +## Views + +### `getBlobInfo(hash BlobHash)` + +Returns the size of each chunk of the blob. + +#### Parameters + +- `hash` (`[32]byte`): The hash of the blob. + +#### Returns + +``` +: (uint32) +... +: (uint32) +``` + +### `getBlobField(hash BlobHash, field BlobField)` + +Returns the chunk associated with the given blob field name. + +#### Parameters + +- `hash` (`[32]byte`): The hash of the blob. +- `field` (`[]byte`): The field name. + +#### Returns + +- `bytes` (`[]byte`): The chunk associated with the given field name. + +### `listBlobs()` + +Returns a list of pairs `blob hash`: `total size of chunks` (`uint32`) for all blobs in the registry. diff --git a/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/blocklog.md b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/blocklog.md new file mode 100644 index 00000000000..c78d57d17a6 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/blocklog.md @@ -0,0 +1,202 @@ +--- +description: The `blocklog` contract keeps track of the blocks of requests processed by the chain. +image: /img/logo/WASP_logo_dark.png +tags: + - core contracts + - blocklog + - views + - information + - request status + - receipts + - events + - reference +--- + +# The `blocklog` Contract + +The `blocklog` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts chain. + +The `blocklog` contract keeps track of the blocks of requests processed by the chain, providing views to get request +status, receipts, block, and event details. + +To avoid having a monotonically increasing state size, only the latest `N` +blocks (and their events and receipts) are stored. This parameter can be configured +when [deploying the chain](/wasp/how-tos/setting-up-a-chain). + +--- + +## Entry Points + +### `retryUnprocessable(u requestID)` + +Tries to retry a given request that was marked as "unprocessable". + +:::note +"Unprocessable" requests are on-ledger requests that do not include enough base tokens to cover the deposit fees (example if an user tries to deposit many native tokens in a single output but only includes the minimum possible amount of base tokens). Such requests will be collected into an "unprocessable list" and users are able to deposit more funds onto their on-chain account and retry them afterwards. +::: + +#### Parameters + +- `u` ([`isc::RequestID`](https://github.com/iotaledger/wasp/blob/develop/packages/isc/request.go)): The requestID to be retried. (sender of the retry request must match the sender of the "unprocessable" request) + +--- + +## Views + +### `getBlockInfo(n uint32)` + +Returns information about the block with index `n`. + +#### Parameters + +- `n`: (optional `uint32`) The block index. Default: the latest block. + +#### Returns + +- `n` (`uint32`):The block index. +- `i` ([`BlockInfo`](#blockinfo)):The information about the block. + +### `getRequestIDsForBlock(n uint32)` + +Returns a list with all request IDs in the block with block index `n`. + +#### Parameters + +- `n` (optional `uint32`):The block index. The default value is the latest block. + +#### Returns + +- `n` (`uint32`):The block index. +- `u`: ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) + of [`RequestID`](#requestid)) + +### `getRequestReceipt(u RequestID)` + +Returns the receipt for the request with the given ID. + +#### Parameters + +- `u` ([`RequestID`](#requestid)):The request ID. + +#### Returns + +- `n` (`uint32`):The block index. +- `r` (`uint16`):The request index within the block. +- `d` ([`RequestReceipt`](#requestreceipt)):The request receipt. + +### `getRequestReceiptsForBlock(n uint32)` + +Returns all the receipts in the block with index `n`. + +#### Parameters + +- `n` (optional `uint32`):The block index. Defaults to the latest block. + +#### Returns + +- `n` (`uint32`):The block index. +- `d`: ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) + of [`RequestReceipt`](#requestreceipt)) + +### `isRequestProcessed(u RequestID)` + +Returns whether the request with ID `u` has been processed. + +#### Parameters + +- `u` ([`RequestID`](#requestid)):The request ID. + +#### Returns + +- `p` (`bool`):Whether the request was processed or not. + +### `getEventsForRequest(u RequestID)` + +Returns the list of events triggered during the execution of the request with ID `u`. + +### Parameters + +- `u` ([`RequestID`](#requestid)):The request ID. + +#### Returns + +- `e`: ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) of `[]byte`). + +### `getEventsForBlock(n blockIndex)` + +Returns the list of events triggered during the execution of all requests in the block with index `n`. + +#### Parameters + +- `n` (optional `uint32`):The block index. Defaults to the latest block. + +#### Returns + +- `e`: ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) of `[]byte`). + +### `getEventsForContract(h Hname)` + +Returns a list of events triggered by the smart contract with hname `h`. + +#### Parameters + +- `h` (`hname`):The smart contract’s hname. +- `f` (optional `uint32` - default: `0`):"From" block index. +- `t` (optional `uint32` - default: `MaxUint32`):"To" block index. + +#### Returns + +- `e`: ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) of `[]byte`) + +### `hasUnprocessable(u requestID)` + +Asserts whether or not a given requestID (`u`) is present in the "unprocessable list" + +#### Parameters + +- `u` ([`isc::RequestID`](https://github.com/iotaledger/wasp/blob/develop/packages/isc/request.go)): The requestID to be checked + +#### Returns + +- `x` ([`bool`]) Whether or not the request exists in the "unprocessable list" + +--- + +## Schemas + +### `RequestID` + +A `RequestID` is encoded as the concatenation of: + +- Transaction ID (`[32]byte`). +- Transaction output index (`uint16`). + +### `BlockInfo` + +`BlockInfo` is encoded as the concatenation of: + +- The block timestamp (`uint64` UNIX nanoseconds). +- Amount of requests in the block (`uint16`). +- Amount of successful requests (`uint16`). +- Amount of off-ledger requests (`uint16`). +- Anchor transaction ID ([`iotago::TransactionID`](https://github.com/iotaledger/iota.go/blob/develop/transaction.go)). +- Anchor transaction sub-essence hash (`[32]byte`). +- Previous L1 commitment (except for block index 0). + - Trie root (`[20]byte`). + - Block hash (`[20]byte`). +- Total base tokens in L2 accounts (`uint64`). +- Total storage deposit (`uint64`). +- Gas burned (`uint64`). +- Gas fee charged (`uint64`). + +### `RequestReceipt` + +`RequestReceipt` is encoded as the concatenation of: + +- Gas budget (`uint64`). +- Gas burned (`uint64`). +- Gas fee charged (`uint64`). +- The request ([`isc::Request`](https://github.com/iotaledger/wasp/blob/develop/packages/isc/request.go)). +- Whether the request produced an error (`bool`). +- If the request produced an error, the + [`UnresolvedVMError`](./errors.md#unresolvedvmerror). diff --git a/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/errors.md b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/errors.md new file mode 100644 index 00000000000..e4e5dbb2244 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/errors.md @@ -0,0 +1,77 @@ +--- +description: 'The errors contract keeps a map of error codes to error message templates. These error codes are used in +request receipts.' +image: /img/logo/WASP_logo_dark.png +tags: + +- smart contracts +- core +- root +- initialization +- entry points +- fees +- ownership +- views +- reference +--- + +# The `errors` Contract + +The `errors` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts +chain. + +The `errors` contract keeps a map of error codes to error message templates. +This allows contracts to store lengthy error strings only once and then reuse them by just providing the error code (and +optional extra values) when producing an error, thus saving storage and gas. + +--- + +## Entry Points + +### `registerError(m ErrorMessageFormat) c ErrorCode` + +Registers an error message template. + +#### Parameters + +- `m` (`string`): The error message template, which supports standard [go verbs](https://pkg.go.dev/fmt#hdr-Printing) + for variable printing. + +#### Returns + +- `c` (`ErrorCode`): The error code of the registered template + +--- + +## Views + +### `getErrorMessageFormat(c ErrorCode) m ErrorMessageFormat` + +Returns the message template stored for a given error code. + +#### Parameters + +- `c` (`ErrorCode`): The error code of the registered template. + +#### Returns + +- `m` (`string`): The error message template. + +--- + +## Schemas + +### `ErrorCode` + +`ErrorCode` is encoded as the concatenation of: + +- The contract hname(`hname`). +- The error ID, calculated as the hash of the error template(`uint16`). + +### `UnresolvedVMError` + +`UnresolvedVMError` is encoded as the concatenation of: + +- The error code ([`ErrorCode`](#errorcode)). +- CRC32 checksum of the formatted string (`uint32`). +- The JSON-encoded list of parameters for the template (`string` prefixed with `uint16` size). diff --git a/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/evm.md b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/evm.md new file mode 100644 index 00000000000..99be19b75bc --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/evm.md @@ -0,0 +1,170 @@ +--- +description: 'The evm core contract provides the necessary infrastructure to accept Ethereum transactions and execute +EVM code.' +image: /img/logo/WASP_logo_dark.png +tags: + +- smart contracts +- core +- root +- initialization +- entry points +- fees +- ownership +- views +- reference +--- + +# The `evm` Contract + +The `evm` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts chain. + +The `evm` core contract provides the necessary infrastructure to accept Ethereum transactions and execute EVM code. +It also includes the implementation of the [ISC Magic contract](../../how-tos/core-contracts/introduction.md). + +:::note + +For more information about how ISC supports EVM contracts, refer to the [EVM](../../getting-started/languages-and-vms.md#evmsolidity-based-smart-contracts) section. + +::: + +--- + +## Entry Points + +Most entry points of the `evm` core contract are meant to be accessed through the JSON-RPC service provided +automatically by the Wasp node so that the end users can use standard EVM tools like [MetaMask](https://metamask.io/). +We only list the entry points not exposed through the JSON-RPC interface in this document. + +### `init()` + +Called automatically when the ISC is deployed. + +Some parameters of the `evm` contract can be specified by passing them to the +[`root` contract `init` entry point](root.md#init): + +- `evmg` (optional [`GenesisAlloc`](#genesisalloc)): The genesis allocation. The balance of all accounts must be 0. +- `evmbk` (optional `int32` - default: keep all): Amount of EVM blocks to keep in the state. +- `evmchid` (optional `uint16` - default: 1074): EVM chain iD + + :::caution + + Re-using an existing Chain ID is not recommended and can be a security risk. For serious usage, register a unique + Chain ID on [Chainlist](https://chainlist.org/) and use that instead of the default. **It is not possible to change + the EVM chain ID after deployment.** + + ::: + +- `evmw` (optional [`GasRatio`](#gasratio) - default: `1:1`): The ISC to EVM gas ratio. + +### `registerERC20NativeToken` + +Registers an ERC20 contract to act as a proxy for the native tokens, at address +`0x107402xxxxxxxx00000000000000000000000000`, where `xxxxxxxx` is the +little-endian encoding of the foundry serial number. + +Only the foundry owner can call this endpoint. + +#### Parameters + +- `fs` (`uint32`): The foundry serial number +- `n` (`string`): The token name +- `t` (`string`): The ticker symbol +- `d` (`uint8`): The token decimals + +You can call this endpoint with the `wasp-cli register-erc20-native-token` command. See +`wasp-cli chain register-erc20-native-token -h` for instructions on how to use the command. + +### `registerERC20NativeTokenOnRemoteChain` + +Registers an ERC20 contract to act as a proxy for the native tokens **on another +chain**. + +The foundry must be controlled by this chain. Only the foundry owner can call +this endpoint. + +This endpoint is intended to be used in case the foundry is controlled by chain +A, and the owner of the foundry wishes to register the ERC20 contract on chain +B. In that case, the owner must call this endpoint on chain A with `target = +chain B`. The request to chain B is then sent as an on-ledger request. +After a few minutes, call +[`getERC20ExternalNativeTokenAddress`](#geterc20externalnativetokenaddress) +on chain B to find out the address of the ERC20 contract. + +#### Parameters + +- `fs` (`uint32`): The foundry serial number +- `n` (`string`): The token name +- `t` (`string`): The ticker symbol +- `d` (`uint8`): The token decimals +- `A` (`uint8`): The target chain address, where the ERC20 contract will be + registered. + +You can call this endpoint with the `wasp-cli register-erc20-native-token-on-remote-chain` command. See +`wasp-cli chain register-erc20-native-token-on-remote-chain -h` for instructions on how to use the command. + +### `registerERC20ExternalNativeToken` + +Registers an ERC20 contract to act as a proxy for the native tokens. + +Only an alias address can call this endpoint. + +If the foundry is controlled by another ISC chain, the foundry owner can call +[`registerERC20NativeTokenOnRemoteChain`](#registererc20nativetokenonchain) +on that chain, which will automatically call this endpoint on the chain set as +target. + +#### Parameters + +- `fs` (`uint32`): The foundry serial number +- `n` (`string`): The token name +- `t` (`string`): The ticker symbol +- `d` (`uint8`): The token decimals +- `T` (`TokenScheme`): The native token scheme + +### `registerERC721NFTCollection` + +Registers an ERC721 contract to act as a proxy for an NFT collection, at address +`0x107404xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`, where `xxx...` is the first 17 +bytes of the collection ID. + +The call will fail if the address is taken by another collection with the same prefix. + +#### Parameters + +- `C` (`NTFID`): The collection ID + +--- + +## Views + +### `getERC20ExternalNativeTokenAddress` + +Returns the address of an ERC20 contract registered with +[`registerERC20NativeTokenOnRemoteChain`](#registererc20nativetokenonchain). + +Only the foundry owner can call this endpoint. + +#### Parameters + +- `N` (`NativeTokenID`): The native token ID + +--- + +## Schemas + +### `GenesisAlloc` + +`GenesisAlloc` is encoded as the concatenation of: + +- Amount of accounts `n` (`uint32`). +- `n` times: + - Ethereum address (`[]byte` prefixed with `uint32` size). + - Account code (`[]byte` prefixed with `uint32` size). + - Amount of storage key/value pairs `m`(`uint32`). + - `m` times: + - Key (`[]byte` prefixed with `uint32` size). + - Value(`[]byte` prefixed with `uint32` size). + - Account balance (must be 0)(`[]byte` prefixed with `uint32` size). + - Account nonce (`uint64`). + - Account private key (may be used for tests)(`uint64`). diff --git a/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/governance.md b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/governance.md new file mode 100644 index 00000000000..ab8e092379b --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/governance.md @@ -0,0 +1,355 @@ +--- +description: 'The `governance` contract defines the set of identities that constitute the state controller, access nodes, +who is the chain owner, and the fees for request execution.' +image: /img/logo/WASP_logo_dark.png +tags: + +- core contracts +- governance +- state controller +- identities +- chain owner +- rotate +- remove +- claim +- add +- chain info +- fee info +- reference +--- + +# The `governance` Contract + +The `governance` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts +chain. + +The `governance` contract provides the following functionalities: + +- It defines the identity set that constitutes the state controller (the entity that owns the state output via the chain + Alias Address). It is possible to add/remove addresses from the state controller (thus rotating the committee of + validators). +- It defines the chain owner (the L1 entity that owns the chain - initially whoever deployed it). The chain owner can + collect special fees and customize some chain-specific parameters. +- It defines the entities allowed to have an access node. +- It defines the fee policy for the chain (gas price, what token is used to pay for gas, and the validator fee share). + +--- + +## Fee Policy + +The Fee Policy looks like the following: + +```go +{ + GasPerToken Ratio32 // how many gas units are paid for each token + EVMGasRatio Ratio32 // the ratio at which EVM gas is converted to ISC gas + ValidatorFeeShare uint8 // percentage of the fees that are credited to the validators (0 - 100) +} +``` + +--- + +## Entry Points + +### `rotateStateController(S StateControllerAddress)` + +Called when the committee is about to be rotated to the new address `S`. + +If it succeeds, the next state transition will become a governance transition, thus updating the state controller in the +chain's Alias Output. If it fails, nothing happens. + +It can only be invoked by the chain owner. + +#### Parameters + +- `S` ([`iotago::Address`](https://github.com/iotaledger/iota.go/blob/develop/address.go)): The address of the next + state controller. Must be an + [allowed](#addallowedstatecontrolleraddresss-statecontrolleraddress) state controller address. + +### `addAllowedStateControllerAddress(S StateControllerAddress)` + +Adds the address `S` to the list of identities that constitute the state controller. + +It can only be invoked by the chain owner. + +#### Parameters + +- `S` ([`iotago::Address`](https://github.com/iotaledger/iota.go/blob/develop/address.go)): The address to add to the + set of allowed state controllers. + +### `removeAllowedStateControllerAddress(S StateControllerAddress)` + +Removes the address `S` from the list of identities that constitute the state controller. + +It can only be invoked by the chain owner. + +#### Parameters + +- `S` ([`iotago::Address`](https://github.com/iotaledger/iota.go/blob/develop/address.go)): The address to remove from + the set of allowed state controllers. + +### `delegateChainOwnership(o AgentID)` + +Sets the Agent ID `o` as the new owner for the chain. This change will only be effective +once [`claimChainOwnership`](#claimchainownership) is called by `o`. + +It can only be invoked by the chain owner. + +#### Parameters + +- `o` (`AgentID`): The Agent ID of the next chain owner. + +### `claimChainOwnership()` + +Claims the ownership of the chain if the caller matches the identity set +in [`delegateChainOwnership`](#delegatechainownershipo-agentid). + +### `setFeePolicy(g FeePolicy)` + +Sets the fee policy for the chain. + +#### Parameters + +- `g`: ([`FeePolicy`](#feepolicy)). + +It can only be invoked by the chain owner. + +### `setGasLimits(l GasLimits)` + +Sets the gas limits for the chain. + +#### Parameters + +- `l`: ([`GasLimits`](#gaslimits)). + +It can only be invoked by the chain owner. + +### `setEVMGasRatio(e Ratio32)` + +Sets the EVM gas ratio for the chain. + +#### Parameters + +- `e` ([`Ratio32`](#ratio32)): The EVM gas ratio. + +It can only be invoked by the chain owner. + +### `addCandidateNode(ip PubKey, ic Certificate, ia API, i ForCommittee)` + +Adds a node to the list of candidates. + +#### Parameters + +- `ip` (`[]byte`): The public key of the node to be added. +- `ic` (`[]byte`): The certificate is a signed binary containing both the node public key and their L1 address. +- `ia` (`string`): The API base URL for the node. +- `i` (optional `bool` - default: `false`): Whether the candidate node is being added to be part of the committee or + just an access node. + +It can only be invoked by the access node owner (verified via the Certificate field). + +### `revokeAccessNode(ip PubKey, ic Certificate, ia API, i ForCommittee)` + +Removes a node from the list of candidates. + +#### Parameters + +- `ip` (`[]byte`): The public key of the node to be removed. +- `ic` (`[]byte`): The certificate of the node to be removed. + +It can only be invoked by the access node owner (verified via the Certificate field). + +### `changeAccessNodes(n actions)` + +Iterates through the given map of actions and applies them. + +#### Parameters + +- `n` ([`Map`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/map.go) of `public key` => `byte`): + The list of actions to perform. Each byte value can be one of the following: + - `0`: Remove the access node from the access nodes list. + - `1`: Accept a candidate node and add it to the list of access nodes. + - `2`: Drop an access node from the access node and candidate lists. + +It can only be invoked by the chain owner. + +### `startMaintenance()` + +Starts the chain maintenance mode, meaning no further requests will be processed except +calls to the governance contract. + +It can only be invoked by the chain owner. + +### `stopMaintenance()` + +Stops the maintenance mode. + +It can only be invoked by the chain owner. + +### `setCustomMetadata(x bytes)` + +Changes optional extra metadata that is appended to the L1 AliasOutput. + +#### Parameters + +- `x` (`bytes`): the optional metadata + +### `setPayoutAgentID` + +`setPayoutAgentID` sets the payout AgentID. The default AgentID is the chain owner. Transaction fee will be taken to ensure the common account has minimum storage deposit which is in base token. The rest of transaction fee will be transferred to payout AgentID. + +#### Parameters + +- `s` (`AgentID`): the payout AgentID + +### `setMinCommonAccountBalance` + +`setMinCommonAccountBalance` sets the minimum balanced to be held in the common account. + +#### Parameters + +- `ms` (`AgentID`): the minimum common account balance + +--- + +## Views + +### `getAllowedStateControllerAddresses()` + +Returns the list of allowed state controllers. + +#### Returns + +- `a` ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) + of [`iotago::Address`](https://github.com/iotaledger/iota.go/blob/develop/address.go)): The list of allowed state + controllers. + +### `getChainOwner()` + +Returns the AgentID of the chain owner. + +#### Returns + +- `o` (`AgentID`): The chain owner. + +### `getChainInfo()` + +Returns information about the chain. + +#### Returns + +- `c` (`ChainID`): The chain ID +- `o` (`AgentID`): The chain owner +- `g` ([`FeePolicy`](#feepolicy)): The gas fee policy +- `l` ([`GasLimits`](#gaslimits)): The gas limits +- `x` (`bytes`): The custom metadata + +### `getFeePolicy()` + +Returns the gas fee policy. + +#### Returns + +- `g` ([`FeePolicy`](#feepolicy)): The gas fee policy. + +### `getEVMGasRatio` + +Returns the ISC : EVM gas ratio. + +#### Returns + +- `e` ([`Ratio32`](#ratio32)): The ISC : EVM gas ratio. + +### `getGasLimits()` + +Returns the gas limits. + +#### Returns + +- `l` ([`GasLimits`](#gaslimits)): The gas limits. + +### `getChainNodes()` + +Returns the current access nodes and candidates. + +#### Returns + +- `ac` ([`Map`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/map.go) + of public key => `0x01`): The access nodes. +- `an` ([`Map`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/map.go) + of public key => [`AccessNodeInfo`](#accessnodeinfo)): The candidate nodes. + +### `getMaintenanceStatus()` + +Returns whether the chain is undergoing maintenance. + +#### Returns + +- `m` (`bool`): `true` if the chain is in maintenance mode + +### `getCustomMetadata()` + +Returns the extra metadata that is added to the chain AliasOutput. + +#### Returns + +- `x` (`bytes`): the optional metadata + +### `getPayoutAgentID` + +`getPayoutAgentID` gets the payout AgentID. + +Returns the payout AgentID of the chain. + +#### Returns + +- `s` (`AgentID`): the payout AgentID. + +### `getMinCommonAccountBalance` + +`getMinCommonAccountBalance` returns the minimum balanced to be held in the common account. + +#### Returns + +- `ms` (`uint64`): the minimum storage deposit. + +## Schemas + +### `Ratio32` + +A ratio between two values `x` and `y`, expressed as two `int32` numbers `a:b`, where `y = x * b/a`. + +`Ratio32` is encoded as the concatenation of the two `uint32` values `a` & `b`. + +### `FeePolicy` + +`FeePolicy` is encoded as the concatenation of: + +- The [`TokenID`](accounts.md#tokenid) of the token used to charge for gas. (`iotago.NativeTokenID`) + - If this value is `nil`, the gas fee token is the base token. +- Gas per token ([`Ratio32`](#ratio32)): expressed as an `a:b` (`gas/token`) ratio, meaning how many gas units each token pays for. +- Validator fee share. Must be between 0 and 100, meaning the percentage of the gas fees distributed to the + validators. (`uint8`) +- The ISC:EVM gas ratio ([`Ratio32`](#ratio32)): such that `ISC gas = EVM gas * a/b`. + +### `GasLimits` + +`GasLimits` is encoded as the concatenation of: + +- The maximum gas per block (`uint64`). A request that exceeds this limit is + skipped and processed in the next block. +- The minimum gas per request (`uint64`). If a request consumes less than this + value, it is charged for this instead. +- The maximum gas per request (`uint64`). If a request exceeds this limit, it + is rejected as failed. +- The maximum gas per external view call (`uint64). This is the gas budget + assigned to external view calls. + +### `AccessNodeInfo` + +`AccessNodeInfo` is encoded as the concatenation of: + +- The validator address. (`[]byte` prefixed by `uint16` size) +- The certificate. (`[]byte` prefixed by `uint16` size) +- Whether the access node is part of the committee of validators. (`bool`) +- The API base URL. (`string` prefixed by `uint16` size) diff --git a/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/overview.md b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/overview.md new file mode 100644 index 00000000000..e3d70cd2419 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/overview.md @@ -0,0 +1,37 @@ +--- +description: There currently are 6 core smart contracts that are always deployed on each chain, root, _default, accounts, blob, blocklog, and governance. +image: /img/banner/banner_wasp_core_contracts_overview.png +tags: + - smart contracts + - core + - initialization + - request handling + - on-chain ledger + - accounts + - data + - receipts + - reference +--- + +# Core Contracts + +![Wasp Node Core Contracts Overview](/img/banner/banner_wasp_core_contracts_overview.png) + +There are currently 7 core smart contracts that are always deployed on each +chain. These are responsible for the vital functions of the chain and +provide infrastructure for all other smart contracts: + +- [`root`](./root.md): Responsible for the initialization of the chain, maintains registry of deployed contracts. + +- [`accounts`](./accounts.md): Manages the on-chain ledger of accounts. + +- [`blob`](./blob.md): Responsible for the registry of binary objects of arbitrary size. + +- [`blocklog`](./blocklog.md): Keeps track of the blocks and receipts of requests that were processed by the chain. + +- [`governance`](./governance.md): Handles the administrative functions of the chain. For example: rotation of the committee of validators of the chain, fees and other chain-specific configurations. + +- [`errors`](./errors.md): Keeps a map of error codes to error messages templates. These error codes are used in request receipts. + +- [`evm`](./evm.md): Provides the necessary infrastructure to accept Ethereum + transactions and execute EVM code. diff --git a/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/root.md b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/root.md new file mode 100644 index 00000000000..439e438befb --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/root.md @@ -0,0 +1,121 @@ +--- +description: 'The root contract is the first smart contract deployed on the chain. It functions as a smart contract +factory for the chain.' +image: /img/logo/WASP_logo_dark.png +tags: + +- smart contracts +- core +- root +- initialization +- entry points +- fees +- ownership +- views +- reference +--- + +# The `root` Contract + +The `root` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts +chain. + +The `root` contract is responsible for the initialization of the chain. +It is the first smart contract deployed on the chain and, upon receiving the `init` request, bootstraps the state of the +chain. +Deploying all of the other core contracts is a part of the state initialization. + +The `root` contract also functions as a smart contract factory for the chain: upon request, it deploys other smart +contracts and maintains an on-chain registry of smart contracts in its state. +The contract registry keeps a list of contract records containing their respective name, hname, description, and +creator. + +--- + +## Entry Points + +### `init()` + +The constructor. Automatically called immediately after confirmation of the origin transaction and never called again. +When executed, this function: + +- Initializes base values of the chain according to parameters. +- Sets the caller as the _chain owner_. +- Deploys all the core contracts. + +### `deployContract(ph ProgramHash, nm Name, ds Description)` + +Deploys a non-EVM smart contract on the chain if the caller has deployment permission. + +#### Parameters + +- `ph` (`[32]byte`): The hash of the binary _blob_ (that has been previously stored in the [`blob` contract](blob.md)). +- `nm` (`string`): The name of the contract to be deployed, used to calculate the + contract's _hname_. The hname must be unique among all contract hnames in the chain. +- `ds` (`string`): Description of the contract to be deployed. + +Any other parameters that are passed to the deployContract function will be passed on to +the `init` function of the smart contract being deployed. Note that this means that the +init parameter names cannot be the above ones, as they will have been filtered out. + +### `grantDeployPermission(dp AgentID)` + +The chain owner grants deploy permission to the agent ID `dp`. + +#### Parameters + +`dp`(AgentID): The agent ID. + +### `revokeDeployPermission(dp AgentID)` + +The chain owner revokes the deploy permission of the agent ID `dp`. + +#### Parameters + +`dp`(AgentID): The agent ID. + +### `requireDeployPermissions(de DeployPermissionsEnabled)` + +#### Parameters + +- `de` (`bool`): Whether permissions should be required to deploy a contract on the chain. + +By default, permissions are enabled (addresses need to be granted the right to deploy), but the chain owner can override +this setting to allow anyone to deploy contracts on the chain. + +--- + +## Views + +### `findContract(hn Hname)` + +Returns the record for a given smart contract with Hname `hn` (if it exists). + +#### Parameters + +`hn`: The smart contract’s Hname + +#### Returns + +- `cf` (`bool`): Whether or not the contract exists. +- `dt` ([`ContractRecord`](#contractrecord)): The requested contract record (if it exists). + +### `getContractRecords()` + +Returns the list of all smart contracts deployed on the chain and related records. + +#### Returns + +A map of `Hname` => [`ContractRecord`](#contractrecord) + +--- + +## Schemas + +### `ContractRecord` + +A `ContractRecord` is encoded as the concatenation of: + +- Program hash (`[32]byte`). +- Contract description (`string`). +- Contract name (`string`). diff --git a/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/xfer.md b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/xfer.md new file mode 100644 index 00000000000..208316b58c8 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/core-contracts/xfer.md @@ -0,0 +1,71 @@ +--- +description: 'The `transferAccountToChain` contract needs special consideration.' +image: /img/logo/WASP_logo_dark.png +tags: + - core contracts + - accounts + - deposit + - withdraw + - assets + - balance + - reference +--- + +# `accounts.transferAccountToChain` + +The `transferAccountToChain` function of the `accounts` contract is one that needs +careful consideration before use. Make sure you understand precisely how to use it to +prevent + +--- + +## Entry Point + +### `transferAccountToChain(g GasReserve)` + +Transfers the specified allowance from the sender SC's L2 account on +the target chain to the sender SC's L2 account on the origin chain. + +Caller must be a contract, and we will transfer the allowance from its L2 account +on the target chain to its L2 account on the origin chain. This requires that +this function takes the allowance into custody and in turn sends the assets as +allowance to the origin chain, where that chain's accounts.TransferAllowanceTo() +function then transfers it into the caller's L2 account on that chain. + +#### Parameters + +- `g` (`uint64`): Optional gas amount to reserve in the allowance for + the internal call to transferAllowanceTo(). Default 100 (MinGasFee). + But better to provide it so that it matches the fee structure. + +### IMPORTANT CONSIDERATIONS + +1. The caller contract needs to provide sufficient base tokens in its + allowance, to cover the gas fee GAS1 for this request. + Note that this amount depends on the fee structure of the target chain, + which can be different from the fee structure of the caller's own chain. + +2. The caller contract also needs to provide sufficient base tokens in + its allowance, to cover the gas fee GAS2 for the resulting request to + accounts.TransferAllowanceTo() on the origin chain. The caller needs to + also specify this GAS2 amount through the GasReserve parameter. + +3. The caller contract also needs to provide a storage deposit SD with + this request, holding enough base tokens _independent_ of the GAS1 and + GAS2 amounts. + Since this storage deposit is dictated by L1 we can use this amount as + storage deposit for the resulting accounts.TransferAllowanceTo() request, + where it will then be returned to the caller as part of the transfer. + +4. This means that the caller contract needs to provide at least + GAS1 + GAS2 + SD base tokens as assets to this request, and provide an + allowance to the request that is exactly GAS2 + SD + transfer amount. + Failure to meet these conditions may result in a failed request and + worst case the assets sent to accounts.TransferAllowanceTo() could be + irretrievably locked up in an account on the origin chain that belongs + to the accounts core contract of the target chain. + +5. The caller contract needs to set the gas budget for this request to + GAS1 to guard against unanticipated changes in the fee structure that + raise the gas price, otherwise the request could accidentally cannibalize + GAS2 or even SD, with potential failure and locked up assets as a result. diff --git a/docs/build/isc/v1.3-alpha/docs/reference/json-rpc-spec.md b/docs/build/isc/v1.3-alpha/docs/reference/json-rpc-spec.md new file mode 100644 index 00000000000..e15f1c9684d --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/json-rpc-spec.md @@ -0,0 +1,68 @@ +# JSON-RPC API + +The [JSON-RPC](https://www.jsonrpc.org/specification) is a stateless, lightweight remote procedure call (RPC) protocol. It defines several data structures and the rules around their processing. It is transport agnostic because the concepts can be used within the same process, over sockets, HTTP, or in various message-passing environments. It uses JSON (RFC 4627) as data format. + +This page deals with the JSON-RPC API used by EVM execution clients. + +## JSON-RPC Methods According to [Ethereum Client API](https://ethereum.org/en/developers/docs/apis/json-rpc/) + + +| Method | Description | Status | +|-----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------| +| [eth_getBlockByHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbyhash) | _Returns information about a block by hash_ | ✅ | +| [eth_getBlockByNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) | _Returns information about a block by number_ | ✅ | +| [eth_getBlockTransactionCountByHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbyhash) | _Returns the number of transactions in a block from a block matching the given block hash_ | ✅ | +| [eth_getBlockTransactionCountByNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbynumber) | _Returns the number of transactions in a block matching the given block number_ | ✅ | +| [eth_getUncleCountByBlockHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclecountbyblockhash) | _Returns the number of uncles in a block from a block matching the given block hash_ | ✅ | +| [eth_getUncleCountByBlockNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclecountbyblocknumber) | _Returns the number of uncles in a block from a block matching the given block number_ | ✅ | +| [eth_protocolVersion](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_protocolversion) | _Returns the current Ethereum protocol version_ | ✅ | +| [eth_chainId](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_chainid) | _Returns the chain ID of the current network_ | ✅ | +| [eth_syncing](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_syncing) | _Returns an object with data about the sync status or false-copy_ | ✅ | +| [eth_coinbase](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_coinbase) | _Returns the client Coinbase address_ | ✅ | +| [eth_accounts](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_accounts) | _Returns a list of addresses owned by client_ | ✅ | +| [eth_blockNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber) | _Returns the number of most recent block._ | ✅ | +| [eth_call](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call) | _Executes a new message call immediately without creating a transaction on the blockchain_ | ✅ | +| [eth_estimateGas](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas) | _Generates and returns an estimate of how much gas is necessary to allow the transaction to complete._ | ✅ | +| [eth_gasPrice](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice) | _Returns the current price per gas in wei_ | ✅ | +| [eth_feeHistory](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_feehistory) | _Returns fee history_ | ✅ | +| [eth_newFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newfilter) | _Creates a filter object, based on filter options, to notify when the state changes (logs)_ | ❌ | +| [eth_newBlockFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newblockfilter) | _Creates a filter in the node, to notify when a new block arrives_ | ❌ | +| [eth_newPendingTransactionFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newpendingtransactionfilter) | _Creates a filter in the node, to notify when new pending transactions arrive_ | ❌ | +| [eth_uninstallFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_uninstallfilter) | _Uninstalls a filter with given id_ | ❌ | +| [eth_getFilterChanges](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterchanges) | _Polling method for a filter, which returns an array of logs which occurred since last poll_| ❌ | +| [eth_getFilterLogs](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterlogs) | _Returns an array of all logs matching filter with given id. Can compute the same results with an `eth_getLogs call`_ | ❌ | +| [eth_getLogs](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs) | _Anytime a transaction is mined, we can see event logs for that transaction by making a request to eth_getLogs and then take actions based off those results_ | ✅ | +| [eth_mining](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_mining) | _Returns whether the client is actively mining new blocks_ | ✅ | +| [eth_hashrate](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_hashrate) | _Returns the number of hashes per second that the node is mining with_ | ✅ | +| [eth_sign](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign) | _Returns an EIP-191 signature over the provided data._ | ✅ | +| [eth_signTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_signtransaction) | _Signs and submits a transaction_ | ✅ | +| [eth_getBalance](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getbalance) | _Returns the balance of the account of given address_ | ✅ | +| [eth_getStorageAt](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getstorageat) | _Returns the value from a storage position at a given address_ | ✅ | +| [eth_getTransactionCount](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactioncount) | _Returns the number of transactions sent from an address_ | ✅ | +| [eth_getCode](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getcode) | _Returns code at a given address_ | ✅ | +| [eth_sendTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction) | _Signs and submits a transaction_ | ✅ | +| [eth_sendRawTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction) | _Submits a raw transaction_ | ✅ | +| [eth_getTransactionByHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyhash) | _Returns the information about a transaction requested by transaction hash_ | ✅ | +| [eth_getTransactionByBlockHashAndIndex](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblockhashandindex) | _Returns information about a transaction by block hash and transaction index position_ | ✅ | +| [eth_getTransactionByBlockNumberAndIndex](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblocknumberandindex) | _Returns information about a transaction by block number and transaction index position_ | ✅ | +| [eth_getTransactionReceipt](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionrecepit) | _Returns the receipt of a transaction by transaction hash_ | ✅ | + + +## JSON-RPC methods according to the [Web3 Module API](https://openethereum.github.io/JSONRPC-web3-module) + +| Method | Description | Status | +|----------------------------------------------------------------------------------------------|------------------------------------------------------------------------|--------------------------------| +| [web3_clientVersion](https://openethereum.github.io/JSONRPC-web3-module#web3_clientversion) | _Returns the current client version_ | ✅ | +| [web3_sha](https://openethereum.github.io/JSONRPC-web3-module#web3_sha3) | _Returns Keccak-256 (not the standardized SHA3-256) of the given data_ | ✅ | + + + +## JSON-RPC methods according to the [Net Module API](https://openethereum.github.io/JSONRPC-net-module) + +| Method | Description | Status | +|----------------------------------------------------------------------------------|------------------------------------------------------------------------|--------------------------------| +| [net_listening](https://openethereum.github.io/JSONRPC-net-module#net_listening) | _Returns true if client is actively listening for network connections_ | ✅ | +| [net_peerCount](https://openethereum.github.io/JSONRPC-net-module#net_peercount) | _Returns number of peers currently connected to the client_ | ✅ | +| [net_version](https://openethereum.github.io/JSONRPC-net-module#net_version) | _Returns the current network protocol version_ | ✅ | + +You can find the complete set of available specs in the [Ethereum API Documentation](https://ethereum.github.io/execution-apis/api-documentation/). diff --git a/docs/build/isc/v1.3-alpha/docs/reference/magic-contract/introduction.md b/docs/build/isc/v1.3-alpha/docs/reference/magic-contract/introduction.md new file mode 100644 index 00000000000..3ca44996914 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/magic-contract/introduction.md @@ -0,0 +1,38 @@ +--- +sidebar_position: 1 +--- + +import DocCardList from '@theme/DocCardList'; + +# Introduction + +This section documents the magic contract and all it's interfaces: + + + + +## Call a Native Contract + +You can call native contracts using [`ISC.sandbox.call`](https://github.com/iotaledger/wasp/blob/develop/packages/vm/core/evm/iscmagic/ISCSandbox.sol#L56): + +```solidity +pragma solidity >=0.8.5; + +import "@iota/iscmagic/ISC.sol"; + +contract MyEVMContract { + event EntropyEvent(bytes32 entropy); + + function callInccounter() public { + ISCDict memory params = ISCDict(new ISCDictItem[](1)); + bytes memory int64Encoded42 = hex"2A00000000000000"; + params.items[0] = ISCDictItem("counter", int64Encoded42); + ISCAssets memory allowance; + ISC.sandbox.call(ISC.util.hn("inccounter"), ISC.util.hn("incCounter"), params, allowance); + } +} +``` + +`ISC.util.hn` is used to get the `hname` of the `inccounter` contract and the +`incCounter` entry point. You can also call view entry points using +[ISC.sandbox.callView](https://github.com/iotaledger/wasp/blob/develop/packages/vm/core/evm/iscmagic/ISCSandbox.sol#L59). diff --git a/docs/build/isc/v1.3-alpha/docs/reference/wasm-lib-data-types.mdx b/docs/build/isc/v1.3-alpha/docs/reference/wasm-lib-data-types.mdx new file mode 100644 index 00000000000..28789a1772d --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/reference/wasm-lib-data-types.mdx @@ -0,0 +1,104 @@ +--- +tags: + - data types + - WasmLib + - array + - proxies + - map + - reference + +description: The WasmLib provides direct support for the basic value data types that are found in all programming languages, and WasmLib versions of ISC-specific value data types. +image: /img/logo/WASP_logo_dark.png +--- + +# WasmLib Data Types + +You will need to manipulate data with your smart contracts. We distinguish two groups of +predefined data types that can be used in schema definition files. The WasmLib +implementations for each supported programming language provide full support for these +predefined data types. Each predefined data type can be (de)serialized as byte string or +as human-readable text string. + +## Basic Value Data Types + +These are mostly simple built-in scalar data types as provided by most programming +languages. Each integer data type has a clearly defined storage size. The +[Schema Tool](../schema/how-tos/usage.mdx) will attempt to use the closest matching built-in data type when +generating code for a specific language. + +- `BigInt` - An arbitrary-length unsigned integer. +- `Bool` - An 8-bit boolean value (0 or 1). +- `Bytes` - An arbitrary-length byte array. +- `Int8` - 8-bit signed integer value. +- `Int16` - 16-bit signed integer value. +- `Int32` - 32-bit signed integer value. +- `Int64` - 64-bit signed integer value. +- `String` - An arbitrary-length UTF-8 encoded string value. +- `Uint8` - 8-bit unsigned integer value. +- `Uint16` - 16-bit unsigned integer value. +- `Uint32` - 32-bit unsigned integer value. +- `Uint64` - 64-bit unsigned integer value. + +## ISC-specific Value Data Types + +These are ISC-specific value data types that are needed in the ISC sandbox function calls. +WasmLib provides its own implementations for each of the ISC value data types. + +- `Address` - A 33-byte encoded _Tangle_ address. +- `AgentID` - An ISC Agent ID (Address + Hname). +- `ChainID` - A 32-byte ISC Chain ID. +- `Hash` - A 32-byte hash value. +- `Hname` - A 4-byte unsigned integer hash value derived from a name string. +- `NftID` - A 32-byte ISC NFT ID. +- `RequestID` - A 34-byte ISC transaction request ID. +- `TokenID` - A 38-byte ISC token ID. + +## Full Matrix of WasmLib Types + +WasmLib implements a full set of [value proxies](../schema/proxies.mdx#value-proxies) for each +predefined value type that provide access to data on the ISC host. But there is one aspect +of this data that we have not considered yet. Some data provided by the host is mutable, +whereas other data may be immutable. To facilitate this distinction, each value proxy type +comes in two flavors that reflect this, and make sure that the data can only be used as +intended. + +The rule is that from an immutable container you can only derive immutable container and +value proxies. The referenced data can never be changed through immutable proxies. +Separating these constraints for types into separate value proxy types allows the use of +compile-time type-checking to enforce these constraints. To guard against client code that +tries to bypass them, the ISC sandbox will also check these constraints at runtime on the +host. + +| ISC type | WasmLib type | Mutable proxy | Immutable proxy | +|-----------|-------------------|------------------------|--------------------------| +| BigInt | Sc**BigInt** | ScMutable**BigInt** | ScImmutable**BigInt** | +| Bool | _boolean_ | ScMutable**Bool** | ScImmutable**Bool** | +| Bytes | _byte array_ | ScMutable**Bytes** | ScImmutable**Bytes** | +| Int8 | _8-bit signed_ | ScMutable**Int8** | ScImmutable**Int8** | +| Int16 | _16-bit signed_ | ScMutable**Int16** | ScImmutable**Int16** | +| Int32 | _32-bit signed_ | ScMutable**Int32** | ScImmutable**Int32** | +| Int64 | _64-bit signed_ | ScMutable**Int64** | ScImmutable**Int64** | +| String | _UTF-8 string_ | ScMutable**String** | ScImmutable**String** | +| Uint8 | _8-bit unsigned_ | ScMutable**Uint8** | ScImmutable**Uint8** | +| Uint16 | _16-bit unsigned_ | ScMutable**Uint16** | ScImmutable**Uint16** | +| Uint32 | _32-bit unsigned_ | ScMutable**Uint32** | ScImmutable**Uint32** | +| Uint64 | _64-bit unsigned_ | ScMutable**Uint64** | ScImmutable**Uint64** | +| | | | | +| Address | Sc**Address** | ScMutable**Address** | ScImmutable**Address** | +| AgentId | Sc**AgentId** | ScMutable**AgentId** | ScImmutable**AgentId** | +| ChainId | Sc**ChainId** | ScMutable**ChainId** | ScImmutable**ChainId** | +| Hash | Sc**Hash** | ScMutable**Hash** | ScImmutable**Hash** | +| Hname | Sc**Hname** | ScMutable**Hname** | ScImmutable**Hname** | +| NftID | Sc**NftID** | ScMutable**NftID** | ScImmutable**NftID** | +| RequestId | Sc**RequestId** | ScMutable**RequestId** | ScImmutable**RequestId** | +| TokenID | Sc**TokenID** | ScMutable**TokenID** | ScImmutable**TokenID** | + +The consistent naming makes it easy to remember the type names. Bool, Bytes, String, and +the integer types are the odd ones out. They are implemented in WasmLib by the closest +equivalents in the chosen WasmLib implementation programming language. + +The [Schema Tool](../schema/how-tos/usage.mdx) will automatically generate the proper immutable proxies +from the schema definition. For example, View functions will only be able to access the +[State](../schema/how-tos/state.mdx) map through immutable proxies. The same goes for the +[Params](../schema/how-tos/params.mdx) map that was passed into a Func or View, and for the +[Results](../schema/how-tos/results.mdx) map that was returned from a call to a Func or View. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/access.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/access.mdx new file mode 100644 index 00000000000..a9c799a32a2 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/access.mdx @@ -0,0 +1,37 @@ +--- +description: "This article explains how to define access controls for functions using the optional 'access' subsection in the schema definition file." +tags: + - Access Control + - Schema Tool + - Smart Contract + - AgentID + - Function Access +image: /img/logo/WASP_logo_dark.png +--- + +# Limit Access + +You can define function access controls through the optional `access` subsection in the schema definition file. +By default, functions are accessible to everyone. However, when specified, the `access` identifier restricts who can +call a function. + +## Access Identifiers + +You can set access identifiers with **one** of the following options: + +- `self`: Restricts access to the smart contract itself. +- `chain`: Allows only the chain owner to invoke the function. +- Other: Specify an AgentID or AgentID[] variable in state storage, controlling the agent(s) permitted to call the + function. + You should provide a mechanism to initialize and manage this variable. + +The [Schema Tool](usage.mdx) handles the auto-generation of the code for access verification. + +## Usage Examples + +You can find examples in the schema definition file where the `owner` state variable operates as an access identifier. +Functions such as `init` initialize the state variable, while `setOwner` can modify ownership, +enhancing the security by limiting function access to the current owner. + +Remember to tailor access identifiers to individual functions as required, +and establish multiple identifiers if necessary. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/call.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/call.mdx new file mode 100644 index 00000000000..3a0f26d0df1 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/call.mdx @@ -0,0 +1,178 @@ +--- +description: "Explore how synchronous function calls work between smart contracts, highlighting the role of function descriptors in parameter and token passage, and understanding the ISC host's role in this procedure." +tags: + - Synchronous Calls + - Smart Contracts + - Function Descriptors + - ISC Host + - Function Parameters + - Smart Contract Memory +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Call Functions + +Synchronous function calls between smart contracts act very similar to how normal function calls work in any programming language, +but with a slight twist. +With normal function calls, you share all the global memory that you can access with every function that you call. +However, when calling a smart contract function, +you can only access the memory assigned to that specific smart contract. + +## How Synchronous Calls Operate + +### Data Sharing + +If you want to share data between smart contracts, you will need to use: + +- Function [parameters](params.mdx) +- [Return](results.mdx) values + +## The ISC Host Role + +Ensuring smooth synchronous calls between contracts on the same chain, the ISC host: + +- Recognizes all contracts functioning on a chain. +- Directs the call appropriately to the destined contract function using function descriptors. + +### Function Descriptors + +Function descriptors allow: + +- Specification of call parameters via the [Params](params.mdx) proxy. +- Function invocation through the `func` interface. +- Passing tokens to non-[View](views.mdx) function calls within the same chain. + +:::note + +The only way to call a function and properly pass tokens to it within the same chain is through the function descriptor. +Otherwise, the allowance() function will not register any incoming tokens. + +::: + +### Call Process + +During a call: + +- The initiator function pauses and awaits the completion of the called function. +- Post-completion, retrieves potential returned values through the [Results](results.mdx) proxy. + +### Calling From View Functions + +When a view function initiates a call: + +- It can only reach out to other [view](views.mdx) functions. +- The `ScFuncs` interface mandates an `ScViewContext` for the constructor creating the function descriptor. + +## Usage Example + +Here's how a smart contract would tell a `dividend` contract on the same chain to divide the 1000 tokens it passes to the function: + + + + + +```go +f := dividend.ScFuncs.Divide(ctx) +f.Func.TransferBaseTokens(1000).Call() +``` + + + + +```rust +let f = dividend::ScFuncs::divide(ctx); +f.func.transfer_base_tokens(1000).call(); +``` + + + + +```ts +let f = dividend.ScFuncs.divide(ctx); +f.func.transferBaseTokens(1000).call(); +``` + + + + +And here is how a smart contract would ask a `dividend` contract on the same chain to +return the dispersion factor for a specific address: + + + + + +```go +f := dividend.ScFuncs.GetFactor(ctx) +f.Params.Address().SetValue(address) +f.Func.Call() +factor := f.Results.Factor().Value() +``` + + + + +```rust +let f = dividend::ScFuncs::get_factor(ctx); +f.params.address().set_value(&address); +f.func.call(); +let factor = f.results.factor().value(); +``` + + + + +```ts +let f = dividend.ScFuncs.getFactor(ctx); +f.params.address().setValue(address); +f.func.call(); +let factor = f.results.factor().value(); +``` + + + + +1. Create a function descriptor for the desired function. +2. Use the [Params](params.mdx) proxy in the descriptor to set its parameters. +3. Direct the `func` member of the descriptor to call the associated function +4. Use the [Results](results.mdx) proxy in the descriptor to retrieve its results. + +The function descriptors assume that the function to be called is associated with the +default Hname of the contract, in this case ScHname::new("dividend"). If you deployed the +contract that contains the function you want to call under a different name, then you +would have to provide its associated Hname to the `func` member through the of_contract() +member function like this: + + + + + +```go +altContract := NewScHname("alternateName") +f := dividend.ScFuncs.Divide(ctx) +f.Func.OfContract(altContract).TransferBaseTokens(1000).Call() +``` + + + + +```rust +let alt_contract = ScHname::new("alternateName"); +let f = dividend::ScFuncs::divide(ctx); +f.func.of_contract(alt_contract).transfer_base_tokens(1000).call(); +``` + + + + +```ts +let altContract = ScHname.fromString('alternateName'); +let f = dividend.ScFuncs.divide(ctx); +f.func.ofContract(altContract).transferBaseTokens(1000).call(); +``` + + + diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/events.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/events.mdx new file mode 100644 index 00000000000..02bd5174e73 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/events.mdx @@ -0,0 +1,317 @@ +--- +description: "This article outlines how to trigger events in smart contracts utilizing ISC sandbox's ScFuncContext and the Schema Tool for structured events." +tags: + - Smart Contracts + - ISC Sandbox + - Schema Tool + - Event-driven + - Call Context + - ScFuncContext + - Event Triggering +image: /img/logo/WASP_logo_dark.png +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Trigger Events + +Smart contracts operate in a confined environment but need a mechanism to interact with users. +A solution to this is triggering events, which is facilitated through smart contracts. + +## ISC Sandbox Interface + +The `ScFuncContext` [Call Context](../../explanations/context.mdx) in ISC _Sandbox_ has an `event()` function to support event triggering. +This function takes a text string parameter, requiring creators and users to maintain and understand the chosen format. +However, this setup is prone to errors and inconsistency due to the arbitrary nature of the text strings used. + +## Structured Events with Schema Tool + +To mitigate issues stemming from the rudimentary interface, +use the [Schema Tool](usage.mdx) to define structured events, +making event creation and handling more consistent and less error-prone. + +This tool allows you to establish structured events that are integrated into all Func function contexts. +Note that events: + +- Can only be triggered within a Func +- Become part of the smart contract's state +- Are logged in the core `blocklog` contract +- Cannot be triggered within a View + +## Event Structure + +Define each event in the `events` section of the schema definition file. +This setup ensures that events are encoded consistently, +utilizing a function that automatically formats the event string with the event name, timestamp, and parameter fields, +delimited by vertical bars. +This structured approach facilitates streamlined, error-resistant event triggering. + +### Example + +Here is the `events` section that can be found in the demo `fairroulette` smart contract: + + + + +```yaml +events: + bet: + address: Address # address of better + amount: Uint64 # amount of tokens to bet + number: Uint16 # number to bet on + payout: + address: Address # address of winner + amount: Uint64 # amount of tokens won + round: + number: Uint32 # current betting round number + start: + stop: + winner: + number: Uint16 # the winning number +``` + + + + +The [Schema Tool](usage.mdx) will generate `events.xx` which contains the following code +for the `FairRouletteEvents` struct: + + + + + +```go +package fairroulette + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" + +type FairRouletteEvents struct { +} + +func (e FairRouletteEvents) Bet( + // address of better + address wasmtypes.ScAddress, + // amount of tokens to bet + amount uint64, + // number to bet on + number uint16, +) { + evt := wasmlib.NewEventEncoder("fairroulette.bet") + evt.Encode(wasmtypes.AddressToString(address)) + evt.Encode(wasmtypes.Uint64ToString(amount)) + evt.Encode(wasmtypes.Uint16ToString(number)) + evt.Emit() +} + +func (e FairRouletteEvents) Payout( + // address of winner + address wasmtypes.ScAddress, + // amount of tokens won + amount uint64, +) { + evt := wasmlib.NewEventEncoder("fairroulette.payout") + evt.Encode(wasmtypes.AddressToString(address)) + evt.Encode(wasmtypes.Uint64ToString(amount)) + evt.Emit() +} + +func (e FairRouletteEvents) Round( + // current betting round number + number uint32, +) { + evt := wasmlib.NewEventEncoder("fairroulette.round") + evt.Encode(wasmtypes.Uint32ToString(number)) + evt.Emit() +} + +func (e FairRouletteEvents) Start() { + evt := wasmlib.NewEventEncoder("fairroulette.start") + evt.Emit() +} + +func (e FairRouletteEvents) Stop() { + evt := wasmlib.NewEventEncoder("fairroulette.stop") + evt.Emit() +} + +func (e FairRouletteEvents) Winner( + // the winning number + number uint16, +) { + evt := wasmlib.NewEventEncoder("fairroulette.winner") + evt.Encode(wasmtypes.Uint16ToString(number)) + evt.Emit() +} +``` + + + + +```rust +use wasmlib::*; + +pub struct FairRouletteEvents { +} + +impl FairRouletteEvents { + + pub fn bet(&self, + // address of better + address: &ScAddress, + // amount of tokens to bet + amount: u64, + // number to bet on + number: u16, + ) { + let mut evt = EventEncoder::new("fairroulette.bet"); + evt.encode(&address_to_string(&address)); + evt.encode(&uint64_to_string(amount)); + evt.encode(&uint16_to_string(number)); + evt.emit(); + } + + pub fn payout(&self, + // address of winner + address: &ScAddress, + // amount of tokens won + amount: u64, + ) { + let mut evt = EventEncoder::new("fairroulette.payout"); + evt.encode(&address_to_string(&address)); + evt.encode(&uint64_to_string(amount)); + evt.emit(); + } + + pub fn round(&self, + // current betting round number + number: u32, + ) { + let mut evt = EventEncoder::new("fairroulette.round"); + evt.encode(&uint32_to_string(number)); + evt.emit(); + } + + pub fn start(&self) { + let mut evt = EventEncoder::new("fairroulette.start"); + evt.emit(); + } + + pub fn stop(&self) { + let mut evt = EventEncoder::new("fairroulette.stop"); + evt.emit(); + } + + pub fn winner(&self, + // the winning number + number: u16, + ) { + let mut evt = EventEncoder::new("fairroulette.winner"); + evt.encode(&uint16_to_string(number)); + evt.emit(); + } +} +``` + + + + +```ts +import * as wasmlib from 'wasmlib'; +import * as wasmtypes from 'wasmlib/wasmtypes'; + +export class FairRouletteEvents { + bet( + // address of better + address: wasmtypes.ScAddress, + // amount of tokens to bet + amount: u64, + // number to bet on + number: u16, + ): void { + const evt = new wasmlib.EventEncoder('fairroulette.bet'); + evt.encode(wasmtypes.addressToString(address)); + evt.encode(wasmtypes.uint64ToString(amount)); + evt.encode(wasmtypes.uint16ToString(number)); + evt.emit(); + } + + payout( + // address of winner + address: wasmtypes.ScAddress, + // amount of tokens won + amount: u64, + ): void { + const evt = new wasmlib.EventEncoder('fairroulette.payout'); + evt.encode(wasmtypes.addressToString(address)); + evt.encode(wasmtypes.uint64ToString(amount)); + evt.emit(); + } + + round( + // current betting round number + number: u32, + ): void { + const evt = new wasmlib.EventEncoder('fairroulette.round'); + evt.encode(wasmtypes.uint32ToString(number)); + evt.emit(); + } + + start(): void { + const evt = new wasmlib.EventEncoder('fairroulette.start'); + evt.emit(); + } + + stop(): void { + const evt = new wasmlib.EventEncoder('fairroulette.stop'); + evt.emit(); + } + + winner( + // the winning number + number: u16, + ): void { + const evt = new wasmlib.EventEncoder('fairroulette.winner'); + evt.encode(wasmtypes.uint16ToString(number)); + evt.emit(); + } +} +``` + + + + +Notice how the generated functions use the WasmLib EventEncoder to encode the parameters +into a single string before emitting it. Here is the way in which `fairroulette` emits the +`bet` event in its smart contract code: + + + + + +```go + f.Events.Bet(bet.Better.Address(), bet.Amount, bet.Number) +``` + + + + +```rust + f.events.bet(&bet.better.address(), bet.amount, bet.number); +``` + + + + +```ts +f.events.bet(bet.better.address(), bet.amount, bet.number); +``` + + + + +The smart contract client code can define handler functions to listen in to the event +stream and respond to any events it deems noteworthy. The [Schema Tool](usage.mdx) will +automatically generate the necessary client side code that properly listens for the +events, parses the event strings into a type-safe structure, and passes this structure to +the corresponding handler function. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/funcdesc.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/funcdesc.mdx new file mode 100644 index 00000000000..bb4f18ee046 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/funcdesc.mdx @@ -0,0 +1,404 @@ +--- +tags: + - descriptor + - view + - access + - contract functions + - schema tool + +description: The schema tool provides us with an easy way to get access to smart contract functions through function descriptors, which allow you to initiate the function by calling it synchronously, or posting a request to run it asynchronously. + +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Add Function Descriptors + +You can use the [Schema Tool](usage.mdx) to access, and initiate smart contract functions seamlessly using +function descriptors. +These descriptors allow you to access optional [Params](params.mdx) and [Results](results.mdx) maps through strict +compile-time checked interfaces. + +## Function Descriptors Overview + +Function descriptors are structures that: + +- Offer access to the optional [Params](params.mdx) and [Results](results.mdx) maps. +- Allow synchronous or asynchronous initiation of functions through [`call()`](call.mdx) or [`post()`](post.mdx) requests. + +## The Schema Tool in Action + +The Schema Tool performs the following tasks: + +### 1. **Generate Specific Descriptors**: + +- For each function (`func`) and view. +- The outcome: Structs granting access to [Params](params.mdx) or [Results](results.mdx) maps, wherever specified. + +## 2. **Create the `ScFuncs` Interface**: + +- Facilitate the creation and initialization of each function descriptor. +- Incorporate a member function for every func or view to craft their respective function descriptor properly. + + + + + +```go +package dividend + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" + +type DivideCall struct { + Func *wasmlib.ScFunc +} + +type InitCall struct { + Func *wasmlib.ScInitFunc + Params MutableInitParams +} + +type MemberCall struct { + Func *wasmlib.ScFunc + Params MutableMemberParams +} + +type SetOwnerCall struct { + Func *wasmlib.ScFunc + Params MutableSetOwnerParams +} + +type GetFactorCall struct { + Func *wasmlib.ScView + Params MutableGetFactorParams + Results ImmutableGetFactorResults +} + +type GetOwnerCall struct { + Func *wasmlib.ScView + Results ImmutableGetOwnerResults +} + +type Funcs struct{} + +var ScFuncs Funcs + +// divide tokens over members +func (sc Funcs) Divide(ctx wasmlib.ScFuncCallContext) *DivideCall { + return &DivideCall{Func: wasmlib.NewScFunc(ctx, HScName, HFuncDivide)} +} + +func (sc Funcs) Init(ctx wasmlib.ScFuncCallContext) *InitCall { + f := &InitCall{Func: wasmlib.NewScInitFunc(ctx, HScName, HFuncInit)} + f.Params.proxy = wasmlib.NewCallParamsProxy(&f.Func.ScView) + return f +} + +func (sc Funcs) Member(ctx wasmlib.ScFuncCallContext) *MemberCall { + f := &MemberCall{Func: wasmlib.NewScFunc(ctx, HScName, HFuncMember)} + f.Params.proxy = wasmlib.NewCallParamsProxy(&f.Func.ScView) + return f +} + +func (sc Funcs) SetOwner(ctx wasmlib.ScFuncCallContext) *SetOwnerCall { + f := &SetOwnerCall{Func: wasmlib.NewScFunc(ctx, HScName, HFuncSetOwner)} + f.Params.proxy = wasmlib.NewCallParamsProxy(&f.Func.ScView) + return f +} + +func (sc Funcs) GetFactor(ctx wasmlib.ScViewCallContext) *GetFactorCall { + f := &GetFactorCall{Func: wasmlib.NewScView(ctx, HScName, HViewGetFactor)} + f.Params.proxy = wasmlib.NewCallParamsProxy(f.Func) + wasmlib.NewCallResultsProxy(f.Func, &f.Results.proxy) + return f +} + +func (sc Funcs) GetOwner(ctx wasmlib.ScViewCallContext) *GetOwnerCall { + f := &GetOwnerCall{Func: wasmlib.NewScView(ctx, HScName, HViewGetOwner)} + wasmlib.NewCallResultsProxy(f.Func, &f.Results.proxy) + return f +} +``` + + + + + +```rust +use wasmlib::*; +use crate::*; + +pub struct DivideCall { + pub func: ScFunc, +} + +pub struct InitCall { + pub func: ScInitFunc, + pub params: MutableInitParams, +} + +pub struct MemberCall { + pub func: ScFunc, + pub params: MutableMemberParams, +} + +pub struct SetOwnerCall { + pub func: ScFunc, + pub params: MutableSetOwnerParams, +} + +pub struct GetFactorCall { + pub func: ScView, + pub params: MutableGetFactorParams, + pub results: ImmutableGetFactorResults, +} + +pub struct GetOwnerCall { + pub func: ScView, + pub results: ImmutableGetOwnerResults, +} + +pub struct ScFuncs { +} + +impl ScFuncs { + // divide tokens over members + pub fn divide(_ctx: &dyn ScFuncCallContext) -> DivideCall { + DivideCall { + func: ScFunc::new(HSC_NAME, HFUNC_DIVIDE), + } + } + + pub fn init(_ctx: &dyn ScFuncCallContext) -> InitCall { + let mut f = InitCall { + func: ScInitFunc::new(HSC_NAME, HFUNC_INIT), + params: MutableInitParams { proxy: Proxy::nil() }, + }; + ScInitFunc::link_params(&mut f.params.proxy, &f.func); + f + } + + pub fn member(_ctx: &dyn ScFuncCallContext) -> MemberCall { + let mut f = MemberCall { + func: ScFunc::new(HSC_NAME, HFUNC_MEMBER), + params: MutableMemberParams { proxy: Proxy::nil() }, + }; + ScFunc::link_params(&mut f.params.proxy, &f.func); + f + } + + pub fn set_owner(_ctx: &dyn ScFuncCallContext) -> SetOwnerCall { + let mut f = SetOwnerCall { + func: ScFunc::new(HSC_NAME, HFUNC_SET_OWNER), + params: MutableSetOwnerParams { proxy: Proxy::nil() }, + }; + ScFunc::link_params(&mut f.params.proxy, &f.func); + f + } + + pub fn get_factor(_ctx: &dyn ScViewCallContext) -> GetFactorCall { + let mut f = GetFactorCall { + func: ScView::new(HSC_NAME, HVIEW_GET_FACTOR), + params: MutableGetFactorParams { proxy: Proxy::nil() }, + results: ImmutableGetFactorResults { proxy: Proxy::nil() }, + }; + ScView::link_params(&mut f.params.proxy, &f.func); + ScView::link_results(&mut f.results.proxy, &f.func); + f + } + + pub fn get_owner(_ctx: &dyn ScViewCallContext) -> GetOwnerCall { + let mut f = GetOwnerCall { + func: ScView::new(HSC_NAME, HVIEW_GET_OWNER), + results: ImmutableGetOwnerResults { proxy: Proxy::nil() }, + }; + ScView::link_results(&mut f.results.proxy, &f.func); + f + } +} +``` + + + + +```ts +import * as wasmlib from 'wasmlib'; +import * as sc from './index'; + +export class DivideCall { + func: wasmlib.ScFunc; + public constructor(ctx: wasmlib.ScFuncCallContext) { + this.func = new wasmlib.ScFunc(ctx, sc.HScName, sc.HFuncDivide); + } +} + +export class DivideContext { + state: sc.MutableDividendState = new sc.MutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class InitCall { + func: wasmlib.ScInitFunc; + params: sc.MutableInitParams = new sc.MutableInitParams( + wasmlib.ScView.nilProxy, + ); + public constructor(ctx: wasmlib.ScFuncCallContext) { + this.func = new wasmlib.ScInitFunc(ctx, sc.HScName, sc.HFuncInit); + } +} + +export class InitContext { + params: sc.ImmutableInitParams = new sc.ImmutableInitParams( + wasmlib.paramsProxy(), + ); + state: sc.MutableDividendState = new sc.MutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class MemberCall { + func: wasmlib.ScFunc; + params: sc.MutableMemberParams = new sc.MutableMemberParams( + wasmlib.ScView.nilProxy, + ); + public constructor(ctx: wasmlib.ScFuncCallContext) { + this.func = new wasmlib.ScFunc(ctx, sc.HScName, sc.HFuncMember); + } +} + +export class MemberContext { + params: sc.ImmutableMemberParams = new sc.ImmutableMemberParams( + wasmlib.paramsProxy(), + ); + state: sc.MutableDividendState = new sc.MutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class SetOwnerCall { + func: wasmlib.ScFunc; + params: sc.MutableSetOwnerParams = new sc.MutableSetOwnerParams( + wasmlib.ScView.nilProxy, + ); + public constructor(ctx: wasmlib.ScFuncCallContext) { + this.func = new wasmlib.ScFunc(ctx, sc.HScName, sc.HFuncSetOwner); + } +} + +export class SetOwnerContext { + params: sc.ImmutableSetOwnerParams = new sc.ImmutableSetOwnerParams( + wasmlib.paramsProxy(), + ); + state: sc.MutableDividendState = new sc.MutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class GetFactorCall { + func: wasmlib.ScView; + params: sc.MutableGetFactorParams = new sc.MutableGetFactorParams( + wasmlib.ScView.nilProxy, + ); + results: sc.ImmutableGetFactorResults = new sc.ImmutableGetFactorResults( + wasmlib.ScView.nilProxy, + ); + public constructor(ctx: wasmlib.ScViewCallContext) { + this.func = new wasmlib.ScView(ctx, sc.HScName, sc.HViewGetFactor); + } +} + +export class GetFactorContext { + params: sc.ImmutableGetFactorParams = new sc.ImmutableGetFactorParams( + wasmlib.paramsProxy(), + ); + results: sc.MutableGetFactorResults = new sc.MutableGetFactorResults( + wasmlib.ScView.nilProxy, + ); + state: sc.ImmutableDividendState = new sc.ImmutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class GetOwnerCall { + func: wasmlib.ScView; + results: sc.ImmutableGetOwnerResults = new sc.ImmutableGetOwnerResults( + wasmlib.ScView.nilProxy, + ); + public constructor(ctx: wasmlib.ScViewCallContext) { + this.func = new wasmlib.ScView(ctx, sc.HScName, sc.HViewGetOwner); + } +} + +export class GetOwnerContext { + results: sc.MutableGetOwnerResults = new sc.MutableGetOwnerResults( + wasmlib.ScView.nilProxy, + ); + state: sc.ImmutableDividendState = new sc.ImmutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class ScFuncs { + // divide tokens over members + static divide(ctx: wasmlib.ScFuncCallContext): DivideCall { + return new DivideCall(ctx); + } + + static init(ctx: wasmlib.ScFuncCallContext): InitCall { + const f = new InitCall(ctx); + f.params = new sc.MutableInitParams(wasmlib.newCallParamsProxy(f.func)); + return f; + } + + static member(ctx: wasmlib.ScFuncCallContext): MemberCall { + const f = new MemberCall(ctx); + f.params = new sc.MutableMemberParams(wasmlib.newCallParamsProxy(f.func)); + return f; + } + + static setOwner(ctx: wasmlib.ScFuncCallContext): SetOwnerCall { + const f = new SetOwnerCall(ctx); + f.params = new sc.MutableSetOwnerParams(wasmlib.newCallParamsProxy(f.func)); + return f; + } + + static getFactor(ctx: wasmlib.ScViewCallContext): GetFactorCall { + const f = new GetFactorCall(ctx); + f.params = new sc.MutableGetFactorParams( + wasmlib.newCallParamsProxy(f.func), + ); + f.results = new sc.ImmutableGetFactorResults( + wasmlib.newCallResultsProxy(f.func), + ); + return f; + } + + static getOwner(ctx: wasmlib.ScViewCallContext): GetOwnerCall { + const f = new GetOwnerCall(ctx); + f.results = new sc.ImmutableGetOwnerResults( + wasmlib.newCallResultsProxy(f.func), + ); + return f; + } +} +``` + + + + +## `dividend` Example - Generated Code + +In the `dividend` example in `contract.xx`, specific structs for [Funcs and Views](../../schema/proxies.mdx) are created. +Here's how they operate: + +### Access + +- Via the `func` member within each struct. +- The `func` member type: Either `ScFunc` or `ScView`, contingent on whether it’s a function or a view. + +### Utilization + +- The `func` member is used to initiate function calls in various ways. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/funcs.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/funcs.mdx new file mode 100644 index 00000000000..0c48c6c85ed --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/funcs.mdx @@ -0,0 +1,82 @@ +--- +tags: + - functions + - views + - state + - access + - params + - results + +image: /img/logo/WASP_logo_dark.png +description: The code generated for Funcs will be able to inspect and modify the smart contract state, whereas the code generated for Views will only be able to inspect the state. +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Define Functions + +Here is the full schema definition file for the `dividend` example. We will now focus on +its [`funcs` and `views` sections](../../explanations/context.mdx). Since they are structured identically we will only need +to explain the layout of these sections once. + + + + +```yaml +name: Dividend +description: Simple dividend smart contract +structs: {} +typedefs: {} +state: + memberList: Address[] # array with all the recipients of this dividend + + # factors per member + + members: map[Address]Uint64 # map with all the recipient factors of this dividend + owner: AgentID # owner of contract, the only one who can call 'member' func + totalFactor: Uint64 # sum of all recipient factors +funcs: + # divide tokens over members + divide: {} + init: + params: + owner: AgentID? # optional owner of contract, defaults to contract creator + member: + access: owner # only defined owner of contract can add members + params: + address: Address # address of dividend recipient + factor: Uint64 # relative division factor + setOwner: + access: owner # only defined owner of contract can change owner + params: + owner: AgentID # new owner of smart contract +views: + getFactor: + params: + address: Address # address of dividend recipient + results: + factor: Uint64 # relative division factor + getOwner: + results: + owner: AgentID # current owner of this smart contract +``` + + + + + +As you can see each of the `funcs` and `views` sections defines their functions in the +same way. The only resulting difference is in the way the [Schema Tool](usage.mdx) +generates code for them: + +- The code generated for Funcs will be able to inspect and modify the smart contract state. +- The code generated for Views will only be able to inspect the state. + +Functions are defined as named subsections in the schema definition file. The name of the +subsection will become the name of the function. In turn, there can be 3 optional +subsections under each function subsection. + +- [`access`](access.mdx) indicates who is allowed to access the function. +- `params` holds the field definitions that describe the function parameters. +- `results` holds the field definitions that describe the function results. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/init.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/init.mdx new file mode 100644 index 00000000000..3425089182c --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/init.mdx @@ -0,0 +1,269 @@ +--- +tags: + - init + - initialization + - owner + - initial state + - smart contract creator + - one-time + - contract deployment + +description: The init function will automatically be called immediately after the first time the contract has been deployed to the VM. This is a one-time initialization call, meant to be performed by the contract deployment mechanism. +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Initialize a Smart Contract + +Smart contracts begin with a blank slate. You can define an initial state through the `init()` function. +This function is vital for setting configurations at the time of deployment. + +## Features of the `init()` Function + +### One-time Call + +Triggered automatically post-deployment, **it can only be used once** to set the initial configurations. + +### Security + +The ISC ensures the `init()` function is inaccessible after its initial execution, +safeguarding it from unauthorized accesses. + +### Necessity For a Separate Configuration Function + +To facilitate reconfiguration in the future, develop a distinct configuration function with proper access controls. + +## Usage Example + +To show how creating a smart contract with WasmLib works, we will slowly start fleshing +out the smart contract functions of the `dividend` example in this tutorial. Here is the +first part of the code that implements it, which contains the `init()` function: + + + + + +```go +// This example implements 'dividend', a simple smart contract that will +// automatically disperse iota tokens which are sent to the contract to a group +// of member accounts according to predefined division factors. The intent is +// to showcase basic functionality of WasmLib through a minimal implementation +// and not to come up with a complete robust real-world solution. +// Note that we have drawn sometimes out constructs that could have been done +// in a single line over multiple statements to be able to properly document +// step by step what is happening in the code. We also unnecessarily annotate +// all 'var' statements with their assignment type to improve understanding. + +//nolint:revive,goimports +package dividend + +import ( + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" +) + +// 'init' is used as a way to initialize a smart contract. It is an optional +// function that will automatically be called upon contract deployment. In this +// case we use it to initialize the 'owner' state variable so that we can later +// use this information to prevent non-owners from calling certain functions. +// The 'init' function takes a single optional parameter: +// - 'owner', which is the agent id of the entity owning the contract. +// When this parameter is omitted the owner will default to the contract creator. +func funcInit(ctx wasmlib.ScFuncContext, f *InitContext) { + // The schema tool has already created a proper InitContext for this function that + // allows us to access call parameters and state storage in a type-safe manner. + + // First we set up a default value for the owner in case the optional 'owner' + // parameter was omitted. We use the agent that sent the deploy request. + var owner wasmtypes.ScAgentID = ctx.RequestSender() + + // Now we check if the optional 'owner' parameter is present in the params map. + if f.Params.Owner().Exists() { + // Yes, it was present, so now we overwrite the default owner with + // the one specified by the 'owner' parameter. + owner = f.Params.Owner().Value() + } + + // Now that we have sorted out which agent will be the owner of this contract + // we will save this value in the 'owner' variable in state storage on the host. + // Read the documentation on schema.yaml to understand why this state variable is + // supported at compile-time by code generated from schema.yaml by the schema tool. + f.State.Owner().SetValue(owner) +} +``` + + + + +```rust +// This example implements 'dividend', a simple smart contract that will +// automatically disperse iota tokens which are sent to the contract to a group +// of member accounts according to predefined division factors. The intent is +// to showcase basic functionality of WasmLib through a minimal implementation +// and not to come up with a complete robust real-world solution. +// Note that we have drawn sometimes out constructs that could have been done +// in a single line over multiple statements to be able to properly document +// step by step what is happening in the code. We also unnecessarily annotate +// all 'let' statements with their assignment type to improve understanding. + +use wasmlib::*; + +use crate::*; + +// 'init' is used as a way to initialize a smart contract. It is an optional +// function that will automatically be called upon contract deployment. In this +// case we use it to initialize the 'owner' state variable so that we can later +// use this information to prevent non-owners from calling certain functions. +// The 'init' function takes a single optional parameter: +// - 'owner', which is the agent id of the entity owning the contract. +// When this parameter is omitted the owner will default to the contract creator. +pub fn func_init(ctx: &ScFuncContext, f: &InitContext) { + // The schema tool has already created a proper InitContext for this function that + // allows us to access call parameters and state storage in a type-safe manner. + + // First we set up a default value for the owner in case the optional 'owner' + // parameter was omitted. We use the agent that sent the deploy request. + let mut owner: ScAgentID = ctx.request_sender(); + + // Now we check if the optional 'owner' parameter is present in the params map. + if f.params.owner().exists() { + // Yes, it was present, so now we overwrite the default owner with + // the one specified by the 'owner' parameter. + owner = f.params.owner().value(); + } + + // Now that we have sorted out which agent will be the owner of this contract + // we will save this value in the 'owner' variable in state storage on the host. + // Read the documentation on schema.yaml to understand why this state variable is + // supported at compile-time by code generated from schema.yaml by the schema tool. + f.state.owner().set_value(&owner); +} +``` + + + + +```ts +// This example implements 'dividend', a simple smart contract that will +// automatically disperse iota tokens which are sent to the contract to a group +// of member accounts according to predefined division factors. The intent is +// to showcase basic functionality of WasmLib through a minimal implementation +// and not to come up with a complete robust real-world solution. +// Note that we have drawn sometimes out constructs that could have been done +// in a single line over multiple statements to be able to properly document +// step by step what is happening in the code. We also unnecessarily annotate +// all 'let' statements with their assignment type to improve understanding. + +import * as wasmlib from 'wasmlib'; +import * as sc from './index'; + +// 'init' is used as a way to initialize a smart contract. It is an optional +// function that will automatically be called upon contract deployment. In this +// case we use it to initialize the 'owner' state variable so that we can later +// use this information to prevent non-owners from calling certain functions. +// The 'init' function takes a single optional parameter: +// - 'owner', which is the agent id of the entity owning the contract. +// When this parameter is omitted the owner will default to the contract creator. +export function funcInit(ctx: wasmlib.ScFuncContext, f: sc.InitContext): void { + // The schema tool has already created a proper InitContext for this function that + // allows us to access call parameters and state storage in a type-safe manner. + + // First we set up a default value for the owner in case the optional 'owner' + // parameter was omitted. We use the agent that sent the deploy request. + let owner: wasmlib.ScAgentID = ctx.requestSender(); + + // Now we check if the optional 'owner' parameter is present in the params map. + if (f.params.owner().exists()) { + // Yes, it was present, so now we overwrite the default owner with + // the one specified by the 'owner' parameter. + owner = f.params.owner().value(); + } + + // Now that we have sorted out which agent will be the owner of this contract + // we will save this value in the 'owner' variable in state storage on the host. + // Read the documentation on schema.yaml to understand why this state variable is + // supported at compile-time by code generated from schema.yaml by the schema tool. + f.state.owner().setValue(owner); +} +``` + + + + +We define an owner variable and allow it to be something other than the default value of +the contract creator. It is always a good idea to be flexible enough to transfer +ownership to another entity if necessary. Remember that once a smart contract has been +deployed it is no longer possible to change it. Therefore, it is good practice to think +through situations that could require a change in advance and allow the contract itself to +handle such changes through its state by providing a proper function interface: + + + + + +```go +// 'setOwner' is used to change the owner of the smart contract. +// It updates the 'owner' state variable with the provided agent id. +// The 'setOwner' function takes a single mandatory parameter: +// - 'owner', which is the agent id of the entity that will own the contract. +// Only the current owner can change the owner. +func funcSetOwner(_ wasmlib.ScFuncContext, f *SetOwnerContext) { + // Note that the schema tool has already dealt with making sure that this function + // can only be called by the owner and that the required parameter is present. + // So once we get to this point in the code we can take that as a given. + + // Save the new owner parameter value in the 'owner' variable in state storage. + f.State.Owner().SetValue(f.Params.Owner().Value()) +} +``` + + + + +```rust +// 'setOwner' is used to change the owner of the smart contract. +// It updates the 'owner' state variable with the provided agent id. +// The 'setOwner' function takes a single mandatory parameter: +// - 'owner', which is the agent id of the entity that will own the contract. +// Only the current owner can change the owner. +pub fn func_set_owner(_ctx: &ScFuncContext, f: &SetOwnerContext) { + // Note that the schema tool has already dealt with making sure that this function + // can only be called by the owner and that the required parameter is present. + // So once we get to this point in the code we can take that as a given. + + // Save the new owner parameter value in the 'owner' variable in state storage. + f.state.owner().set_value(&f.params.owner().value()); +} +``` + + + + +```ts +// 'setOwner' is used to change the owner of the smart contract. +// It updates the 'owner' state variable with the provided agent id. +// The 'setOwner' function takes a single mandatory parameter: +// - 'owner', which is the agent id of the entity that will own the contract. +// Only the current owner can change the owner. +export function funcSetOwner( + ctx: wasmlib.ScFuncContext, + f: sc.SetOwnerContext, +): void { + // Note that the schema tool has already dealt with making sure that this function + // can only be called by the owner and that the required parameter is present. + // So once we get to this point in the code we can take that as a given. + + // Save the new owner parameter value in the 'owner' variable in state storage. + f.state.owner().setValue(f.params.owner().value()); +} +``` + + + + +Note that we only define a single owner here. +A proper fall-back could require multiple owners in case the owner entity could disappear, +which would allow others to take over instead of the contract becoming immutable about the “owner functionality”. +We cannot stress enough how important it is to **think through every aspect of a smart contract before deployment**. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/params.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/params.mdx new file mode 100644 index 00000000000..60691771f75 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/params.mdx @@ -0,0 +1,102 @@ +--- +description: "Learn how to define function parameters using the 'params' subsection, and how the Schema Tool facilitates this process." +tags: + - Function Parameters + - Schema Tool + - Params Subsection + - Optional Parameters + - Parameter Proxy +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Define Function Parameters + +You can use the optional [`params`](params.mdx) subsection to specify the parameters a function accepts. +This section can define both mandatory and optional parameters. +Optional parameters are denoted with a question mark `?` following the field type. + +## Schema Tool Automation + +The [Schema Tool](usage.mdx) streamlines the creation of functions by: + +- Generating an immutable structure holding parameter proxies from the [Params](params.mdx) map. +- Checking the presence and data type of non-optional parameters before the function call. + +These functionalities allow users to directly use parameter proxies in the structure passed to the function. + +:::note + +Omitting the `params` subsection results in no structure generation or parameter passing to the function. + +::: + +For example, here is the structure generated for the immutable [Params](params.mdx) for +the `member` function: + + + + + +```go +type ImmutableMemberParams struct { + proxy wasmtypes.Proxy +} + +// address of dividend recipient +func (s ImmutableMemberParams) Address() wasmtypes.ScImmutableAddress { + return wasmtypes.NewScImmutableAddress(s.proxy.Root(ParamAddress)) +} + +// relative division factor +func (s ImmutableMemberParams) Factor() wasmtypes.ScImmutableUint64 { + return wasmtypes.NewScImmutableUint64(s.proxy.Root(ParamFactor)) +} +``` + + + + +```rust +#[derive(Clone)] +pub struct ImmutableMemberParams { + pub(crate) proxy: Proxy, +} + +impl ImmutableMemberParams { + // address of dividend recipient + pub fn address(&self) -> ScImmutableAddress { + ScImmutableAddress::new(self.proxy.root(PARAM_ADDRESS)) + } + + // relative division factor + pub fn factor(&self) -> ScImmutableUint64 { + ScImmutableUint64::new(self.proxy.root(PARAM_FACTOR)) + } +} +``` + + + + +```ts +export class ImmutableMemberParams extends wasmtypes.ScProxy { + // address of dividend recipient + address(): wasmtypes.ScImmutableAddress { + return new wasmtypes.ScImmutableAddress(this.proxy.root(sc.ParamAddress)); + } + + // relative division factor + factor(): wasmtypes.ScImmutableUint64 { + return new wasmtypes.ScImmutableUint64(this.proxy.root(sc.ParamFactor)); + } +} +``` + + + + +The [Schema Tool](usage.mdx) will also generate a mutable version of the structure, +suitable for providing the parameters when calling this smart contract function from any [Call Context](../../explanations/context.mdx). diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/post.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/post.mdx new file mode 100644 index 00000000000..e4ef8b23b4d --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/post.mdx @@ -0,0 +1,99 @@ +--- +tags: + - function descriptor + - return values + - request + - post + - smart contract chain + - Asynchronous function +description: Asynchronous function calls between smart contracts are posted as requests on the Tangle. They allow you to invoke any smart contract function that is not a View on any smart contract chain. +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Post Asynchronous Requests + +Asynchronous requests enable interactions between different contracts. +Learn how to navigate the subtleties of posting asynchronous requests on the Tangle, +and how to effectively manage tokens and delays in execution. + +## Overview of Asynchronous Function Calls + +### Posting Requests on the Tangle + +Asynchronous function calls occur through requests posted on the Tangle. +These calls can invoke any function that is not a [View](views.mdx) on any smart contract chain. + +### Function Descriptor Methods + +To post a request, use the following methods from the function descriptor: + +- `post()`: Posts to the current chain. +- `postToChain()`: Allows specifying the chain through the chain ID parameter. + +### Delayed Execution + +You can set a delay in the execution using the `delay()` method, +enhancing smart contracts with timed actions or time-lock functionalities. + + + + + +```go +eor := ScFuncs.EndOfRound(ctx) +eor.Func.Delay(3600).Post() +``` + + + + +```rust +let eor = ScFuncs::end_of_round(ctx); +eor.func.delay(3600).post(); +``` + + + + +```ts +let eor = sc.ScFuncs.endOfRound(ctx); +eor.func.delay(3600).post(); +``` + + + + +## Managing Tokens in Asynchronous Calls + +### Mandatory Token Transfer + +Asynchronous requests require a minimum token transfer to cover the gas for function call execution. +Unused tokens return to the caller's account on the chain. + +### Specifying Tokens + +You can specify tokens: + +- Explicitly, as in to synchronous calls. +- Automatically, letting WasmLib determine the minimum requisite amount. + +### Prohibited `delay()` with [`call()`](call.mdx) + +Using `delay()` before a [`call()`](call.mdx) will cause a panic due to indeterminate user intentions at compile-time +without substantial overhead. + +## Handling Return Values + +If you need some return values, +you will have to create a mechanism that can do so. +For example, +you can provide a callback chain/contract/function combination as part of the input parameters of the requested function so that upon completion, +that function can asynchronously post the results to the indicated function. +It will require a certain degree of cooperation between both smart contracts. + +### Future Prospects + +Future developments aim to facilitate a generic mechanism for seamless return value communication in asynchronous function calls. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/results.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/results.mdx new file mode 100644 index 00000000000..d80691a6888 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/results.mdx @@ -0,0 +1,85 @@ +--- +image: /img/logo/WASP_logo_dark.png +description: "Understand how to outline function results using the 'results' subsection and how the Schema Tool aids in this process." +tags: + - Function Results + - Schema Tool + - Results Subsection + - Mutable Structure + - Result Variables +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Define Function Results + +You can use the optional `results` subsection to detail the results a function can produce. +This setup aligns with the field definitions seen in the [Params](params.mdx) subsection. + +## Schema Tool Features + +The [Schema Tool](usage.mdx) assists in this setup by: + +- Creating a mutable structure that includes proxies for each result variable found in the [Results](results.mdx) map. +- Enabling users to assign values to result variables via this generated structure during the function call. + +:::note + +If the `results` subsection is not used, no structure will be created or conveyed to the function. + +::: + +For example, here is the structure generated for the mutable results for the `getFactor` +function: + + + + + +```go +type MutableGetFactorResults struct { + proxy wasmtypes.Proxy +} + +// relative division factor +func (s MutableGetFactorResults) Factor() wasmtypes.ScMutableUint64 { + return wasmtypes.NewScMutableUint64(s.proxy.Root(ResultFactor)) +} +``` + + + + +```rust +#[derive(Clone)] +pub struct MutableGetFactorResults { + pub(crate) proxy: Proxy, +} + +impl MutableGetFactorResults { + // relative division factor + pub fn factor(&self) -> ScMutableUint64 { + ScMutableUint64::new(self.proxy.root(RESULT_FACTOR)) + } +} +``` + + + + +```ts +export class MutableGetFactorResults extends wasmtypes.ScProxy { + // relative division factor + factor(): wasmtypes.ScMutableUint64 { + return new wasmtypes.ScMutableUint64(this.proxy.root(sc.ResultFactor)); + } +} +``` + + + + +Note that the [Schema Tool](usage.mdx) will also generate an immutable version of the +structure, suitable for accessing the results after by the caller of this smart contract +function. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/spec.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/spec.mdx new file mode 100644 index 00000000000..1c8c35fee58 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/spec.mdx @@ -0,0 +1,460 @@ +--- +tags: + - spec + - meta-programming + - compile +description: The spec of schema tool and how to develop schema tool. +image: /img/logo/WASP_logo_dark.png +--- + +# Spec + +## Workflow + +1. YAML file would be converted to a tree of `wasp_yaml.Node` +2. Convert the tree to a `model.SchemaDef` object +3. Compile the `model.SchemaDef` object to `model.Schema` object by calling `Compile()` +4. Convert `model.Schema` object to the Smart Contract of targeting languages + +## Types + +### model.SchemaDef + +`model.SchemaDef` is a intermediate object during the Smart Contract generation. An YAML file will be converted to `model.SchemaDef` object. +During the conversion, each YAML attribute except the top-level ones (`name`, `description`, `events`, `structs`, `typedefs`, `state`, `funcs`, `views`) will be converted into `DefElt`. + +Therefore, for YAML tags `name`, `description`, the values of them will be converted into 2 independent `DefElt`. + +``` +name: TestName +description: This is test description +``` + +For keywords that can have multiple values can be seen as either a one layer map (i.e., `typedefs` and `state`) +or two layer map (i.e., `typedefs` and `state`). A one layer map will be converted into `DefMap` which +is a map whose key and value are both `DefElt`. And a two layer map will be converted into `DefMapMap` which +is a map whose key is `DefElt` and value is `DefMap`. + +The definition of `DefElt` is shown as following, + +```go +type DefElt struct { + Val string + Comment string + Line int +} +``` + +It contains the raw value of the YAML attributes (without extracting the information), the comment belongs to the +YAML attribute, and the line number of the YAML attribute. + +Here is an example of one layer map + +```yaml +typedefs: + TestTypedef1: String + TestTypedef2: String +state: + TestState1: Int64[] + TestState2: Int64[] +``` + +And an example of two layer map + +```yaml +structs: + point: + x: Int32 + y: Int32 +funcs: + testFunc: + params: + testFuncParam: Uint64 + results: + testFuncResult: Uint64 +views: + testView: + params: + testViewParam: Uint64 + results: + testViewResult: Uint64 +``` + +Next, schema tool will set each fields in `SchemaDef` variable. + +```go +type SchemaDef struct { + Copyright string + Name DefElt + Description DefElt + Events DefMapMap + Structs DefMapMap + Typedefs DefMap + State DefMap + Funcs FuncDefMap + Views FuncDefMap +} +``` + +### model.Schema + +By calling `Schema.Compile()`, `model.SchemaDef` object will be compiled into `model.Schema`. +During the compilation, schema tool will extract the rules from the YAML attributes. + +Here is the definition of a `Schema` object. + +```go +type Schema struct { + ContractName string + Copyright string + PackageName string + Description string + CoreContracts bool + SchemaTime time.Time + Events []*Struct + Funcs []*Func + Params []*Field + Results []*Field + StateVars []*Field + Structs []*Struct + Typedefs []*Field +} +``` + +And let's take a close look at `Field` object. + +```go +type Field struct { + Name string // external name for this field + Alias string // internal name alias, can be different from Name + Array bool + FldComment string + MapKey string + Optional bool + Type string + BaseType bool + Comment string + Line int // the line number originally in yaml/json file +} +``` + +As you can see `typedefs` was a simple `DefMap`, which consists a map whose key and value are both `DefElt`, +and `DefElt` a simple object contains only raw string of the YAML attribute, comment and line number. +However, after the compilation, information is extracted from the raw string, so do some checks are conducted in this step. + +### Compile + +An emitter is used for filling corresponding values into templates under `tools/schema/generator`. +For how to do meta-programming with emitter, see section [Emitter](#emitter) + +```go +type ( + FieldMap map[string]*Field + FieldMapMap map[string]FieldMap + StringMap map[string]string + StringMapMap map[string]StringMap +) +``` + +## Comments + +### Header Comment and Line Comment + +Header comment has higher priority than the line comment. If there are both header comment and line comment presented at +same YAML attribute, then schema tool will keep only the header comment. + +### Comment Block + +A comment block is a chunk of comment that doesn't have a line break to separate it. Schema tool would take the +header comment that immediately followed by the YAML attribute or the line comment block if header comment block is not +presented. + +Therefore, for the following case + +```yaml +typedefs: + # header comment 1 + # header comment 2 + + # header comment 3 + # header comment 4 + TestTypedef: + String # line comment 1 + # line comment 2 +``` + +only these 2 lines + +```yaml +# header comment 3 +# header comment 4 +``` + +will be kept and presented in the final Smart Contract. + +And the next case + +```yaml +typedefs: + TestTypedef: + String # line comment 1 + # line comment 2 + + # line comment 3 + # line comment 4 +``` + +only these 2 lines + +```yaml +# line comment 1 +# line comment 2 +``` + +will be kept and presented in the final Smart Contract. + +## Emitter + +### Access Keys + +With `$` prepending a key (keys are set in `GenBase.setCommonKeys()`, `GenBase.setFieldKeys()`, `GenBase.setFuncKeys()`), schema tool can access the value of the key in `GenBase.keys` according to the current context. For example, if you want to access lower case package name, you can access it with `$package`. +To dynamically add a new key in templates (under gotemplates, rstemplates, and tstemplates), you can call `$#set` instruction, see section [set](#set) for more information. + +### Key And Plain String Concatenation + +To concatenate a value from accessing key and a plain string, you should use `$+` operator. +For example, here `FuncName` is a key that preserves the name of the function under current context, and we want to concatenate the function name with "Mutable" and "Results". +In other words, we want to do the same task as the following python code and get the result in `result` variable. + +```python +func_name = "..." # function name under current context +result = "Mutable" + func_name + "Results" # concatenate the strings into the result +``` + +In the schema template language, we should call `Mutable$FuncName$+Results`. + +### Instructions + +Keywords follows `$#` are the instructions defined in our schema template language. One thing you should aware, now, all the instruction should be presented at the beginning of each line. In other words, no spaces and characters are allowed to exist ahead of an instruction. +Here is the list of all the instruction keywords. + +- emit +- each +- func +- if +- set + +We are going to introduce how to use each instruction as follows. Or you can check the implementation of `GenBase.emit()` to know how are they implemented in detailed. + +#### emit + +`emit` is using for expanding templates. The syntax of `emit` instruction is + +``` +$#emit template +``` + +Here, `template` is any template which defined under gotemplates,rstemplates). +Templates are defined in `model.StringMap`. In the instruction call of `emit` just simply use the name of the template (the key in `model.StringMap`). +If you want to insert the `copyright` template to a assigned location, then you should call + +``` +$#emit copyright +``` + +#### each + +`each` processes the template for each item in the array. The syntax of `each` instruction is + +``` +$#each array template +``` + +Here `array` is either a predefined keyword (we are going to introduce each of them as follow) or a multi-lines string. +If a multi-lines string is presented, then the multi-lines string will be expanded and append newline escape character of targeting languages in the end of each line. + +##### event + +Iterate the fields in a event. + +##### events + +Iterate all the `events` in the contract. + +##### func + +Iterate all the `funcs` in the contract. + +##### mandatory + +Iterate all the mandatory fields in the current processed function. The mandatory field must be basetype and not an array or a map. + +##### param + +Iterate all the `params` fields in the current processed function. + +##### params + +Iterate all the `params` fields in the current contract. + +##### result + +Iterate all the `results` fields in the current processed function. + +##### results + +Iterate all the `results` fields in the current contract. + +##### state + +Iterate all the `state` in the contract. + +##### struct + +Iterate the fields in a struct. + +##### structs + +Iterate all the `structs` in the contract. + +##### typedef + +Iterate all the typedefs in the contract. + +#### func + +Currently not used. + +#### if + +The syntax of `if` is + +``` +$#if condition template [elseTemplate] +``` + +`if` processes template when the named condition is true, and it processes the optional `elseTemplate` when the named condition is false + +`condition` is either the predefined conditions (explained as following) or a key that may exist in `keys`. +If a key is presented, then `if` instruction would be used for check whether this key exists in `keys` or not. If the key exists, then `if` will return true, otherwise it will return false. + +And here are the predefined conditions. + +##### array + +Is the current processed field an array? + +##### basetype + +Is the current processed field in basetype? `basetype`s are defined in the map `FieldTypes` in `tools/schema/model/field.go`. + +##### core + +Is the current processed contract a core contract? + +##### event + +Does the current processed event have any field? + +##### events + +Is there any event in the current processed contract? + +##### exist + +Does the value of key `proxy` exist? + +##### func + +Is the current processed function a `func` or a `view`? Return true if it is a `func`. + +##### funcs + +Is there any function in the current processed contract? + +##### init + +Is the current function an init function? An init function will automatically be called immediately after the first time the contract has been deployed to the VM. + +##### mandatory + +Is current field a mandatory field? + +##### map + +Is current processed field a map (check if the `currentField.MapKey` is empty)? + +##### mut + +Is the value in key `mut` Mutable? + +##### param + +Does the current processed function have any parameter? + +##### params + +Does the current contract have any `params` field? + +##### ptrs + +Does the current processed function have either `params` or `results`. +This is used for implementing function object in Rust and TypeScript. + +##### result + +Does the current processed function have any return value? + +##### results + +Does the current contract have any `results` field? + +##### state + +Does the current contract have any `state` field? + +##### structs + +Does the current contract have any `structs` field? + +##### this + +Is the alias name of the current processed field `this`? + +##### typedef + +Is the current processed field a `typedef`? + +##### typedefs + +Does the current contract have any `typedefs` field? + +##### view + +Is the current processed function a `view` or a `func`? Return true if it is a `view`. + +##### else + +If you want to process a template under negate condition, then you can call + +``` +$#if condition else elseTemplate +``` + +Here `else` is a predefined empty template, which is defined at[`tools/schema/generator/templates.go`. + +#### set + +`set` is used for To dynamically specify a value to a certain key. The syntax is + +``` +$#set key value +``` + +For example, if you want to dynamically add a new key `initFunc` with the value in key `nil` you can call + +``` +$#set initFunc $nil +``` + +A special key `exist` is used to add a newly generated type. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/state.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/state.mdx new file mode 100644 index 00000000000..70252bfb4a1 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/state.mdx @@ -0,0 +1,187 @@ +--- +tags: + - state + - access + - storage + - key + - data + - value + +description: The smart contract state storage on the host consists of a single key/value map, as long as you access the data in the same way that you used to store it, you will always get valid data back. + +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Define the State + +In smart contract state storage, there is only a single key/value map, +where both the key and value are constituted of raw data bytes. +To ensure the retrieval of valid data, access it in the manner it was stored. + +The [Schema Tool](usage.mdx) facilitates this by generating a type-safe layer +that oversees the consistent utilization of the expected data type during _data storage_ and retrieval. + +## State Section in Schema Definition File + +In the schema definition file the `state` section hosts field definitions, +delineating the variables stored in the state storage. +Each field is defined with a YAML key/value pair, indicating its name and data type. +This pair can optionally be followed by a descriptive comment. + +With these details, the [Schema Tool](usage.mdx) creates specific code to type-safely access state variables. +Take a closer look at the `state` section in the `dividend` example to understand this better: + + + + +```yaml +state: + memberList: Address[] # array with all the recipients of this dividend + + # factors per member + + members: map[Address]Uint64 # map with all the recipient factors of this dividend + owner: AgentID # owner of contract, the only one who can call 'member' func + totalFactor: Uint64 # sum of all recipient factors +``` + + + + +### Simple Variables + +Starting with straightforward state variables, `totalFactor`, +and `owner` are characterized as Uint64 and AgentID, respectively. +These represent predefined [WasmLib value types](../../reference/wasm-lib-data-types.mdx). + +### Arrays and Maps + +Next, the `memberList` variable denoted by empty brackets `[]`, symbolizing an array. +This array accommodates elements of a homogenous predefined Address value type. + +Lastly, the `members` variable, signified as a map with `map[]`, houses keys of a uniform predefined Address type. +Following the brackets, the homogenous value type, here `Uint64`, is mentioned. + + + + + +```go +type MutableDividendState struct { + proxy wasmtypes.Proxy +} + +func (s MutableDividendState) AsImmutable() ImmutableDividendState { + return ImmutableDividendState(s) +} + +// array with all the recipients of this dividend +func (s MutableDividendState) MemberList() ArrayOfMutableAddress { + return ArrayOfMutableAddress{proxy: s.proxy.Root(StateMemberList)} +} + +// map with all the recipient factors of this dividend +func (s MutableDividendState) Members() MapAddressToMutableUint64 { + return MapAddressToMutableUint64{proxy: s.proxy.Root(StateMembers)} +} + +// owner of contract, the only one who can call 'member' func +func (s MutableDividendState) Owner() wasmtypes.ScMutableAgentID { + return wasmtypes.NewScMutableAgentID(s.proxy.Root(StateOwner)) +} + +// sum of all recipient factors +func (s MutableDividendState) TotalFactor() wasmtypes.ScMutableUint64 { + return wasmtypes.NewScMutableUint64(s.proxy.Root(StateTotalFactor)) +} +``` + + + + +```rust +#[derive(Clone)] +pub struct MutableDividendState { + pub(crate) proxy: Proxy, +} + +impl MutableDividendState { + pub fn as_immutable(&self) -> ImmutableDividendState { + ImmutableDividendState { proxy: self.proxy.root("") } + } + + // array with all the recipients of this dividend + pub fn member_list(&self) -> ArrayOfMutableAddress { + ArrayOfMutableAddress { proxy: self.proxy.root(STATE_MEMBER_LIST) } + } + + // map with all the recipient factors of this dividend + pub fn members(&self) -> MapAddressToMutableUint64 { + MapAddressToMutableUint64 { proxy: self.proxy.root(STATE_MEMBERS) } + } + + // owner of contract, the only one who can call 'member' func + pub fn owner(&self) -> ScMutableAgentID { + ScMutableAgentID::new(self.proxy.root(STATE_OWNER)) + } + + // sum of all recipient factors + pub fn total_factor(&self) -> ScMutableUint64 { + ScMutableUint64::new(self.proxy.root(STATE_TOTAL_FACTOR)) + } +} +``` + + + + +```ts +export class MutableDividendState extends wasmtypes.ScProxy { + asImmutable(): sc.ImmutableDividendState { + return new sc.ImmutableDividendState(this.proxy); + } + + // array with all the recipients of this dividend + memberList(): sc.ArrayOfMutableAddress { + return new sc.ArrayOfMutableAddress(this.proxy.root(sc.StateMemberList)); + } + + // map with all the recipient factors of this dividend + members(): sc.MapAddressToMutableUint64 { + return new sc.MapAddressToMutableUint64(this.proxy.root(sc.StateMembers)); + } + + // owner of contract, the only one who can call 'member' func + owner(): wasmtypes.ScMutableAgentID { + return new wasmtypes.ScMutableAgentID(this.proxy.root(sc.StateOwner)); + } + + // sum of all recipient factors + totalFactor(): wasmtypes.ScMutableUint64 { + return new wasmtypes.ScMutableUint64(this.proxy.root(sc.StateTotalFactor)); + } +} +``` + + + + +## Generated Code Overview + +Examining the `state.xx`code, generated by the [Schema Tool](usage.mdx), +you can find the `MutableDividendState` struct. +This interface allows type-safe access to each state variable through mutable [proxies](../../schema/proxies.mdx), +establishing a one-to-one relationship with the `state` section in the schema definition file. + +### Proxy Interfaces + +Note the generated proxy interface named `MutableDividendState` for mutable `dividend` state. +It enables type-safe proxy object access for each corresponding variable. +Moreover, the tool auto-generates intermediate map and array proxy types, +such as `ArrayOfMutableAddress` and `MapAddressToMutableUint64`, +enforcing the utilization of respective homogenous types. + +See the full `state.xx` for more details. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/structs.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/structs.mdx new file mode 100644 index 00000000000..810c2f398b2 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/structs.mdx @@ -0,0 +1,513 @@ +--- +tags: + - functions + - state + - structures + - storage + - named fields + +description: You can use structs directly as a type in state storage definitions and the schema tool will automatically generate the proxy code to access it properly. + +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Structured Data Types + +The [Schema Tool](usage.mdx) allows you to define your structured data types that are +composed of the predefined WasmLib value data types. The tool will generate a struct with +named fields according to the definition in the schema definition file and also will +generate code to serialize and deserialize the structure to a byte array so that it can +be saved as a single unit of data bytes, for example in state storage. + +You can use structs directly as a type in state storage definitions, and the +[Schema Tool](usage.mdx) will automatically generate the proxy code to access and +(de)serialize it properly. + +For example, let's say you are creating a `betting` smart contract. Then, you would want to +store information for each bet. The Bet structure could consist of the bet amount and +time, the number of the item that was bet on, and the agent ID of the one who placed the +bet. And you would keep track of all bets in state storage in an array of Bet structs. To +do so, you would insert the following into the schema definition file: + + + + +```yaml +structs: + Bet: + amount: Int64 # bet amount + better: AgentID # who placed this bet + number: Int32 # number of item we bet on + time: Int64 # timestamp of this bet +state: + bets: Bet[] # all bets that were made in this round +``` + + + + +The [Schema Tool](usage.mdx) will generate the following code in `structs.xx` for the Bet +struct: + + + + + +```go +package betting + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" + +type Bet struct { + // bet amount + Amount int64 + // who placed this bet + Better wasmtypes.ScAgentID + // number of item we bet on + Number int32 + // timestamp of this bet + Time int64 +} + +func NewBetFromBytes(buf []byte) *Bet { + dec := wasmtypes.NewWasmDecoder(buf) + data := &Bet{} + data.Amount = wasmtypes.Int64Decode(dec) + data.Better = wasmtypes.AgentIDDecode(dec) + data.Number = wasmtypes.Int32Decode(dec) + data.Time = wasmtypes.Int64Decode(dec) + dec.Close() + return data +} + +func (o *Bet) Bytes() []byte { + enc := wasmtypes.NewWasmEncoder() + wasmtypes.Int64Encode(enc, o.Amount) + wasmtypes.AgentIDEncode(enc, o.Better) + wasmtypes.Int32Encode(enc, o.Number) + wasmtypes.Int64Encode(enc, o.Time) + return enc.Buf() +} + +type ImmutableBet struct { + proxy wasmtypes.Proxy +} + +func (o ImmutableBet) Exists() bool { + return o.proxy.Exists() +} + +func (o ImmutableBet) Value() *Bet { + return NewBetFromBytes(o.proxy.Get()) +} + +type MutableBet struct { + proxy wasmtypes.Proxy +} + +func (o MutableBet) Delete() { + o.proxy.Delete() +} + +func (o MutableBet) Exists() bool { + return o.proxy.Exists() +} + +func (o MutableBet) SetValue(value *Bet) { + o.proxy.Set(value.Bytes()) +} + +func (o MutableBet) Value() *Bet { + return NewBetFromBytes(o.proxy.Get()) +} +``` + + + + +```rust +use wasmlib::*; + +#[derive(Clone)] +pub struct Bet { + // bet amount + pub amount : i64, + // who placed this bet + pub better : ScAgentID, + // number of item we bet on + pub number : i32, + // timestamp of this bet + pub time : i64, +} + +impl Bet { + pub fn from_bytes(bytes: &[u8]) -> Bet { + let mut dec = WasmDecoder::new(bytes); + Bet { + amount : int64_decode(&mut dec), + better : agent_id_decode(&mut dec), + number : int32_decode(&mut dec), + time : int64_decode(&mut dec), + } + } + + pub fn to_bytes(&self) -> Vec { + let mut enc = WasmEncoder::new(); + int64_encode(&mut enc, self.amount); + agent_id_encode(&mut enc, &self.better); + int32_encode(&mut enc, self.number); + int64_encode(&mut enc, self.time); + enc.buf() + } +} + +#[derive(Clone)] +pub struct ImmutableBet { + pub(crate) proxy: Proxy, +} + +impl ImmutableBet { + pub fn exists(&self) -> bool { + self.proxy.exists() + } + + pub fn value(&self) -> Bet { + Bet::from_bytes(&self.proxy.get()) + } +} + +#[derive(Clone)] +pub struct MutableBet { + pub(crate) proxy: Proxy, +} + +impl MutableBet { + pub fn delete(&self) { + self.proxy.delete(); + } + + pub fn exists(&self) -> bool { + self.proxy.exists() + } + + pub fn set_value(&self, value: &Bet) { + self.proxy.set(&value.to_bytes()); + } + + pub fn value(&self) -> Bet { + Bet::from_bytes(&self.proxy.get()) + } +} +``` + + + + +```ts +import * as wasmtypes from 'wasmlib/wasmtypes'; + +export class Bet { + // bet amount + amount: i64 = 0; + // who placed this bet + better: wasmtypes.ScAgentID = wasmtypes.agentIDFromBytes([]); + // number of item we bet on + number: i32 = 0; + // timestamp of this bet + time: i64 = 0; + + static fromBytes(buf: u8[]): Bet { + const dec = new wasmtypes.WasmDecoder(buf); + const data = new Bet(); + data.amount = wasmtypes.int64Decode(dec); + data.better = wasmtypes.agentIDDecode(dec); + data.number = wasmtypes.int32Decode(dec); + data.time = wasmtypes.int64Decode(dec); + dec.close(); + return data; + } + + bytes(): u8[] { + const enc = new wasmtypes.WasmEncoder(); + wasmtypes.int64Encode(enc, this.amount); + wasmtypes.agentIDEncode(enc, this.better); + wasmtypes.int32Encode(enc, this.number); + wasmtypes.int64Encode(enc, this.time); + return enc.buf(); + } +} + +export class ImmutableBet extends wasmtypes.ScProxy { + exists(): bool { + return this.proxy.exists(); + } + + value(): Bet { + return Bet.fromBytes(this.proxy.get()); + } +} + +export class MutableBet extends wasmtypes.ScProxy { + delete(): void { + this.proxy.delete(); + } + + exists(): bool { + return this.proxy.exists(); + } + + setValue(value: Bet): void { + this.proxy.set(value.bytes()); + } + + value(): Bet { + return Bet.fromBytes(this.proxy.get()); + } +} +``` + + + + +Notice how the generated ImmutableBet and MutableBet proxies use the fromBytes() and +toBytes() (de)serialization code to automatically transform byte arrays into Bet structs. + +The generated code in `state.xx` that implements the state interface is shown here: + + + + + +```go +package betting + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" + +type ArrayOfImmutableBet struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfImmutableBet) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfImmutableBet) GetBet(index uint32) ImmutableBet { + return ImmutableBet{proxy: a.proxy.Index(index)} +} + +type ImmutableBettingState struct { + proxy wasmtypes.Proxy +} + +// all bets that were made in this round +func (s ImmutableBettingState) Bets() ArrayOfImmutableBet { + return ArrayOfImmutableBet{proxy: s.proxy.Root(StateBets)} +} + +// current owner of this smart contract +func (s ImmutableBettingState) Owner() wasmtypes.ScImmutableAgentID { + return wasmtypes.NewScImmutableAgentID(s.proxy.Root(StateOwner)) +} + +type ArrayOfMutableBet struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfMutableBet) AppendBet() MutableBet { + return MutableBet{proxy: a.proxy.Append()} +} + +func (a ArrayOfMutableBet) Clear() { + a.proxy.ClearArray() +} + +func (a ArrayOfMutableBet) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfMutableBet) GetBet(index uint32) MutableBet { + return MutableBet{proxy: a.proxy.Index(index)} +} + +type MutableBettingState struct { + proxy wasmtypes.Proxy +} + +func (s MutableBettingState) AsImmutable() ImmutableBettingState { + return ImmutableBettingState(s) +} + +// all bets that were made in this round +func (s MutableBettingState) Bets() ArrayOfMutableBet { + return ArrayOfMutableBet{proxy: s.proxy.Root(StateBets)} +} + +// current owner of this smart contract +func (s MutableBettingState) Owner() wasmtypes.ScMutableAgentID { + return wasmtypes.NewScMutableAgentID(s.proxy.Root(StateOwner)) +} +``` + + + + +```rust +use wasmlib::*; + +use crate::*; + +#[derive(Clone)] +pub struct ArrayOfImmutableBet { + pub(crate) proxy: Proxy, +} + +impl ArrayOfImmutableBet { + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_bet(&self, index: u32) -> ImmutableBet { + ImmutableBet { proxy: self.proxy.index(index) } + } +} + +#[derive(Clone)] +pub struct ImmutableBettingState { + pub(crate) proxy: Proxy, +} + +impl ImmutableBettingState { + // all bets that were made in this round + pub fn bets(&self) -> ArrayOfImmutableBet { + ArrayOfImmutableBet { proxy: self.proxy.root(STATE_BETS) } + } + + // current owner of this smart contract + pub fn owner(&self) -> ScImmutableAgentID { + ScImmutableAgentID::new(self.proxy.root(STATE_OWNER)) + } +} + +#[derive(Clone)] +pub struct ArrayOfMutableBet { + pub(crate) proxy: Proxy, +} + +impl ArrayOfMutableBet { + + pub fn append_bet(&self) -> MutableBet { + MutableBet { proxy: self.proxy.append() } + } + pub fn clear(&self) { + self.proxy.clear_array(); + } + + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_bet(&self, index: u32) -> MutableBet { + MutableBet { proxy: self.proxy.index(index) } + } +} + +#[derive(Clone)] +pub struct MutableBettingState { + pub(crate) proxy: Proxy, +} + +impl MutableBettingState { + pub fn as_immutable(&self) -> ImmutableBettingState { + ImmutableBettingState { proxy: self.proxy.root("") } + } + + // all bets that were made in this round + pub fn bets(&self) -> ArrayOfMutableBet { + ArrayOfMutableBet { proxy: self.proxy.root(STATE_BETS) } + } + + // current owner of this smart contract + pub fn owner(&self) -> ScMutableAgentID { + ScMutableAgentID::new(self.proxy.root(STATE_OWNER)) + } +} +``` + + + + +```ts +import * as wasmtypes from 'wasmlib/wasmtypes'; +import * as sc from './index'; + +export class ArrayOfImmutableBet extends wasmtypes.ScProxy { + length(): u32 { + return this.proxy.length(); + } + + getBet(index: u32): sc.ImmutableBet { + return new sc.ImmutableBet(this.proxy.index(index)); + } +} + +export class ImmutableBettingState extends wasmtypes.ScProxy { + // all bets that were made in this round + bets(): sc.ArrayOfImmutableBet { + return new sc.ArrayOfImmutableBet(this.proxy.root(sc.StateBets)); + } + + // current owner of this smart contract + owner(): wasmtypes.ScImmutableAgentID { + return new wasmtypes.ScImmutableAgentID(this.proxy.root(sc.StateOwner)); + } +} + +export class ArrayOfMutableBet extends wasmtypes.ScProxy { + appendBet(): sc.MutableBet { + return new sc.MutableBet(this.proxy.append()); + } + + clear(): void { + this.proxy.clearArray(); + } + + length(): u32 { + return this.proxy.length(); + } + + getBet(index: u32): sc.MutableBet { + return new sc.MutableBet(this.proxy.index(index)); + } +} + +export class MutableBettingState extends wasmtypes.ScProxy { + asImmutable(): sc.ImmutableBettingState { + return new sc.ImmutableBettingState(this.proxy); + } + + // all bets that were made in this round + bets(): sc.ArrayOfMutableBet { + return new sc.ArrayOfMutableBet(this.proxy.root(sc.StateBets)); + } + + // current owner of this smart contract + owner(): wasmtypes.ScMutableAgentID { + return new wasmtypes.ScMutableAgentID(this.proxy.root(sc.StateOwner)); + } +} +``` + + + + +The results are ImmutableBettingState and MutableBettingState structures that can +directly interface to the state of the betting contract. + +Note how the comments from the schema definition file have been copied to the code's structure definition and access +functions for the fields. This will allow your development environment to pop up context - sensitive help +for those fields and access functions. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/thunks.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/thunks.mdx new file mode 100644 index 00000000000..76531cd30a1 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/thunks.mdx @@ -0,0 +1,379 @@ +--- +description: 'Learn about thunk functions and how the Schema Tool uses them to facilitate smart contract function calls.' +tags: + - Thunk Functions + - Schema Tool + - Wrapper Function + - Smart Contract Functions + - Type-Safe + - Function Signature + - Code Injection +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Thunk Functions + +In software development, thunk functions are a crucial part of setting up smart contracts correctly, +facilitating type-safety and easy mapping of function names to their actual implementations. + +## Overview + +A thunk is a wrapper function employed to inject code before and/or after a function call. +It helps in adapting functions to meet changing demands. +Through the [Schema Tool](usage.mdx), +thunks are generated to establish correct calls to smart contract functions and to ensure type-safety. +They share a common function signature, fostering a straightforward creation of a function table for generic calls. + +## Role in Wasm + +Working hand in hand with the WebAssembly (Wasm) format, +thunks play a pivotal role in the `lib.xx` component. +Below is how a chunk of a `dividend` smart contract would look (the detailed thunk function content is omitted): + + + + + +```go +var exportMap = wasmlib.ScExportMap{ + Names: []string{ + FuncDivide, + FuncInit, + FuncMember, + FuncSetOwner, + ViewGetFactor, + ViewGetOwner, + }, + Funcs: []wasmlib.ScFuncContextFunction{ + funcDivideThunk, + funcInitThunk, + funcMemberThunk, + funcSetOwnerThunk, + }, + Views: []wasmlib.ScViewContextFunction{ + viewGetFactorThunk, + viewGetOwnerThunk, + }, +} + +func OnDispatch(index int32) { + exportMap.Dispatch(index) +} + +func funcDivideThunk(ctx wasmlib.ScFuncContext) {} +func funcInitThunk(ctx wasmlib.ScFuncContext) {} +func funcMemberThunk(ctx wasmlib.ScFuncContext) {} +func funcSetOwnerThunk(ctx wasmlib.ScFuncContext) {} +func viewGetFactorThunk(ctx wasmlib.ScViewContext) {} +func viewGetOwnerThunk(ctx wasmlib.ScViewContext) {} +``` + + + + +```rust +const EXPORT_MAP: ScExportMap = ScExportMap { + names: &[ + FUNC_DIVIDE, + FUNC_INIT, + FUNC_MEMBER, + FUNC_SET_OWNER, + VIEW_GET_FACTOR, + VIEW_GET_OWNER, + ], + funcs: &[ + func_divide_thunk, + func_init_thunk, + func_member_thunk, + func_set_owner_thunk, + ], + views: &[ + view_get_factor_thunk, + view_get_owner_thunk, + ], +}; + +pub fn on_dispatch(index: i32) { + EXPORT_MAP.dispatch(index); +} + +fn func_divide_thunk(ctx: &ScFuncContext) {} +fn func_init_thunk(ctx: &ScFuncContext) {} +fn func_member_thunk(ctx: &ScFuncContext) {} +fn func_set_owner_thunk(ctx: &ScFuncContext) {} +fn view_get_factor_thunk(ctx: &ScViewContext) {} +fn view_get_owner_thunk(ctx: &ScViewContext) {} +``` + + + + +```ts +const exportMap: wasmlib.ScExportMap = { + names: [ + sc.FuncDivide, + sc.FuncInit, + sc.FuncMember, + sc.FuncSetOwner, + sc.ViewGetFactor, + sc.ViewGetOwner, + ], + funcs: [funcDivideThunk, funcInitThunk, funcMemberThunk, funcSetOwnerThunk], + views: [viewGetFactorThunk, viewGetOwnerThunk], +}; + +export function on_dispatch(index: i32): void { + exportMap.dispatch(index); +} + +function funcDivideThunk(ctx: ScFuncContext) {} +function funcInitThunk(ctx: ScFuncContext) {} +function funcMemberThunk(ctx: ScFuncContext) {} +function funcSetOwnerThunk(ctx: ScFuncContext) {} +function viewGetFactorThunk(ctx: ScViewContext) {} +function viewGetOwnerThunk(ctx: ScViewContext) {} +``` + + + + +## The Dispatch Process + +The central player here is the `OnDispatch()` function, +called by the primary Wasm file, essentially a dynamic link library. +This mechanism keeps the smart contract (SC) code self-contained and versatile, +fitting for both Wasm requirements and direct client-side executions. + +To meet Wasm's demands, we implement `on_load()` and `on_call()` callbacks that collaborate with `OnDispatch()` in the `lib.xx`, +orchestrating a seamless dispatch process. + +### `on_load()` + +The `on_load()` Wasm function will be called by the Wasm VM host upon loading of the Wasm +code. It will inform the host of all the function ids and types (Func or View) that this +smart contract provides. + +### `on_call()` + +When the host needs to call a function of the smart contract it will call the `on_call()` +callback function with the corresponding function id, and then the `on_call()` function +will dispatch the call via the `ScExportMap` mapping table that was generated by the +[Schema Tool](usage.mdx) to the proper associated thunk function. + +## Generated Main Entry Point + +Here is the generated `main.xx` that forms the main entry point for the Wasm code: + + + + + +```go +//go:build wasm +// +build wasm + +package main + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmvmhost/go/wasmvmhost" + +import "github.com/iotaledger/wasp/contracts/wasm/dividend/go/dividend" + +func main() { +} + +func init() { + wasmvmhost.ConnectWasmHost() +} + +//export on_call +func onCall(index int32) { + dividend.OnDispatch(index) +} + +//export on_load +func onLoad() { + dividend.OnDispatch(-1) +} +``` + + + + +```rust +use dividend::*; +use wasmvmhost::*; + +#[no_mangle] +fn on_call(index: i32) { + WasmVmHost::connect(); + on_dispatch(index); +} + +#[no_mangle] +fn on_load() { + WasmVmHost::connect(); + on_dispatch(-1); +} +``` + + + + +```ts +import * as wasmvmhost from 'wasmvmhost'; +import * as sc from './dividend'; + +export function on_call(index: i32): void { + wasmvmhost.WasmVMHost.connect(); + sc.onDispatch(index); +} + +export function on_load(): void { + wasmvmhost.WasmVMHost.connect(); + sc.onDispatch(-1); +} +``` + + + + +Finally, here is an example implementation of a thunk function for the `setOwner()` +contract function. You can examine the other thunk functions that all follow the same +pattern in the generated `lib.xx`: + + + + + +```go +type SetOwnerContext struct { + Params ImmutableSetOwnerParams + State MutableDividendState +} + +func funcSetOwnerThunk(ctx wasmlib.ScFuncContext) { + ctx.Log("dividend.funcSetOwner") + f := &SetOwnerContext{ + Params: ImmutableSetOwnerParams{ + proxy: wasmlib.NewParamsProxy(), + }, + State: MutableDividendState{ + proxy: wasmlib.NewStateProxy(), + }, + } + + // only defined owner of contract can change owner + access := f.State.Owner() + ctx.Require(access.Exists(), "access not set: owner") + ctx.Require(ctx.Caller() == access.Value(), "no permission") + + ctx.Require(f.Params.Owner().Exists(), "missing mandatory owner") + funcSetOwner(ctx, f) + ctx.Log("dividend.funcSetOwner ok") +} +``` + + + + +```rust +pub struct SetOwnerContext { + params: ImmutableSetOwnerParams, + state: MutableDividendState, +} + +fn func_set_owner_thunk(ctx: &ScFuncContext) { + ctx.log("dividend.funcSetOwner"); + let f = SetOwnerContext { + params: ImmutableSetOwnerParams { proxy: params_proxy() }, + state: MutableDividendState { proxy: state_proxy() }, + }; + + // only defined owner of contract can change owner + let access = f.state.owner(); + ctx.require(access.exists(), "access not set: owner"); + ctx.require(ctx.caller() == access.value(), "no permission"); + + ctx.require(f.params.owner().exists(), "missing mandatory owner"); + func_set_owner(ctx, &f); + ctx.log("dividend.funcSetOwner ok"); +} +``` + + + + +```ts +// this class is actually defined in contract.ts +export class SetOwnerContext { + params: sc.ImmutableSetOwnerParams = new sc.ImmutableSetOwnerParams( + wasmlib.paramsProxy(), + ); + state: sc.MutableDividendState = new sc.MutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +function funcSetOwnerThunk(ctx: wasmlib.ScFuncContext): void { + ctx.log('dividend.funcSetOwner'); + let f = new sc.SetOwnerContext(); + + // only defined owner of contract can change owner + const access = f.state.owner(); + ctx.require(access.exists(), 'access not set: owner'); + ctx.require(ctx.caller().equals(access.value()), 'no permission'); + + ctx.require(f.params.owner().exists(), 'missing mandatory owner'); + sc.funcSetOwner(ctx, f); + ctx.log('dividend.funcSetOwner ok'); +} +``` + + + + +## The Thunk Function in Action + +### Log the Contract and Function Name + +First, the thunk logs the contract and function name to show that the call has started. + +### Set Up Strongly Typed Context + +Then it sets up a strongly typed function-specific context structure. First, we add the +function-specific immutable [Params](params.mdx) interface structure, which is only +present when the function can have parameters. Then we add the contract-specific +[State](state.mdx) interface structure. In this case, it is mutable because setOwner is a +[Func](funcs.mdx). For [Views](views.mdx), this would be an immutable state interface. +Finally, we would add the function-specific mutable [Results](results.mdx) interface +structure, which is only present when the function returns results. +This is not the case for this `setOwner()` function. + +### Set Up Access Control + +Next, it sets up access control for the function according to the schema definition file. +In this case, it retrieves the `owner` state variable through the function context, +requires that the variable exists, and then requires that the function's `caller()` +equals that value. Any failing requirement will panic out of the thunk function with an +error message. So, this code ensures that only the contract owner can call this +function. + +### Verify Function Parameters + +Now we get to the point where we can use the function-specific [Params](params.mdx) +interface to check for mandatory parameters. Each mandatory parameter is required to +exist, or else we will panic out of the thunk function with an error message. + +### Call the Smart Contract Function + +With the setup and automated checks completed, we now call the actual smart contract +function implementation the user maintains. +After this function has been completed, +we would process the returned results for those functions that have any (in this case, we +don't have results). +Finally, we log that the contract function has been completed +successfully. Remember that any error within the user function will cause a panic, so this +logging will never occur in case that happens. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/transfers.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/transfers.mdx new file mode 100644 index 00000000000..8e9e2447797 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/transfers.mdx @@ -0,0 +1,242 @@ +--- +description: 'Explore methods in the Call Context that facilitate the handling and transfer of asset balances in smart contracts using the `dividend` example.' +tags: + - Call Context + - Asset Balances + - ScBalances Proxy + - ScTransfer Proxy + - Dividend Smart Contract +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Transfer Tokens + +The [Call Context](../../explanations/context.mdx) in smart contracts introduces two vital methods - +`balances()` and `allowance()` - to manage token balances efficiently. +Understanding how to use these can be foundational in setting up smart contracts, +as demonstrated in the `dividend` smart contract example. + +## Methods Overview + +### 1. **`balances()` Method**: + +- **Functionality**: Fetch the present asset balances regulated by the smart contract. +- **Access**: Through the `ScBalances` proxy. + +### 2. **`allowance()` Method**: + +- **Functionality**: Verify the caller assets that the current smart contract function can use. +- **Transfer Requirement**: Assets are not automatically transferred; + the function must instigate the transfer explicitly within the allowed limit. +- **Access**: Through the `ScBalances` proxy. + +### 3. **`transfer_allowed()` Method**: + +- **Functionality**: Facilitate asset transfers from the caller's on-chain account to another on-chain account. +- **Proxy**: uses the `ScTransfer` proxy, a mutable variant of `ScBalances`. +- **Application**: In the `dividend` contract, it aids in distributing iotas to member accounts. + +## Dividend Smart Contract Example + +The `dividend` smart contract operates on a principle of equitable asset distribution to its members based on predefined factors. +Here's how it works: + +1. **Setup**: Establish a list of members with associated address/factor pairs and calculate the total factor sum. +2. **Function**: The `divide()` function manages the dividend distribution. +3. **Dividend Allocation**: + - **Input**: Iotas sent to the `divide()` function. + - **Distribution**: Proportional to the individual's factor. + - **Example**: For factors A:50, B:30, and C:20 (total 100): + - **A receives**: 50/100 of the input iotas. + - **B receives**: 30/100 of the input iotas. + - **C receives**: 20/100 of the input iotas. + +In this system, asset distribution is transparent, fair, and automated, ensuring a streamlined division process. + +Here is the `divide` function: + + + + + +```go +// 'divide' is a function that will take any iotas it receives and properly +// disperse them to the accounts in the member list according to the dispersion +// factors associated with these accounts. +// Anyone can send iotas to this function and they will automatically be +// divided over the member list. Note that this function does not deal with +// fractions. It simply truncates the calculated amount to the nearest lower +// integer and keeps any remaining tokens in the sender account. +func funcDivide(ctx wasmlib.ScFuncContext, f *DivideContext) { + // Create an ScBalances proxy to the allowance balances for this + // smart contract. + var allowance *wasmlib.ScBalances = ctx.Allowance() + + // Retrieve the amount of plain iota tokens from the account balance. + var amount uint64 = allowance.BaseTokens() + + // Retrieve the pre-calculated totalFactor value from the state storage. + var totalFactor uint64 = f.State.TotalFactor().Value() + + // Get the proxy to the 'members' map in the state storage. + var members MapAddressToMutableUint64 = f.State.Members() + + // Get the proxy to the 'memberList' array in the state storage. + var memberList ArrayOfMutableAddress = f.State.MemberList() + + // Determine the current length of the memberList array. + var size uint32 = memberList.Length() + + // Loop through all indexes of the memberList array. + for i := uint32(0); i < size; i++ { + // Retrieve the next indexed address from the memberList array. + var address wasmtypes.ScAddress = memberList.GetAddress(i).Value() + + // Retrieve the factor associated with the address from the members map. + var factor uint64 = members.GetUint64(address).Value() + + // Calculate the fair share of tokens to disperse to this member based on the + // factor we just retrieved. Note that the result will been truncated. + var share uint64 = amount * factor / totalFactor + + // Is there anything to disperse to this member? + if share > 0 { + // Yes, so let's set up an ScTransfer map proxy that transfers the + // calculated amount of tokens. + var transfer *wasmlib.ScTransfer = wasmlib.NewScTransferBaseTokens(share) + + // Perform the actual transfer of tokens from the caller allowance + // to the member account. + ctx.TransferAllowed(address.AsAgentID(), transfer) + } + } +} +``` + + + + +```rust +// 'divide' is a function that will take any iotas it receives and properly +// disperse them to the accounts in the member list according to the dispersion +// factors associated with these accounts. +// Anyone can send iotas to this function and they will automatically be +// divided over the member list. Note that this function does not deal with +// fractions. It simply truncates the calculated amount to the nearest lower +// integer and keeps any remaining tokens in its own account. They will be added +// to any next round of tokens received prior to calculation of the new +// dividend amounts. +pub fn func_divide(ctx: &ScFuncContext, f: &DivideContext) { + + // Create an ScBalances proxy to the allowance balances for this + // smart contract. + let allowance: ScBalances = ctx.allowance(); + + // Retrieve the amount of plain iota tokens from the account balance. + let amount: u64 = allowance.base_tokens(); + + // Retrieve the pre-calculated totalFactor value from the state storage. + let total_factor: u64 = f.state.total_factor().value(); + + // Get the proxy to the 'members' map in the state storage. + let members: MapAddressToMutableUint64 = f.state.members(); + + // Get the proxy to the 'memberList' array in the state storage. + let member_list: ArrayOfMutableAddress = f.state.member_list(); + + // Determine the current length of the memberList array. + let size: u32 = member_list.length(); + + // Loop through all indexes of the memberList array. + for i in 0..size { + // Retrieve the next indexed address from the memberList array. + let address: ScAddress = member_list.get_address(i).value(); + + // Retrieve the factor associated with the address from the members map. + let factor: u64 = members.get_uint64(&address).value(); + + // Calculate the fair share of tokens to disperse to this member based on the + // factor we just retrieved. Note that the result will be truncated. + let share: u64 = amount * factor / total_factor; + + // Is there anything to disperse to this member? + if share > 0 { + // Yes, so let's set up an ScTransfer map proxy that transfers the + // calculated amount of tokens. + let transfers: ScTransfer = ScTransfer::base_tokens(share); + + // Perform the actual transfer of tokens from the caller allowance + // to the member account. + ctx.transfer_allowed(&address.as_agent_id(), &transfers, true); + } + } +} +``` + + + + +```ts +// 'divide' is a function that will take any iotas it receives and properly +// disperse them to the accounts in the member list according to the dispersion +// factors associated with these accounts. +// Anyone can send iotas to this function and they will automatically be +// divided over the member list. Note that this function does not deal with +// fractions. It simply truncates the calculated amount to the nearest lower +// integer and keeps any remaining tokens in its own account. They will be added +// to any next round of tokens received prior to calculation of the new +// dividend amounts. +export function funcDivide( + ctx: wasmlib.ScFuncContext, + f: sc.DivideContext, +): void { + // Create an ScBalances proxy to the allowance balances for this + // smart contract. + let allowance: wasmlib.ScBalances = ctx.allowance(); + + // Retrieve the allowed amount of plain iota tokens from the account balance. + let amount: u64 = allowance.baseTokens(); + + // Retrieve the pre-calculated totalFactor value from the state storage. + let totalFactor: u64 = f.state.totalFactor().value(); + + // Get the proxy to the 'members' map in the state storage. + let members: sc.MapAddressToMutableUint64 = f.state.members(); + + // Get the proxy to the 'memberList' array in the state storage. + let memberList: sc.ArrayOfMutableAddress = f.state.memberList(); + + // Determine the current length of the memberList array. + let size: u32 = memberList.length(); + + // Loop through all indexes of the memberList array. + for (let i: u32 = 0; i < size; i++) { + // Retrieve the next indexed address from the memberList array. + let address: wasmlib.ScAddress = memberList.getAddress(i).value(); + + // Retrieve the factor associated with the address from the members map. + let factor: u64 = members.getUint64(address).value(); + + // Calculate the fair share of tokens to disperse to this member based on the + // factor we just retrieved. Note that the result will be truncated. + let share: u64 = (amount * factor) / totalFactor; + + // Is there anything to disperse to this member? + if (share > 0) { + // Yes, so let's set up an ScTransfer proxy that transfers the + // calculated amount of tokens. + let transfers: wasmlib.ScTransfer = wasmlib.ScTransfer.baseTokens(share); + + // Perform the actual transfer of tokens from the caller allowance + // to the member account. + ctx.transferAllowed(address.asAgentID(), transfers); + } + } +} +``` + + + diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/typedefs.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/typedefs.mdx new file mode 100644 index 00000000000..2d55e859696 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/typedefs.mdx @@ -0,0 +1,456 @@ +--- +tags: + - containers + - types + - container types + - single type + - array + - schema definition file + +description: You can add a typedefs section to the schema definition file, where you can define a single type name for a container type. This way you can easily create containers that contain container types. + +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Type Definitions + +:::note WasmLib Types + +You can find the complete list of [WasmLib Data Types](../../reference/wasm-lib-data-types.mdx) in the reference section. + +::: + +The WasmLib allows of [container types](../../schema/proxies.mdx#container-proxies), but it +is not possible to specify these types directly because the type name syntax only allows +you to specify a single container type. + +There is a simple solution to this problem. You can add a `typedefs` section to the schema +definition file, where you can define a single type name for a container type. That way +you can easily create containers that contain such container types. The +[Schema Tool](usage.mdx) will automatically generate the in-between proxy types necessary +to make this work. + +To keep it at the `betting` smart contract from [the previous section](structs.mdx), +imagine you want to keep track of all betting rounds. Since a betting round contains an +array of all bets in a round, if it weren't for typedefs you could not define it easily. + +Instead, now you add the following to your schema definition file: + + + + +```yaml +typedefs: + BettingRound: Bet[] // one round of bets +state: + rounds: BettingRound[] // keep track of all betting rounds +``` + + + + +The [Schema Tool](usage.mdx) will generate the following code in `typedefs.xx` for the +`BettingRound` type: + + + + + +```go +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" + +type ArrayOfImmutableBet struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfImmutableBet) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfImmutableBet) GetBet(index uint32) ImmutableBet { + return ImmutableBet{proxy: a.proxy.Index(index)} +} + +type ImmutableBettingRound = ArrayOfImmutableBet + +type ArrayOfMutableBet struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfMutableBet) AppendBet() MutableBet { + return MutableBet{proxy: a.proxy.Append()} +} + +func (a ArrayOfMutableBet) Clear() { + a.proxy.ClearArray() +} + +func (a ArrayOfMutableBet) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfMutableBet) GetBet(index uint32) MutableBet { + return MutableBet{proxy: a.proxy.Index(index)} +} + +type MutableBettingRound = ArrayOfMutableBet +``` + + + + +```rust +use wasmlib::*; +use crate::*; + +#[derive(Clone)] +pub struct ArrayOfImmutableBet { + pub(crate) proxy: Proxy, +} + +impl ArrayOfImmutableBet { + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_bet(&self, index: u32) -> ImmutableBet { + ImmutableBet { proxy: self.proxy.index(index) } + } +} + +pub type ImmutableBettingRound = ArrayOfImmutableBet; + +#[derive(Clone)] +pub struct ArrayOfMutableBet { + pub(crate) proxy: Proxy, +} + +impl ArrayOfMutableBet { + + pub fn append_bet(&self) -> MutableBet { + MutableBet { proxy: self.proxy.append() } + } + pub fn clear(&self) { + self.proxy.clear_array(); + } + + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_bet(&self, index: u32) -> MutableBet { + MutableBet { proxy: self.proxy.index(index) } + } +} + +pub type MutableBettingRound = ArrayOfMutableBet; +``` + + + + +```ts +import * as wasmtypes from 'wasmlib/wasmtypes'; +import * as sc from './index'; + +export class ArrayOfImmutableBet extends wasmtypes.ScProxy { + length(): u32 { + return this.proxy.length(); + } + + getBet(index: u32): sc.ImmutableBet { + return new sc.ImmutableBet(this.proxy.index(index)); + } +} + +export class ImmutableBettingRound extends ArrayOfImmutableBet {} + +export class ArrayOfMutableBet extends wasmtypes.ScProxy { + appendBet(): sc.MutableBet { + return new sc.MutableBet(this.proxy.append()); + } + + clear(): void { + this.proxy.clearArray(); + } + + length(): u32 { + return this.proxy.length(); + } + + getBet(index: u32): sc.MutableBet { + return new sc.MutableBet(this.proxy.index(index)); + } +} + +export class MutableBettingRound extends ArrayOfMutableBet {} +``` + + + + +Note how `ImmutableBettingRound` and `MutableBettingRound` type aliases are created +for the types `ArrayOfImmutableBet` and `ArrayOfMutableBet`. These are subsequently used +in the state definition that is generated in `state.xx`: + + + + + +```go +package betting + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" + +type ArrayOfImmutableBettingRound struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfImmutableBettingRound) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfImmutableBettingRound) GetBettingRound(index uint32) ImmutableBettingRound { + return ImmutableBettingRound{proxy: a.proxy.Index(index)} +} + +type ImmutableBettingState struct { + proxy wasmtypes.Proxy +} + +// all bets that were made in this round +func (s ImmutableBettingState) Bets() ArrayOfImmutableBet { + return ArrayOfImmutableBet{proxy: s.proxy.Root(StateBets)} +} + +// current owner of this smart contract +func (s ImmutableBettingState) Owner() wasmtypes.ScImmutableAgentID { + return wasmtypes.NewScImmutableAgentID(s.proxy.Root(StateOwner)) +} + +func (s ImmutableBettingState) Rounds() ArrayOfImmutableBettingRound { + return ArrayOfImmutableBettingRound{proxy: s.proxy.Root(StateRounds)} +} + +type ArrayOfMutableBettingRound struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfMutableBettingRound) AppendBettingRound() MutableBettingRound { + return MutableBettingRound{proxy: a.proxy.Append()} +} + +func (a ArrayOfMutableBettingRound) Clear() { + a.proxy.ClearArray() +} + +func (a ArrayOfMutableBettingRound) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfMutableBettingRound) GetBettingRound(index uint32) MutableBettingRound { + return MutableBettingRound{proxy: a.proxy.Index(index)} +} + +type MutableBettingState struct { + proxy wasmtypes.Proxy +} + +func (s MutableBettingState) AsImmutable() ImmutableBettingState { + return ImmutableBettingState(s) +} + +// all bets that were made in this round +func (s MutableBettingState) Bets() ArrayOfMutableBet { + return ArrayOfMutableBet{proxy: s.proxy.Root(StateBets)} +} + +// current owner of this smart contract +func (s MutableBettingState) Owner() wasmtypes.ScMutableAgentID { + return wasmtypes.NewScMutableAgentID(s.proxy.Root(StateOwner)) +} + +func (s MutableBettingState) Rounds() ArrayOfMutableBettingRound { + return ArrayOfMutableBettingRound{proxy: s.proxy.Root(StateRounds)} +} +``` + + + + +```rust +use wasmlib::*; + +use crate::*; + +#[derive(Clone)] +pub struct ArrayOfImmutableBettingRound { + pub(crate) proxy: Proxy, +} + +impl ArrayOfImmutableBettingRound { + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_betting_round(&self, index: u32) -> ImmutableBettingRound { + ImmutableBettingRound { proxy: self.proxy.index(index) } + } +} + +#[derive(Clone)] +pub struct ImmutableBettingState { + pub(crate) proxy: Proxy, +} + +impl ImmutableBettingState { + // all bets that were made in this round + pub fn bets(&self) -> ArrayOfImmutableBet { + ArrayOfImmutableBet { proxy: self.proxy.root(STATE_BETS) } + } + + // current owner of this smart contract + pub fn owner(&self) -> ScImmutableAgentID { + ScImmutableAgentID::new(self.proxy.root(STATE_OWNER)) + } + + pub fn rounds(&self) -> ArrayOfImmutableBettingRound { + ArrayOfImmutableBettingRound { proxy: self.proxy.root(STATE_ROUNDS) } + } +} + +#[derive(Clone)] +pub struct ArrayOfMutableBettingRound { + pub(crate) proxy: Proxy, +} + +impl ArrayOfMutableBettingRound { + + pub fn append_betting_round(&self) -> MutableBettingRound { + MutableBettingRound { proxy: self.proxy.append() } + } + pub fn clear(&self) { + self.proxy.clear_array(); + } + + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_betting_round(&self, index: u32) -> MutableBettingRound { + MutableBettingRound { proxy: self.proxy.index(index) } + } +} + +#[derive(Clone)] +pub struct MutableBettingState { + pub(crate) proxy: Proxy, +} + +impl MutableBettingState { + pub fn as_immutable(&self) -> ImmutableBettingState { + ImmutableBettingState { proxy: self.proxy.root("") } + } + + // all bets that were made in this round + pub fn bets(&self) -> ArrayOfMutableBet { + ArrayOfMutableBet { proxy: self.proxy.root(STATE_BETS) } + } + + // current owner of this smart contract + pub fn owner(&self) -> ScMutableAgentID { + ScMutableAgentID::new(self.proxy.root(STATE_OWNER)) + } + + pub fn rounds(&self) -> ArrayOfMutableBettingRound { + ArrayOfMutableBettingRound { proxy: self.proxy.root(STATE_ROUNDS) } + } +} +``` + + + + +```ts +import * as wasmtypes from 'wasmlib/wasmtypes'; +import * as sc from './index'; + +export class ArrayOfImmutableBettingRound extends wasmtypes.ScProxy { + length(): u32 { + return this.proxy.length(); + } + + getBettingRound(index: u32): sc.ImmutableBettingRound { + return new sc.ImmutableBettingRound(this.proxy.index(index)); + } +} + +export class ImmutableBettingState extends wasmtypes.ScProxy { + // all bets that were made in this round + bets(): sc.ArrayOfImmutableBet { + return new sc.ArrayOfImmutableBet(this.proxy.root(sc.StateBets)); + } + + // current owner of this smart contract + owner(): wasmtypes.ScImmutableAgentID { + return new wasmtypes.ScImmutableAgentID(this.proxy.root(sc.StateOwner)); + } + + rounds(): sc.ArrayOfImmutableBettingRound { + return new sc.ArrayOfImmutableBettingRound(this.proxy.root(sc.StateRounds)); + } +} + +export class ArrayOfMutableBettingRound extends wasmtypes.ScProxy { + appendBettingRound(): sc.MutableBettingRound { + return new sc.MutableBettingRound(this.proxy.append()); + } + + clear(): void { + this.proxy.clearArray(); + } + + length(): u32 { + return this.proxy.length(); + } + + getBettingRound(index: u32): sc.MutableBettingRound { + return new sc.MutableBettingRound(this.proxy.index(index)); + } +} + +export class MutableBettingState extends wasmtypes.ScProxy { + asImmutable(): sc.ImmutableBettingState { + return new sc.ImmutableBettingState(this.proxy); + } + + // all bets that were made in this round + bets(): sc.ArrayOfMutableBet { + return new sc.ArrayOfMutableBet(this.proxy.root(sc.StateBets)); + } + + // current owner of this smart contract + owner(): wasmtypes.ScMutableAgentID { + return new wasmtypes.ScMutableAgentID(this.proxy.root(sc.StateOwner)); + } + + rounds(): sc.ArrayOfMutableBettingRound { + return new sc.ArrayOfMutableBettingRound(this.proxy.root(sc.StateRounds)); + } +} +``` + + + + +Notice how the `rounds()` member function returns a proxy to an array of `BettingRound`. +Which in turn is an array of `Bet`. So, the desired result has been achieved. And every +access step only allows you to take the path laid out, which is checked at +compile-time. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/usage.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/usage.mdx new file mode 100644 index 00000000000..4114e328ccc --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/usage.mdx @@ -0,0 +1,302 @@ +--- +tags: + - functions + - schema tool + - definition file + - Rust + - Go + - init + - json + - yml + +description: The `schema` tool will assist in creating a smart contract as unobtrusively as possible. +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Use the Schema Tool + +Creating smart contracts is simplified using the _Schema Tool_. +This guide outlines the initial steps to set up a new smart contract from scratch. + +## Step 1: Establish a Central Folder + +Select a central folder to house all your smart contracts. +You'll create a separate subfolder for each contract within this central repository. + +Next, choose a descriptive, capitalized camel case name for your contract, like `MySmartContract`. + +## Step 2: Create a Subfolder + +After naming your smart contract, you should create a corresponding subfolder. +Open your terminal, navigate to the central folder, +and initialize your project with the Schema Tool using the following command: + +```shell +schema -init MySmartContract +``` + +This command will create a subfolder named `mysmartcontract` and generate an initial YAML +schema definition file inside this subfolder. Note that the generated subfolder name is +all lower-case. This is to conform to best practices for package names in most languages. +The generated schema definition file looks like this: + + + + +```yaml +name: MySmartContract +description: MySmartContract description +events: {} +structs: {} +typedefs: {} +state: + owner: AgentID // current owner of this smart contract +funcs: + init: + params: + owner: AgentID? // optional owner of this smart contract + setOwner: + access: owner // current owner of this smart contract + params: + owner: AgentID // new owner of this smart contract +views: + getOwner: + results: + owner: AgentID // current owner of this smart contract +``` + + + + +After initializing your project with the Schema Tool, +a pre-populated schema definition file will be generated in the `mysmartcontract` subfolder. +This file contains the necessary sections and functions to manage your smart contract's ownership. + +## Naming Conventions + +Ensure to follow the _camel case_ naming convention in the schema definition file. Here is how to use it: + +- Function and variable names: start with a lowercase letter (e.g., `myFunction`) +- Type names: start with an uppercase letter (e.g., `MyType`) + +## Customizing Fields + +Begin by updating the `description` field with a relevant description of your smart contract. +It is the perfect time to add any known definitions to the necessary sections. + +## Generating Initial Code + +Navigate to your `mysmartcontract` subfolder to generate the initial code for your preferred programming language using +the Schema Tool. + + + + + +If you want to generate Go code, you should run the schema tool with the `-go` option like +this: + +```shell +schema -go +``` + + + + +If you want to generate Rust code, you should run the schema tool with the `-rs` option +like this: + +```shell +schema -rs +``` + + + + +If you want to generate TypeScript code, you should run the schema tool with the `-ts` +option like this: + +```shell +schema -ts +``` + + + + +If you want to generate more than one language your can simply specify multiple options. +For example, to generate both Rust and Go code you would specify both options like this: + +```shell +schema -rs -go +``` + +The schema tool will generate a complete set of source files for the desired language(s), +that will compile successfully into a Wasm code file. You compile these as follows: + + + + + +```shell +tinygo build -target wasm go/main.go +``` + +This will use the Go source files in the go/mysmartcontract subfolder. The only file in +this folder that you should edit manually is `mysmartcontract.go`. All other source files +will be regenerated and overwritten whenever the schema tool is run again. + +See the [TinyGo](https://tinygo.org/) documentation for more build options. + + + + +After generating the Rust code, you should first modify the Cargo.toml file to your +liking, and potentially add the new project to a Rust workspace. Cargo.toml will not be +regenerated once it already exists. Then build the code as follows: + +```shell +wasm-pack build +``` + +This will use Rust source files in the `src` subfolder. The only file in this folder that +you should edit manually is `mysmartcontract.rs`. All other source files will be +regenerated and overwritten whenever the schema tool is run again. + +See the [wasm-pack](https://rustwasm.github.io/wasm-pack/) documentation for more build +options. + + + + +```shell +npx asc ts/mysmartcontract/lib.ts --outFile mysmartcontract_ts.wasm --lib path/to/node_modules +``` + +This will use the TypeScript source files in the ts/mysmartcontract subfolder. The only +file in this folder that you should edit manually is `mysmartcontract.ts`. All other +source files will be regenerated and overwritten whenever the schema tool is run again. + +See the [AssemblyScript](https://www.assemblyscript.org/) documentation for more build +options. + + + + +The generated code is essentially identical for each language, barring some language +idiosyncrasy differences. Just view different language files with the same name next to, +each other, and you will see what we mean. + +Here is an example of the initially generated code, `mysmartcontract.xx` looks like this +before you even start modifying it: + + + + + +```go +package mysmartcontract + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" + + +func funcInit(ctx wasmlib.ScFuncContext, f *InitContext) { + if f.Params.Owner().Exists() { + f.State.Owner().SetValue(f.Params.Owner().Value()) + return + } + f.State.Owner().SetValue(ctx.RequestSender()) +} + +func funcSetOwner(ctx wasmlib.ScFuncContext, f *SetOwnerContext) { + f.State.Owner().SetValue(f.Params.Owner().Value()) +} + +func viewGetOwner(ctx wasmlib.ScViewContext, f *GetOwnerContext) { + f.Results.Owner().SetValue(f.State.Owner().Value()) +} +``` + + + + +```rust +use wasmlib::*; + +use crate::*; + +pub fn func_init(ctx: &ScFuncContext, f: &InitContext) { + if f.params.owner().exists() { + f.state.owner().set_value(&f.params.owner().value()); + return; + } + f.state.owner().set_value(&ctx.request_sender()); +} + +pub fn func_set_owner(_ctx: &ScFuncContext, f: &SetOwnerContext) { + f.state.owner().set_value(&f.params.owner().value()); +} + +pub fn view_get_owner(_ctx: &ScViewContext, f: &GetOwnerContext) { + f.results.owner().set_value(&f.state.owner().value()); +} +``` + + + + +```ts +import * as wasmlib from 'wasmlib'; +import * as wasmtypes from 'wasmlib/wasmtypes'; +import * as sc from './index'; + +export function funcInit(ctx: wasmlib.ScFuncContext, f: sc.InitContext): void { + if (f.params.owner().exists()) { + f.state.owner().setValue(f.params.owner().value()); + return; + } + f.state.owner().setValue(ctx.requestSender()); +} + +export function funcSetOwner( + ctx: wasmlib.ScFuncContext, + f: sc.SetOwnerContext, +): void { + f.state.owner().setValue(f.params.owner().value()); +} + +export function viewGetOwner( + ctx: wasmlib.ScViewContext, + f: sc.GetOwnerContext, +): void { + f.results.owner().setValue(f.state.owner().value()); +} +``` + + + + +The schema tool automatically generates an initial working version of the functions to maintain the smart contract owner, +catering to most use cases. + +To streamline the building process, configure a build rule in your environment. +This rule should trigger the schema tool with the necessary parameters +whenever there are changes in the schema definition file. +This setup ensures automatic file regeneration, +eliminating the need to run the schema tool manually after each modification. +The tool regenerates code only if it detects alterations since its last operation. +To override this and force regeneration, include the `-force` flag in the command line parameter. + +### Creating Smart Contracts using AssemblyScript + + diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/views.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/views.mdx new file mode 100644 index 00000000000..b9aef699f09 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/views.mdx @@ -0,0 +1,133 @@ +--- +description: "Explore the characteristics and constraints of view-only functions in smart contracts, +illustrated through a 'getFactor' function example." +tags: +- View-Only Functions +- Smart Contracts +- Call Context +- Immutable Proxies +- Cross-Chain Requests +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Use View-Only Functions + +View-only functions, also known as "views", +are smart contract functions specialized in retrieving state information without altering the smart contract's state. + +## Characteristics + +### Immutable Proxies + +All state storage accesses occur through immutable proxies, ensuring the state remains unchanged. + +### Restricted Functionalities + +Views have a limited [Call Context](../../explanations/context.mdx), +disabling any function that might induce state changes, including token transactions. + +### Intra-chain Calls + +While they can [`call()`](call.mdx) other views within the same chain, +they cannot initiate non-view functions or [`post()`](post.mdx) cross-chain requests. + +### Return Data + +These functions are designed to return data to the caller, as they can't induce any other external effects. + +## Use Case: 'getFactor' Function + +To illustrate the use of view-only functions, consider the `getFactor()` function integrated in the `dividend` smart contract: + + + + + +```go + +// 'getFactor' is a simple View function. It will retrieve the factor +// associated with the (mandatory) address parameter it was provided with. +func viewGetFactor(_ wasmlib.ScViewContext, f *GetFactorContext) { + // Since we are sure that the 'address' parameter actually exists we can + // retrieve its actual value into an ScAddress value type. + var address wasmtypes.ScAddress = f.Params.Address().Value() + + // Create an ScImmutableMap proxy to the 'members' map in the state storage. + // Note that for views this is an *immutable* map as opposed to the *mutable* + // map we can access from the *mutable* state that gets passed to funcs. + var members MapAddressToImmutableUint64 = f.State.Members() + + // Retrieve the factor associated with the address parameter. + var factor uint64 = members.GetUint64(address).Value() + + // Set the factor in the results map of the function context. + // The contents of this results map is returned to the caller of the function. + f.Results.Factor().SetValue(factor) +} +``` + + + + +```rust +// 'getFactor' is a simple View function. It will retrieve the factor +// associated with the (mandatory) address parameter it was provided with. +pub fn view_get_factor(_ctx: &ScViewContext, f: &GetFactorContext) { + + // Since we are sure that the 'address' parameter actually exists we can + // retrieve its actual value into an ScAddress value type. + let address: ScAddress = f.params.address().value(); + + // Create an ScImmutableMap proxy to the 'members' map in the state storage. + // Note that for views this is an *immutable* map as opposed to the *mutable* + // map we can access from the *mutable* state that gets passed to funcs. + let members: MapAddressToImmutableUint64 = f.state.members(); + + // Retrieve the factor associated with the address parameter. + let factor: u64 = members.get_uint64(&address).value(); + + // Set the factor in the results map of the function context. + // The contents of this results map is returned to the caller of the function. + f.results.factor().set_value(factor); +} +``` + + + + +```ts +// 'getFactor' is a simple View function. It will retrieve the factor +// associated with the (mandatory) address parameter it was provided with. +export function viewGetFactor( + ctx: wasmlib.ScViewContext, + f: sc.GetFactorContext, +): void { + // Since we are sure that the 'address' parameter actually exists we can + // retrieve its actual value into an ScAddress value type. + let address: wasmlib.ScAddress = f.params.address().value(); + + // Create an ScImmutableMap proxy to the 'members' map in the state storage. + // Note that for views this is an *immutable* map as opposed to the *mutable* + // map we can access from the *mutable* state that gets passed to funcs. + let members: sc.MapAddressToImmutableUint64 = f.state.members(); + + // Retrieve the factor associated with the address parameter. + let factor: u64 = members.getUint64(address).value(); + + // Set the factor in the results map of the function context. + // The contents of this results map is returned to the caller of the function. + f.results.factor().setValue(factor); +} +``` + + + + +The return values are passed to the caller through the predefined [Results](results.mdx) map +associated with the [Call Context](../../explanations/context.mdx). +Again, this works the same as for Funcs, although Funcs do not necessarily return values to the caller. The +[Schema Tool](usage.mdx) will generate a function-specific [Results](results.mdx) +structure with type-safe proxies to the result fields in this map. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/how-tos/yaml.mdx b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/yaml.mdx new file mode 100644 index 00000000000..c812b5d6cea --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/how-tos/yaml.mdx @@ -0,0 +1,69 @@ +--- +tags: + - definition + - yaml + - smart contract creator + - one-time + - contract generation + - datatypes +description: the syntax of a schema definition file will be described here. +image: /img/logo/WASP_logo_dark.png +--- + +# YAML Schema Definition: Level 1 Attributes + +The schema definition file can have the following level 1 attributes: + +## name + +- **Type**: Single string +- **Usage**: Dictates the package name for the smart contract + +## description + +- **Type**: Single string +- **Usage**: Describes the smart contract's functionality (currently not utilized in the final smart contract) + +## events + +- **Type**: Map of strings +- **Usage**: Define structured events ([more info](./events.mdx)) +- **Restriction**: Field data types must be primitive; arrays, maps, or typedefs are not allowed + +## structs + +- **Type**: Map of string maps +- **Usage**: Declare structs for future development, usable in schema definitions +- **Restriction**: Fields must hold primitive types; arrays, maps, or typedef aliases are prohibited + +## typedefs + +- **Type**: Map of strings +- **Usage**: Create aliases for primitive values; supports primitive values, maps of primitive values, or arrays of primitive values +- **Restriction**: Nested typedefs are not permissible + +## state + +- **Type**: Map of strings +- **Usage**: Contains key/value pairs for use-case specific data ([details](../../explanations/states.md)) +- **Note**: To employ nested types, create a typedef alias for arrays or maps, but ensure map keys are primitive + +## funcs & views + +Describe functions and views sharing the same parameter and result names, ensuring they adhere to identical data types. The attributes common to both are: + +- **`access`** +- **Requirement**: Must be a state variable +- **Details**: Defines access permissions ([read more](./access.mdx#limiting-access)) + +- **`params`** +- **Type**: Can vary — array, map, or typedef alias +- **Usage**: Specifies input parameters + +- **`results`** +- **Type**: Can vary — array, map, or typedef alias +- **Usage**: Designates return values + +### Special Note on `funcs` + +- **Reserved Keyword**: `init` — relates to a distinct function ([explore](./init.mdx)) diff --git a/docs/build/isc/v1.3-alpha/docs/schema/introduction.mdx b/docs/build/isc/v1.3-alpha/docs/schema/introduction.mdx new file mode 100644 index 00000000000..de35b4c364a --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/introduction.mdx @@ -0,0 +1,62 @@ +# The Schema Tool + +Smart contracts need robustness, combining both flexibility and stringent regulation to prevent mistakes and foster efficiency. +Using the Schema Tool ensures consistency, and simplifies smart contract development. + +## Why Use the Schema Tool? + +### Ensure Robustness and Consistency + +By employing a code generator rooted in a schema definition file, you achieve: + +- **Reliability**: Through debugged, trustworthy generated code. +- **Adaptability**: Facilitating modifications in the smart contract interface. +- **Intent Reflection**: Enforcing defined smart contract behavior at compile-time. +- **Multilingual Support**: Accommodating various programming languages. + +### Prevent Repetitive Coding + +Initial experiences illustrated repetitive coding in: + +- `on_load` function setup and maintenance. +- Function access rights verification. +- Function parameter type and presence confirmation. +- Establishing access to State, Params, and Results maps. +- Common string constant definitions. + +The schema tool diminishes redundancy and ensures up-to-date functionalities. + +## The Schema Definition File + +### Defining a Clear Interface + +The schema definition file serves as a single source of truth, encompassing crucial details like: + +- State Storage Variables. +- [Funcs and Views](../../explanations/context). +- [Access rights](how-tos/access.mdx). +- [Input parameters](how-tos/params.mdx) and [output results](how-tos/results.mdx) . +- Additional Data Structures. + +### Automation with Schema Tool + +Using the [Schema Tool](how-tos/usage.mdx), the file facilitates: + +- **Skeleton Generation**: Crafting a smart contract framework that needs function implementations. +- **Interface Generation**: Creating interfaces to functions with stringent compile-time type-checking, thereby reducing errors. + +## Benefits of Schema Tool in Smart Contracts + +### Centralized Information + +Having all pertinent details in one place allows: + +- **Uniform Function Calls**: Through a generated interface used by client-side code. +- **Error Minimization**: Via compile-time type-checking. + +### Efficiency and Simplicity + +Knowledge of all essential aspects leads to: + +- **Constant Generation**: Avoiding typo-prone key strings repetition and precalculating essential values like `Hnames`. +- **Informative Code**: Generating code to correctly notify the host about available `Funcs` and `Views`. diff --git a/docs/build/isc/v1.3-alpha/docs/schema/proxies.mdx b/docs/build/isc/v1.3-alpha/docs/schema/proxies.mdx new file mode 100644 index 00000000000..0459da5c0bf --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/schema/proxies.mdx @@ -0,0 +1,76 @@ +--- +tags: + - proxies + - sandbox + - wasm + - value proxies + - container proxies + - array proxies + - map proxies + - explanation +description: As there is no way for the Wasm code to access any memory outside its own memory space, the WasmLib interface provides a number of proxies to make accessing data within the ISC sandbox as seamless as possible. +image: /img/wasm_vm/Proxies.png +--- +# Data Access Proxies + +To interact seamlessly with the ISC sandbox's regulated environment and facilitate smart contract data access, +the WasmLib introduces data access proxies. +Proxies are objects that can perform the underlying data transfers between the +separate systems. + +## Overview + +The restrictive ISC sandbox environment requires an intermediary, or a library, to access sandbox functionalities — a role that the WasmLib fulfills through data access `proxies`. +These entities stand as bridges, enabling data transfers between segregated systems, providing a streamlined pathway to interact with smart contract data stored on the ISC host. + +## The Role of Proxies + +Proxies refer to actual objects or values housed in the ISC host, +essentially acting as data references that understand how to manipulate the data they represent. +At the core, data is secured in maps on the ISC host with byte strings serving as both keys and values. + +The WasmLib recognizes three predefined maps: + +- **[State Map](../schema/how-tos/state.mdx):** A repository for all state storage values. +- **[Params Map](../schema/how-tos/params.mdx):** Holds the parameter values of the current function call. +- **[Results Map](../schema/how-tos/results.mdx):** Returns the result values of the function call. + +Through these maps, a complex, +JSON-like data structure can be created with the aid of the [Schema Tool](../schema/how-tos/usage.mdx), +although, fundamentally, this structure is rooted in simple key-value access on the underlying map. + +## Proxy Varieties + +Proxies are segmented into various categories to facilitate different functionalities, including value proxies and container proxies. + +### Value Proxies + +Representing a single instance of a predetermined data type, +value proxies are basic entities facilitating type conversion of the byte string representing the stored value. + +The [Schema Tool](../schema/how-tos/usage.mdx) ensures type-safe code generation, always selecting the suitable proxy type. + +### Container Proxies + +Container proxies offer a virtual nesting system on the underlying map, +creating paths leading to value proxies housed in a virtual container. +They use JSON and YAML nesting patterns, and there are two primary types: + +#### 1. Map Proxies + +- **Root Maps:** Encase any element type but restrict keys to human-readable strings, which are defined in the schema definition file. +- **Virtual Maps:** Resides under a root map and accommodates values of a single associated data type. + +#### 2. Array Proxies + +- Operate as a specialized map where the key is an Int32 value, forming a sequence from 0 to N-1 for an array harboring N elements. + +## Proxies in Action + +![Proxies in WasmLib](/img/wasm_vm/Proxies.png) + +In the illustration, we see the key-value combinations (Key 1 to Key 4) in the ISC state storage map. Key 4 directs us to an array containing indexed values ranging from 0 to N. + +Notice the precise reflection of these elements in the WasmLib proxies, +which maintain a container proxy for every container and a value proxy for each stored value. +However, it is not obligatory for a smart contract function to define a proxy for every value or container in the ISC state storage. diff --git a/docs/build/isc/v1.3-alpha/docs/solo/getting-started.md b/docs/build/isc/v1.3-alpha/docs/solo/getting-started.md new file mode 100644 index 00000000000..6fe73a027ce --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/getting-started.md @@ -0,0 +1,80 @@ +--- +description: 'Solo is a testing framework that allows developers to validate real smart contracts and entire inter-chain +protocols.' +image: /img/logo/WASP_logo_dark.png +tags: + +- testing framework +- golang +- rust +- inter-chain protocols +- validate smart contracts +- install +- how-tos +--- + +# Testing Smart Contracts with Solo + +## What is Solo? + +[_Solo_](https://github.com/iotaledger/wasp/tree/develop/packages/solo) is a testing framework that allows developers to +validate real smart contracts and entire inter-chain protocols before deploying them on the distributed network. + +## Installation + +### Prerequisites + +[Go (version 1.20)](https://tip.golang.org/doc/go1.20). As _Solo_ tests are written in Go, you must +[install Go](https://go.dev/doc/install). + +### Access the Solo Framework + +You can access the Solo package by cloning the [Wasp repository](#clone-the-wasp-repository) +or [installing the Solo package](#install-the-solo-package). + +#### Clone the Wasp Repository + +_Solo_ is part of the [_Wasp_ codebase repository](https://github.com/iotaledger/wasp.git). You can access the Solo +framework by cloning the repository with the following command: + +```shell +git clone https://github.com/iotaledger/wasp.git +``` + +After you have cloned the repository, you can access the Solo package in the `/packages/solo` folder. + +#### Install the Solo Package + +You can install the Solo package separately using the following command: + +```shell +go get github.com/iotaledger/wasp/packages/solo +``` + +:::tip Go Docs + +You can browse the Solo Go API reference (updated to the `master` branch) in +[go-docs](https://pkg.go.dev/github.com/iotaledger/wasp/packages/solo). + +::: + +### Example Contracts + +You will need a smart contract to test along with Solo. +You can find example implementations of Wasm smart contracts, including source code and tests, in the Wasp +repository’s [contracts/wasm folder](https://github.com/iotaledger/wasp/tree/develop/contracts/wasm). + +The following sections will present some Solo usage examples. You can find the example code in +the [Wasp repository](https://github.com/iotaledger/wasp/tree/develop/documentation/tutorial-examples). + +### Run `*_test` Files + +You can run `*_test` files by moving to their directory and running the following command: + +```shell +go test +``` + +If you run this command from the `/documentation/tutorial-examples` folder, you will run the +[Tutorial Test](https://github.com/iotaledger/wasp/blob/develop/documentation/tutorial-examples/test/tutorial_test.go), +which contains all the examples explained in the following sections. diff --git a/docs/build/isc/v1.3-alpha/docs/solo/how-tos/deploying-sc.md b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/deploying-sc.md new file mode 100644 index 00000000000..387e4d18235 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/deploying-sc.md @@ -0,0 +1,70 @@ +--- +description: Deploying Wasm smart contracts with Solo. +image: /img/tutorial/send_request.png +tags: + - testing + - PostRequestSync + - PostRequestOffLedger + - send + - requests + - post + - solo + - on-ledger + - off-ledger + - how-tos +--- + +# Deploying Wasm Smart Contracts + +:::note WASM VM + +For more information about how to create Wasm smart contracts, refer to the [Wasm VM chapter](../../getting-started/languages-and-vms.md#wasm-vm-for-isc). + +::: + +## Deploy the Solo Tutorial + +The following examples will make use of the +[`solotutorial` Rust/Wasm smart contract](https://github.com/iotaledger/wasp/tree/develop/documentation/tutorial-examples). + +In order to test the smart contract using Solo, first you need to deploy it. You can use the following code to +deploy `solotutorial_bg.wasm`: + +```go +func TestTutorialDeploySC(t *testing.T) { + env := solo.New(t, &solo.InitOptions{AutoAdjustStorageDeposit: true}) + chain := env.NewChain() + err := chain.DeployWasmContract(nil, "solotutorial", "solotutorial_bg.wasm") + require.NoError(t, err) +} +``` + +This will work as long as the `solotutorial_bg.wasm` file is in the same directory as the Go test code. + +### Create a Default Wallet and Chain + +You can use the `NewChain()` function to create a new wallet and deploys a new chain using said wallet, and other +default parameters. You can access the wallet calling `chain.OriginatorPrivateKey`. + +### DeployWasmContract Parameters + +#### Deployer's Key Pair + +The first parameter to `DeployWasmContract` is the key pair of the deployer of the smart contract. You can pass `nil` +to use a default wallet, which can be accessed as `chain.OriginatorPrivateKey`. + +#### Smart Contract Name + +The second parameter to `DeployWasmContract` (`"solotutorial"`), is the name assigned to the smart contract instance. +Smart contract instance names must be unique across each chain. + +### AutoAdjustStorageDeposit + +In the example above we enabled the `AutoAdjustStorageDeposit` option. +This is necessary in order to automatically adjust all sent L1 transactions to include the storage deposit if +necessary (provided that the sender owns the funds). + +It is possible to disable the option and have manual control of the storage deposit, but in that case the deployment +of the smart contract will have to be done "by hand". + +In most cases it is recommended to leave it enabled. diff --git a/docs/build/isc/v1.3-alpha/docs/solo/how-tos/error-handling.md b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/error-handling.md new file mode 100644 index 00000000000..40b414feedc --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/error-handling.md @@ -0,0 +1,51 @@ +--- +description: What happens when a smart contract invocation fails? +image: /img/logo/WASP_logo_dark.png +tags: + - testing + - solo + - error handling + - panic + - state + - transition +--- + +# Error Handling + +The following test posts a request to the `solotutorial` smart contract without the expected parameter `"str"`, causing +the smart contract call to panic: + +```go +func TestTutorialInvokeSCError(t *testing.T) { + env := solo.New(t, &solo.InitOptions{AutoAdjustStorageDeposit: true}) + chain := env.NewChain() + err := chain.DeployWasmContract(nil, "solotutorial", "solotutorial_bg.wasm") + require.NoError(t, err) + + // missing the required parameter "str" + req := solo.NewCallParams("solotutorial", "storeString"). + WithMaxAffordableGasBudget() + + _, err = chain.PostRequestSync(req, nil) + require.Error(t, err) + require.True(t, err.Error() == "WASM: panic in VM: missing mandatory string") +} +``` + +The `_, err = chain.PostRequestSync(req, nil)` will return an error containing `WASM: panic in VM: missing mandatory string`. + +This shows that the request resulted in a panic. +The Solo test passes because of the `require.Error(t, err)` line. + +Note that this test still ends with the state `#4`, although the last request to the smart contract failed: + +```log +20:09.974258867 INFO TestTutorialInvokeSCError.ch1 solo/run.go:156 state transition --> #4. Requests in the block: 1. Outputs: 1 +``` + +This shows that a chain block is always generated, regardless of whether the smart contract call succeeds or not. The +result of the request is stored in the chain's [`blocklog`](../../reference/core-contracts/blocklog.md) in the form of +a receipt. In fact, the received Go error `err` in the test above is just generated from the request receipt. + +If a panic occurs during a smart contract call, it is recovered by the VM context, and the request is marked as failed. +Any state changes made prior to the panic are rolled back. diff --git a/docs/build/isc/v1.3-alpha/docs/solo/how-tos/examples.mdx b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/examples.mdx new file mode 100644 index 00000000000..c924b0b67fe --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/examples.mdx @@ -0,0 +1,282 @@ +--- +tags: + - solo + - testing + - errors + - member function + - post + - ctx + - divide function + - error message + +description: Use the SoloContext to create full-blown tests for the dividend example smart contract. + +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Example Tests + +In the previous sections we showed how you can [`call()`](../../schema/how-tos/call.mdx) or +[`post()`](../../schema/how-tos/post.mdx) smart contract function requests. We also created a few wrapper +functions to simplify calling these functions even further. Now we will look at how to use +the SoloContext to create full-blown tests for the `dividend` example smart contract. + +Let's start with a simple test. We are going to use the `member` function to add a valid +new member/factor combination to the member group. + + + + + +```go +func TestAddMemberOk(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member1 := ctx.NewSoloAgent("member1") + dividendMember(ctx, member1, 100) + require.NoError(t, ctx.Err) +} +``` + + + + +The above test first deploys the `dividend` smart contract to a new chain, and returns a +SoloContext `ctx`. Then it uses `ctx` to create a new SoloAgent `member1`. When creating a +SoloAgent a new _Tangle_ address is created for that agent and its on-chain account is +pre-seeded with 10M base tokens so that it is ready to be used in tests. The SoloAgent can +be used whenever an address or agent ID needs to be provided, it can be used to sign a +request to identify it as the sender, and it can be used to inspect the asset balances on +its Tangle address and its on-chain account. + +In this case, we simply create `member1`, and pass it to the dividend contract's `member` +function, which will receive the address of `member1` and a dispersal factor of 100. +Finally, we check if ctx has received an error during the execution of the call. Remember +that the only way to pass an error from a WasmLib function call is through a `panic()` +call. The code that handles the actual call will intercept any `panic()` that was raised, +and return an error. The SoloContext saves this error for later inspection, because the +function descriptor used in the call itself has no way of passing back this error. + +The next two example tests each call the contract's `member` function in the exact same +way, but in both cases one required parameter is omitted. The idea is to test that the +function properly panics by checking the ctx.Err value is not nil after the call. Finally, +the error message text is checked to see if it contains the expected error message. + + + + + +```go +func TestAddMemberFailMissingAddress(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member := dividend.ScFuncs.Member(ctx) + member.Params.Factor().SetValue(100) + member.Func.Post() + require.Error(t, ctx.Err) + require.Contains(t, ctx.Err.Error(), "missing mandatory address") +} + +func TestAddMemberFailMissingFactor(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member1 := ctx.NewSoloAgent("member1") + member := dividend.ScFuncs.Member(ctx) + member.Params.Address().SetValue(member1.ScAgentID().Address()) + member.Func.Post() + require.Error(t, ctx.Err) + require.Contains(t, ctx.Err.Error(), "missing mandatory factor") +} +``` + + + + +Each test has to set up the chain/contract/context from scratch. We will often use a +specific setupTest() function to do all setup work that is shared by many tests. + +We cannot use the `dividendMember` wrapper function in these two tests because of the +missing required function parameters. So we have simply copy/pasted the code, and removed +the `Params` proxy initialization lines that we wanted to be detected as missing. + +Now let's see a more complex example: + + + + + +```go +func TestDivide1Member(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member1 := ctx.NewSoloAgent("member1") + bal := ctx.Balances(member1) + + dividendMember(ctx, member1, 100) + require.NoError(t, ctx.Err) + + bal.Chain += ctx.GasFee + bal.Originator += ctx.StorageDeposit - ctx.GasFee + bal.VerifyBalances(t) + + const dividendToDivide = 1*isc.Million + 1 + dividendDivide(ctx, dividendToDivide) + require.NoError(t, ctx.Err) + + bal.Chain += ctx.GasFee + bal.Originator -= ctx.GasFee + bal.Add(member1, dividendToDivide) + bal.VerifyBalances(t) +} +``` + + + + +The first half of the code is almost identical to our first test above. We set up the +test, create an agent, set the factor for that agent to 100, and verify that no error +occurred. Notice how we additionally call `ctx.Balances()` to make a snapshot of all the +original asset balances including those of the agent. + +Then in the next lines we update the asset balances with the changes we expect to happen +because of the call to the `member` function. And then we verify these changes against the +actual asset balances by calling `bal.VerifyBalances(t)`. + +Next we transfer 1M + 1 tokens as part of the post request to the `divide` function. We +subsequently check that no error has occurred. Finally, we again modify the asset balances +to reflect the expected changes and verify these changes against the actual asset +balances. + +Now let's skip to the most complex test of all: + + + + + +```go + func TestDivide3Members(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member1 := ctx.NewSoloAgent("member1") + bal := ctx.Balances(member1) + + dividendMember(ctx, member1, 25) + require.NoError(t, ctx.Err) + + bal.Chain += ctx.GasFee + bal.Originator += ctx.StorageDeposit - ctx.GasFee + bal.VerifyBalances(t) + + member2 := ctx.NewSoloAgent("member2") + bal = ctx.Balances(member1, member2) + + dividendMember(ctx, member2, 50) + require.NoError(t, ctx.Err) + + bal.Chain += ctx.GasFee + bal.Originator += ctx.StorageDeposit - ctx.GasFee + bal.VerifyBalances(t) + + member3 := ctx.NewSoloAgent() + bal = ctx.Balances(member1, member2, member3) + + dividendMember(ctx, member3, 75) + require.NoError(t, ctx.Err) + + bal.Chain += ctx.GasFee + bal.Originator += ctx.StorageDeposit - ctx.GasFee + bal.VerifyBalances(t) + + const dividendToDivide = 2*isc.Million - 1 + dividendDivide(ctx, dividendToDivide) + require.NoError(t, ctx.Err) + + remain := dividendToDivide - dividendToDivide*25/150 - dividendToDivide*50/150 - dividendToDivide*75/150 + bal.Chain += ctx.GasFee + bal.Originator += remain - ctx.GasFee + bal.Add(member1, dividendToDivide*25/150) + bal.Add(member2, dividendToDivide*50/150) + bal.Add(member3, dividendToDivide*75/150) + bal.VerifyBalances(t) + + const dividendToDivide2 = 2*isc.Million + 234 + dividendDivide(ctx, dividendToDivide2) + require.NoError(t, ctx.Err) + + remain = dividendToDivide2 - dividendToDivide2*25/150 - dividendToDivide2*50/150 - dividendToDivide2*75/150 + bal.Chain += ctx.GasFee + bal.Originator += remain - ctx.GasFee + bal.Add(member1, dividendToDivide2*25/150) + bal.Add(member2, dividendToDivide2*50/150) + bal.Add(member3, dividendToDivide2*75/150) + bal.VerifyBalances(t) +} +``` + + + + +This function creates 3 agents, and associates factors of 25, 50, and 75 respectively to +them. That required 3 `member` requests, and we verify the expected balance changes after +each request. Next the `divide` function is called, with 2M-1 tokens passed to it. + +After this we verify that each agent has been distributed tokens according to its relative +factor. Those factors are 25/150th, 50/150th, and 75/150th, respectively. Note that we +cannot transfer fractional tokens, so we truncate to the nearest integer and ultimately +any remaining tokens are not transferred, but remain in the sender's account. + +Finally, we call `divide` again with 2M+234 tokens and again verify the asset balances +afterwards. + +Next we will show how to test [Views](../../schema/how-tos/views.mdx) and/or [Funcs](../../schema/how-tos/funcs.mdx) that return +a result. Note that even though Funcs are usually invoked through a [`post()`](../../schema/how-tos/post.mdx) +request, in which case any return values are inaccessible, they still can be invoked +through a [call()](../../schema/how-tos/call.mdx) from within another Func, in which these return values can +be used normally. Since solo executes [`post()`](../../schema/how-tos/post.mdx) requests synchronously, it is +possible to have a Func return a result and test for certain result values. + + + + + +```go +func TestGetFactor(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member1 := ctx.NewSoloAgent("member1") + dividendMember(ctx, member1, 25) + require.NoError(t, ctx.Err) + + member2 := ctx.NewSoloAgent("member2") + dividendMember(ctx, member2, 50) + require.NoError(t, ctx.Err) + + member3 := ctx.NewSoloAgent() + dividendMember(ctx, member3, 75) + require.NoError(t, ctx.Err) + + value := dividendGetFactor(ctx, member3) + require.NoError(t, ctx.Err) + require.EqualValues(t, 75, value) + + value = dividendGetFactor(ctx, member2) + require.NoError(t, ctx.Err) + require.EqualValues(t, 50, value) + + value = dividendGetFactor(ctx, member1) + require.NoError(t, ctx.Err) + require.EqualValues(t, 25, value) +} +``` + + + + +Here we first set up the same 3 dispersion factors, and then we retrieve the dispersion +factors for each member in reverse order and verify their values. + +In the [next section](timelock.mdx) we will describe a few more helper member functions +of the SoloContext. diff --git a/docs/build/isc/v1.3-alpha/docs/solo/how-tos/first-example.md b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/first-example.md new file mode 100644 index 00000000000..f4189cee840 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/first-example.md @@ -0,0 +1,94 @@ +--- +description: Example of a _Solo_ test. It deploys a new chain and invokes some view calls. +image: /img/logo/WASP_logo_dark.png +tags: + - testing framework + - golang + - solo + - example + - new chain + - how-tos +--- + +# First Example + +The following is an example of a _Solo_ test. It deploys a new chain and invokes some view calls in the +[`root`](../../reference/core-contracts/root.md) and [`governance`](../../reference/core-contracts/governance.md) +[core contracts](../../reference/core-contracts/overview.md). + +```go +import ( + "testing" + + "github.com/iotaledger/wasp/packages/solo" + "github.com/iotaledger/wasp/packages/vm/core/corecontracts" + "github.com/stretchr/testify/require" +) + +func TestTutorialFirst(t *testing.T) { + env := solo.New(t) + chain := env.NewChain() + + // calls views governance::ViewGetChainInfo and root:: ViewGetContractRecords + chainID, chainOwnerID, coreContracts := chain.GetInfo() + // assert that all core contracts are deployed + require.EqualValues(t, len(corecontracts.All), len(coreContracts)) + + t.Logf("chain ID: %s", chainID.String()) + t.Logf("chain owner ID: %s", chainOwnerID.String()) + for hname, rec := range coreContracts { + t.Logf(" Core contract %q: %s", rec.Name, hname) + } +} +``` + +The output of the test will be something like this: + +```log +=== RUN TestTutorialFirst +29:43.383770108 INFO TestTutorialFirst.db dbmanager/dbmanager.go:64 creating new in-memory database for: CHAIN_REGISTRY +29:43.383957435 INFO TestTutorialFirst solo/solo.go:162 Solo environment has been created: logical time: 00:01.001000000, time step: 1ms +29:43.384671943 INFO TestTutorialFirst solo/solo.go:236 deploying new chain 'tutorial1'. ID: tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd, state controller address: tgl1qpk70349ftcpvlt6lnn0437p63wt7w2ejvlkw93wkkt0kc39f2wpvuv73ea +29:43.384686865 INFO TestTutorialFirst solo/solo.go:238 chain 'tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd'. state controller address: tgl1qpk70349ftcpvlt6lnn0437p63wt7w2ejvlkw93wkkt0kc39f2wpvuv73ea +29:43.384698704 INFO TestTutorialFirst solo/solo.go:239 chain 'tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd'. originator address: tgl1qq93jh7dsxq3lznajgtq33v26rt0pz0rs0rwar4jahahp6h2hh9jy4nc52k +29:43.384709967 INFO TestTutorialFirst.db dbmanager/dbmanager.go:64 creating new in-memory database for: tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd +29:43.384771911 INFO TestTutorialFirst solo/solo.go:244 chain 'tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd'. origin state commitment: c4f09061cd63ea506f89b7cbb3c6e0984f124158 +29:43.417023624 INFO TestTutorialFirst solo/solo.go:171 solo publisher: state [tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd 1 1 0-6c7ff6bc5aaa3af12f9b6b7c43dcf557175ac251418df562f7ec4ff092e84d4f 0000000000000000000000000000000000000000000000000000000000000000] +29:43.417050354 INFO TestTutorialFirst solo/solo.go:171 solo publisher: request_out [tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd 0-11232aa47639429b83faf79547c6bf615bd65aa461f243c89e4073b792ac89b7 1 1] +29:43.417056290 INFO TestTutorialFirst.tutorial1 solo/run.go:156 state transition --> #1. Requests in the block: 1. Outputs: 1 +29:43.417179099 INFO TestTutorialFirst.tutorial1 solo/run.go:176 REQ: 'tx/0-11232aa47639429b83faf79547c6bf615bd65aa461f243c89e4073b792ac89b7' +29:43.417196814 INFO TestTutorialFirst.tutorial1 solo/solo.go:301 chain 'tutorial1' deployed. Chain ID: tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd + tutorial_test.go:20: chain ID: tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd + tutorial_test.go:21: chain owner ID: tgl1qq93jh7dsxq3lznajgtq33v26rt0pz0rs0rwar4jahahp6h2hh9jy4nc52k + tutorial_test.go:23: Core contract "blob": fd91bc63 + tutorial_test.go:23: Core contract "governance": 17cf909f + tutorial_test.go:23: Core contract "errors": 8f3a8bb3 + tutorial_test.go:23: Core contract "evm": 07cb02c1 + tutorial_test.go:23: Core contract "accounts": 3c4b5e02 + tutorial_test.go:23: Core contract "root": cebf5908 + tutorial_test.go:23: Core contract "blocklog": f538ef2b +--- PASS: TestTutorialFirst (0.03s) +``` + +:::note + +- The example uses [`stretchr/testify`](https://github.com/stretchr/testify) for assertions, but it is not strictly + required. +- Addresses, chain IDs and other hashes should be the same on each run of the test because Solo uses a constant seed by + default. +- The timestamps shown in the log come from the computer's timer, but the Solo environment operates on its own logical + time. + +::: + +The [core contracts](../../reference/core-contracts/overview.md) listed in the log are automatically deployed on each +new chain. The log also shows their _contract IDs_. + +The output fragment in the log `state transition --> #1` means that the state of the chain has changed from block index +0 (the origin index of the empty state) to block index 1. State #0 is the empty origin state, and #1 always contains all +core smart contracts deployed on the chain, as well as other data internal to the chain itself, such as the _chainID_ +and the _chain owner ID_. + +The _chain ID_ and _chain owner ID_ are, respectively, the ID of the deployed chain, and the address of the L1 account +that triggered the deployment of the chain (which is automatically generated by Solo in our example, but it can be +overridden when calling `env.NewChain`). diff --git a/docs/build/isc/v1.3-alpha/docs/solo/how-tos/invoking-sc.md b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/invoking-sc.md new file mode 100644 index 00000000000..ec60f2d2cbe --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/invoking-sc.md @@ -0,0 +1,116 @@ +--- +description: Invoking smart contracts with on-ledger and off-ledger requests with Solo. +image: /img/tutorial/send_request.png +tags: + - how-to + - explanation + - testing + - PostRequestSync + - PostRequestOffLedger + - send + - requests + - post + - solo + - on-ledger + - off-ledger +--- + +# Invoking Smart Contracts + +After deploying +the [`solotutorial`](https://github.com/iotaledger/wasp/tree/develop/documentation/tutorial-examples) +smart contract, you can invoke the `storeString` function: + +```go +func TestTutorialInvokeSC(t *testing.T) { + env := solo.New(t, &solo.InitOptions{AutoAdjustStorageDeposit: true}) + chain := env.NewChain() + err := chain.DeployWasmContract(nil, "solotutorial", "solotutorial_bg.wasm") + require.NoError(t, err) + + // invoke the `storeString` function + req := solo.NewCallParams("solotutorial", "storeString", "str", "Hello, world!"). + WithMaxAffordableGasBudget() + _, err = chain.PostRequestSync(req, nil) + require.NoError(t, err) + + // invoke the `getString` view + res, err := chain.CallView("solotutorial", "getString") + require.NoError(t, err) + require.Equal(t, "Hello, world!", codec.MustDecodeString(res.MustGet("str"))) +} +``` + +## Parameters + +### `NewCallParams()` + +The above example uses `NewCallParams` to set up the parameters of the request that it will send to the contract. +It specifies that it wants to invoke the `storeString` entry point of the `solotutorial` smart contract, passing the +parameter named `str` with the string value `"Hello, world!"`. + +### `WithMaxAffordableGasBudget()` + +`WithMaxAffordableGasBudget()` assigns the gas budget of the request to the maximum that the sender can afford with the +funds they own on L2 (including any funds attached in the request itself). +In this case the funds attached automatically for the storage deposit will be enough to cover for the gas fee, so it is +not necessary to manually deposit more funds for gas. + +## `PostRequestSync()` + +`PostRequestSync` sends an on-ledger request to the chain. + +## On-Ledger Requests + +[![Generic process of posting an on-ledger request to the smart contract](/img/tutorial/send_request.png)](/img/tutorial/send_request.png) + +The diagram above depicts the generic process of posting an _on-ledger_ request to the smart contract. +The same diagram is valid for the Solo environment and any other requester that sends an on-ledger request, e.g., the +IOTA Smart Contracts wallet or another chain. + +Posting an on-ledger request always consists of the steps below. +Note that in Solo, all seven steps are carried out by a single call to `PostRequestSync`. + +1. Create the L1 transaction, which wraps the L2 request and moves tokens. + + Each on-ledger request must be contained in a transaction on the ledger. + Therefore, it must be signed by the sender’s private key. + This securely identifies each requester in IOTA Smart Contracts. + In Solo, the transaction is signed by the private key provided in the second parameter of the `PostRequestSync` call + (`chain.OriginatorPrivateKey()` by default). + +2. Post and confirm the transaction to the L1 ledger. + + In Solo, it is just adding the transaction to the emulated L1 ledger, so it is confirmed immediately and + synchronously. + The confirmed transaction on the ledger becomes part of the backlog of requests to be processed by the chain. + In the real L1 ledger, the sender must wait until the ledger confirms the transaction. + +3. The chain picks the request from the backlog and runs the request on the VM. +4. The _VM_ calls the target entry point of the smart contract program. The program updates the state. +5. The VM produces a state update transaction (the _anchor_). +6. The chain signs the transaction with its private key (the `chain.StateControllerKeyPair()` in Solo). +7. The chain posts the resulting transaction to the L1 ledger and, after confirmation, commits the corresponding state. + +The following lines in the test log correspond to step 7: + +```log +49:37.771863573 INFO TestTutorialInvokeSC solo/solo.go:171 solo publisher: state [tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd 4 1 0-177c8a62feb7d434608215a179dd6637b8038d1237dd264 +d8feaf4d9a851b808 0000000000000000000000000000000000000000000000000000000000000000] +49:37.771878833 INFO TestTutorialInvokeSC solo/solo.go:171 solo publisher: request_out [tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd 0-c55b41b07687c644b7f7a1b9fb5da86f2d40195f39885 +bc348767e2dd285ca15 4 1] +49:37.771884127 INFO TestTutorialInvokeSC.ch1 solo/run.go:156 state transition --> #4. Requests in the block: 1. Outputs: 1 +``` + +## Off-ledger Requests + +Alternatively, you could send an off-ledger request by using `chain.PostRequestOffLedger` instead of `PostRequestSync`. +However, since off-ledger requests cannot have tokens attached, in order to cover the gas fee, you must deposit funds to +the chain beforehand: + +```go +user, _ := env.NewKeyPairWithFunds(env.NewSeedFromIndex(1)) +chain.DepositBaseTokensToL2(10_000, user) // to cover gas fees +_, err = chain.PostRequestOffLedger(req, user) +require.NoError(t, err) +``` diff --git a/docs/build/isc/v1.3-alpha/docs/solo/how-tos/test.mdx b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/test.mdx new file mode 100644 index 00000000000..aedbaab2e19 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/test.mdx @@ -0,0 +1,123 @@ +--- +tags: + - testing + - solo testing environment + - call context + - smart contract functionalities + - data types + - type conversions + - Go + +description: Testing of smart contracts happens in the Solo testing environment. This enables synchronous, deterministic testing of smart contract functionality without the overhead of having to start nodes, set up a committee, and send transactions over the _Tangle_. +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Testing Smart Contracts + +Testing of smart contracts happens in the [Solo](../getting-started.md) testing +environment. This enables synchronous, deterministic testing of smart contract +functionalities without the overhead of having to start nodes, set up a committee, and +send transactions over the _Tangle_. Instead, you can use Go's built-in test environment in +combination with Solo to deploy chains and smart contracts and simulate transactions. + +Solo directly interacts with the ISC code, and therfore uses all the ISC-specific data +types directly. Our Wasm smart contracts cannot access these types directly, because they +run in a separate, sandboxed environment. Therefore, WasmLib implements its +[own versions](../../reference/wasm-lib-data-types.mdx) of these data types, and the _VM_ layer acts as a data type +translator between both systems. + +The impact of this type transformation used to be that to be able to write tests in the +solo environment the user also needed to know about the ISC-specific data types and type +conversion functions, and exactly how to properly pass such data in and out of smart +contract function calls. This burdened the user with an unnecessary increased learning +curve and countless unnecessary type conversions. + +With the introduction of the [Schema Tool](../../schema/how-tos/usage.mdx), we were able to remove this +impedance mismatch and allow the users to test smart contract functionality in terms of +the WasmLib data types and functions that they are already familiar with. To that end, we +introduced `SoloContext`, a new [Call Context](../../explanations/context.mdx) that specifically works with +the Solo testing environment. We aimed to simplify the testing of smart contracts as much +as possible, keeping the full Solo interface hidden as much as possible, but still +available when necessary. + +The only concession we still have to make is to the language used. Because Solo only works +in the Go language environment, we have to use the Go language version of the interface +code that the [Schema Tool](../../schema/how-tos/usage.mdx) generates when testing our smart contracts. Because +WasmLib programming for Go, Rust, and TypeScript are practically identical, we feel that +this is not unsurmountable. The WasmLib interfaces only differ slightly if language +idiosyncrasies force differences in syntax or naming conventions. This hurdle used to be a +lot bigger, when direct programming of Solo had to be used, and most type conversions had +to be done manually. Now we get to use the generated compile-time type-checked interface +to our smart contract functions that we are already familiar with. + +Let's look at the simplest way of initializing a smart contract by using the new +`SoloContext` in a test function: + + + + + +```go +func TestDeploy(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + require.NoError(t, ctx.ContractExists(dividend.ScName)) +} +``` + + + + +The first line will automatically create a new chain, and upload and deploy the provided +example `dividend` contract to this chain. It returns a `SoloContext` for further use. The +second line verifies the existence of the deployed contract on the chain associated with +that [Call Context](../../explanations/context.mdx). + +Here is another part of the `dividend` test code, where you can see how we wrap repetitive +calls to smart contract functions that are used in multiple tests: + + + + + +```go +func dividendMember(ctx *wasmsolo.SoloContext, agent *wasmsolo.SoloAgent, factor uint64) { + member := dividend.ScFuncs.Member(ctx) + member.Params.Address().SetValue(agent.ScAgentID().Address()) + member.Params.Factor().SetValue(factor) + member.Func.Post() +} + +func dividendDivide(ctx *wasmsolo.SoloContext, amount uint64) { + divide := dividend.ScFuncs.Divide(ctx) + divide.Func.TransferBaseTokens(amount).Post() +} + +func dividendGetFactor(ctx *wasmsolo.SoloContext, member *wasmsolo.SoloAgent) uint64 { + getFactor := dividend.ScFuncs.GetFactor(ctx) + getFactor.Params.Address().SetValue(member.ScAgentID().Address()) + getFactor.Func.Call() + value := getFactor.Results.Factor().Value() + return value +} +``` + + + + +As you can see, we pass the `SoloContext` and the parameters to the wrapper functions, +then use the `SoloContext` to create a [Function Descriptor](../../schema/how-tos/funcdesc.mdx) for the wrapped +function, pass any parameters through the [Params](../../schema/how-tos/params.mdx) proxy, and then either +[`post()`](../../schema/how-tos/post.mdx) the function request or [`call`](../../schema/how-tos/call.mdx) the function. Any +results returned are extracted through the descriptor's [Results](../../schema/how-tos/results.mdx) proxy, and +returned by the wrapper function. + +There is hardly any difference in the way the function interface is used within Wasm code +or within Solo test code. The [Call Context](../../explanations/context.mdx) knows how to properly +[`call()`](../../schema/how-tos/call.mdx) or [`post()`](../../schema/how-tos/post.mdx) the function call through the function +descriptor. This makes for seamless testing of smart contracts. + +In the [next section](examples.mdx) we will go deeper into how the helper member functions +of the SoloContext are used to simplify tests. diff --git a/docs/build/isc/v1.3-alpha/docs/solo/how-tos/the-l1-ledger.md b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/the-l1-ledger.md new file mode 100644 index 00000000000..ed3c5b84c53 --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/the-l1-ledger.md @@ -0,0 +1,71 @@ +--- +description: How to interact with the L1 ledger in Solo. +image: /img/logo/WASP_logo_dark.png +tags: + - testing + - solo + - UTXO + - tokens + - ledger + - l1 + - how-tos +--- + +# The L1 Ledger + +IOTA Smart Contracts work as a **layer 2** (**L2**) extension of the _IOTA Multi-Asset Ledger_, **layer 1** (**L1**). +The specifics of the ledger is outside the scope of this documentation; for now it is sufficient to know that the ledger +contains balances of different kinds of assets (base tokens, native tokens, foundries and _NFT_s) locked in addresses. +Assets can only be moved on the ledger by unlocking the corresponding address with its private key. + +For example: + +```log +Address: iota1pr7vescn4nqc9lpvv37unzryqc43vw5wuf2zx8tlq2wud0369hjjugg54mf + IOTA: 4012720 + Native token 0x08fcccc313acc182fc2c647dc98864062b163a8ee254231d7f029dc6be3a2de52e0100000000: 100 + NFT 0x94cd51b79d9608ed6e38780d48e9fc8c295b893077739b28ce591c45b33dec44 +``` + +In this example, the address owns some base tokens (IOTA), 100 units of a native token with ID `0x08fc...`, and an NFT +with ID `0x94cd...`. + +You can find more information about the ledger in the +[Multi-Asset Ledger TIP](https://github.com/lzpap/tips/blob/master/tips/TIP-0018/tip-0018.md). + +In normal operation, the L2 state is maintained by a committee of Wasp _nodes_. The L1 ledger is provided and +maintained by a network of [Hornet](https://github.com/iotaledger/hornet) nodes, which is a distributed implementation +of the IOTA Multi-Asset Ledger. + +The Solo environment implements a standalone in-memory ledger, simulating the behavior of a real L1 ledger without the +need to run a network of Hornet nodes. + +The following example creates a new wallet (private/public key pair) and requests some base tokens from the faucet: + +```go +func TestTutorialL1(t *testing.T) { + env := solo.New(t) + _, userAddress := env.NewKeyPairWithFunds(env.NewSeedFromIndex(1)) + t.Logf("address of the user is: %s", userAddress.Bech32(parameters.L1.Protocol.Bech32HRP)) + numBaseTokens := env.L1BaseTokens(userAddress) + t.Logf("balance of the user is: %d base tokens", numBaseTokens) + env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount) +} +``` + +The _output_ of the test is: + +```log +=== RUN TestTutorialL1 +47:49.136622566 INFO TestTutorialL1.db dbmanager/dbmanager.go:64 creating new in-memory database for: CHAIN_REGISTRY +47:49.136781104 INFO TestTutorialL1 solo/solo.go:162 Solo environment has been created: logical time: 00:01.001000000, time step: 1ms + tutorial_test.go:32: address of the user is: tgl1qp5d8zm9rr9rcae2hq95plx0rquy5gu2mpedurm2kze238neuhh5csjngz0 + tutorial_test.go:34: balance of the user is: 1000000000 base tokens +--- PASS: TestTutorialL1 (0.00s) +``` + +The L1 ledger in Solo can be accessed via the Solo instance called `env`. +The ledger is unique for the lifetime of the Solo environment. +Even if several L2 chains are deployed during the test, all of them will live on the same L1 ledger; this way Solo makes +it possible to test cross-chain transactions. +(Note that in the test above we did not deploy any chains: the L1 ledger exists independently of any chains.) diff --git a/docs/build/isc/v1.3-alpha/docs/solo/how-tos/the-l2-ledger.md b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/the-l2-ledger.md new file mode 100644 index 00000000000..ed737dbeaed --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/the-l2-ledger.md @@ -0,0 +1,176 @@ +--- +description: 'Smart contracts can exchange assets between themselves on the same chain and between different chains, as +well as with addresses on the L1 ledger.' +image: /img/logo/WASP_logo_dark.png +tags: + +- testing +- solo +- account +- address +- wallet +- balances +- ledger + +--- + +# The L2 Ledger + +Each chain in IOTA Smart Contracts contains its own L2 ledger, independent of the L1 ledger. +Smart contracts can exchange assets between themselves on the same chain, between different chains, and with addresses +on the L1 Ledger. + +Imagine that you have a wallet with some tokens on the L1 ledger, and you want to send those tokens to a smart contract +on a chain and later receive these tokens back on L1. + +On the L1 ledger, your wallet's private key is represented by an address, which holds some tokens. +Those tokens are _controlled_ by the private key. + +In IOTA Smart Contracts the L2 ledger is a collection of _on-chain accounts_ (sometimes also called just _accounts_). +Each L2 account is controlled by the same private key as its associated address and can hold tokens on the chain's +ledger, just like an address can hold tokens on L1. +This way, the chain is essentially a custodian of the tokens deposited in its accounts. + +## Deposit and Withdraw Tokens + +The following test demonstrates how a wallet can deposit tokens in a chain +account and then withdraw them. + +Note that the math is made somewhat more complex by the gas fees and storage deposit. +You could ignore them, but we include them in the example to show you exactly how you can handle them. + +```go +func TestTutorialAccounts(t *testing.T) { + env := solo.New(t, &solo.InitOptions{AutoAdjustStorageDeposit: true}) + chain := env.NewChain() + + // create a wallet with some base tokens on L1: + userWallet, userAddress := env.NewKeyPairWithFunds(env.NewSeedFromIndex(0)) + env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount) + + // the wallet can we identified on L2 by an AgentID: + userAgentID := isc.NewAgentID(userAddress) + // for now our on-chain account is empty: + chain.AssertL2BaseTokens(userAgentID, 0) + + // send 1 Mi from the L1 wallet to own account on-chain, controlled by the same wallet + req := solo.NewCallParams(accounts.Contract.Name, accounts.FuncDeposit.Name). + AddBaseTokens(1 * isc.Million) + + // estimate the gas fee and storage deposit + gas1, gasFee1, err := chain.EstimateGasOnLedger(req, userWallet, true) + require.NoError(t, err) + storageDeposit1 := chain.EstimateNeededStorageDeposit(req, userWallet) + require.Zero(t, storageDeposit1) // since 1 Mi is enough + + // send the deposit request + req.WithGasBudget(gas1). + AddBaseTokens(gasFee1) // including base tokens for gas fee + _, err = chain.PostRequestSync(req, userWallet) + require.NoError(t, err) + + // our L1 balance is 1 Mi + gas fee short + env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount-1*isc.Million-gasFee1) + // our L2 balance is 1 Mi + chain.AssertL2BaseTokens(userAgentID, 1*isc.Million) + // (the gas fee went to the chain's private account) + + // withdraw all base tokens back to L1 + req = solo.NewCallParams(accounts.Contract.Name, accounts.FuncWithdraw.Name). + WithAllowance(isc.NewAssetsBaseTokens(1 * isc.Million)) + + // estimate the gas fee and storage deposit + gas2, gasFee2, err := chain.EstimateGasOnLedger(req, userWallet, true) + require.NoError(t, err) + storageDeposit2 := chain.EstimateNeededStorageDeposit(req, userWallet) + + // send the withdraw request + req.WithGasBudget(gas2). + AddBaseTokens(gasFee2 + storageDeposit2). // including base tokens for gas fee and storage + AddAllowanceBaseTokens(storageDeposit2) // and withdrawing the storage as well + _, err = chain.PostRequestSync(req, userWallet) + require.NoError(t, err) + + // we are back to the initial situation, having been charged some gas fees + // in the process: + env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount-gasFee1-gasFee2) + chain.AssertL2BaseTokens(userAgentID, 0) +} +``` + +The example above creates a chain and a wallet with `utxodb.FundsFromFaucetAmount` base tokens on L1. +Then, it sends 1 million tokens to the corresponding on-chain account by posting a +[`deposit`](../../reference/core-contracts/accounts.md#deposit) request to the +[`accounts` core contract](../../reference/core-contracts/accounts.md) on the chain. + +Finally, it sends a [`withdraw`](../../reference/core-contracts/accounts.md#withdraw) request to the `accounts` core +contract to get the tokens back to L1. + +Both requests are affected by the gas fees and the storage deposit. +In some cases, it is possible to ignore these amounts if they are negligible compared to the transferred amounts. +In this case, however, we want to be very precise. + +### Deposit Requests + +#### 1. Request to Deposit Funds + +The first step in the deposit request is to create a request to deposit the funds with `solo.NewCallParams`. + +#### 2. Add Base Tokens + +In the example above we want to deposit 1 Mi, so we call `AddBaseTokens(1 * isc.Million)`. + +This instructs Solo to take that amount from the L1 balance and add it to the transaction. This is only possible for +on-ledger requests. + +#### 3. Calculate Gas Fees + +Once the chain executes the request, it will be charged a gas fee. + +We use `chain.EstimateGasOnLedger` before actually sending the request to estimate this fee. + +#### 4. Estimate Storage Deposit + +On-ledger requests also require a storage deposit. We use `EstimateNeededStorageDeposit` for this. As the 1 Mi already +included is enough for the storage deposit there’s no need to add more. + +#### 5. Add Gas Budget to the Request + +We adjust the request with the gas budget and the gas fee with `WithGasBudget` and `AddBaseTokens`, respectively. + +#### 6. Send the On-Ledger Request + +Finally, we send the on-ledger request with `PostRequestSync`. + +#### 7. The Chain Picks Up the Request + +Any attached base tokens (1 Mi + gas fee) are automatically credited to the sender's L2 account. + +#### 8. The chain executes the request + +The gas fee is deducted from the sender's L2 account. + +#### 9. The Transfer is Complete + +We have exactly 1 Mi on our L2 balance. + +### Withdraw Request + +The process for the `withdraw` request is similar to the [deposit process](#deposit-requests), with two main +differences: + +#### 1. Ensure the L1 Transaction Can Cover the Storage Deposit + +As the storage deposit is larger than the gas fee, we must ensure that the L1 transaction contains enough funds for the +storage deposit. These tokens are automatically deposited in our L2 account, and we immediately withdraw them. + +#### 2.Set the Request's Allowance + +We use `AddAllowanceBaseTokens` to set the _allowance_ of our request. The allowance specifies the maximum amount of +tokens the smart contract can debit from the sender's L2 account. + +It would fail if we posted the same `deposit` request from another user wallet (another private key). +Try it! Only the address owner can move those funds from the on-chain account. + +You can also try removing the `AddAllowanceBaseTokens` call. It will fail because a smart contract cannot deduct funds from the +sender's L2 balance unless explicitly authorized by the allowance. diff --git a/docs/build/isc/v1.3-alpha/docs/solo/how-tos/timelock.mdx b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/timelock.mdx new file mode 100644 index 00000000000..d30cfade07b --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/timelock.mdx @@ -0,0 +1,131 @@ +--- +tags: + - testing + - colored tokens + - time locks + - solo + - plain iotas + - balance + - mint + - delay + +description: You can post a time-locked request by using the Delay() method. You can mint NFTs by using the MintNFT() method. +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Minting NFTs and Time Locks + +Let's examine some less commonly used member functions of the SoloContext. We will switch +to the `fairauction` example to show their usage. Here is the `startAuction()` function of +the `fairauction` test suite: + + + + + +```go +const ( + description = "Cool NFTs for sale!" + deposit = uint64(1000) + minBid = uint64(500) +) + +func startAuction(t *testing.T) (*wasmsolo.SoloContext, *wasmsolo.SoloAgent, wasmtypes.ScNftID) { + ctx := wasmsolo.NewSoloContext(t, fairauction.ScName, fairauction.OnDispatch) + auctioneer := ctx.NewSoloAgent() + nftID := ctx.MintNFT(auctioneer, []byte("NFT metadata")) + require.NoError(t, ctx.Err) + + // start the auction + sa := fairauction.ScFuncs.StartAuction(ctx.Sign(auctioneer)) + sa.Params.MinimumBid().SetValue(minBid) + sa.Params.Description().SetValue(description) + transfer := wasmlib.NewScTransferBaseTokens(deposit) // deposit, must be >=minimum*margin + transfer.AddNFT(&nftID) + sa.Func.Transfer(transfer).Post() + require.NoError(t, ctx.Err) + + return ctx, auctioneer, nftID +} +``` + + + + +The function first sets up the SoloContext as usual, and then it performs quite a bit of +extra work. This is because we want the startAuction() function to start an auction, so +that the tests that subsequently use startAuction() can then focus on testing all kinds of +bidding and auction results. + +First, we are going to need an agent that functions as the `auctioneer`. This auctioneer +will auction off an NFT. To provide the auctioneer with this NFT we use the `MintNFT()` +method to mint a fresh NFT into his account. The minting process will assign a unique NFT +ID. Of course, we check that no error occurred during the minting process. + +Now we are going to start the auction by calling the `startAuction` function of the +`fairauction` contract. We get the function descriptor in the usual way, but we also call +the `Sign()` method of the SoloContext to make sure that the transaction we are about to +post takes its assets from the auctioneer address, and the transaction will be signed with +the corresponding private key. Very often you won't care who posts a request, and we have +set it up in such a way that by default tokens come from the chain originator address, +which has been seeded with tokens just for this occasion. But whenever it is important +where the tokens come from, or who invokes the request, you need to specify the agent +involved by using the Sign() method. + +Next we set up the function parameters as usual. After the parameters have been set up, we +see something new happening. We create an `ScTransfer` proxy and initialize it with the +base tokens that we need to deposit, plus the freshly minted NFT that we are auctioning. +Next we use the `Transfer()` method to pass this proxy before posting the request. This is +exactly how we would do it from within the smart contract code. Note that the function +`NewScTransferBaseTokens()` is used as a shorthand to immediately initialize the new +`ScTransfer` proxy with the desired amount of base tokens. + +Finally, we make sure there was no error after posting the request and return the +SoloContext, `auctioneer` and `nftID`. That concludes the startAuction() function. + +Here is the first test function that uses our startAuction() function: + + + + + +```go +func TestStartAuction(t *testing.T) { + ctx, auctioneer, nftID := startAuction(t) + + nfts := ctx.Chain.L2NFTs(auctioneer.AgentID()) + require.Len(t, nfts, 0) + nfts = ctx.Chain.L2NFTs(ctx.Account().AgentID()) + require.Len(t, nfts, 1) + require.Equal(t, nftID, ctx.Cvt.ScNftID(&nfts[0])) + + // remove pending finalize_auction from backlog + ctx.AdvanceClockBy(61 * time.Minute) + require.True(t, ctx.WaitForPendingRequests(1)) +} +``` + + + + +This test function checks that the NFT was moved by `startAuction` from the auctioneer's +on-chain account to the chain's on-chain account. + +The `startAuction` function of the smart contract will also have posted a time-locked +request to the `finalizeAuction` function by using the `Delay()` method. Therefore, we +need to remove the pending `finalizeAuction` request from the backlog. + +First we move the logical clock forward to a point in time when that request is supposed +to have been triggered. Then we wait for this request to actually be processed. Note that +this will happen in a separate goroutine in the background, so we explicitly wait for the +request counters to catch up with the one request that is pending. + +The `WaitForPendingRequests()` method can also be used whenever a smart contract function +is known to [`post()`](../../schema/how-tos/post.mdx) a request to itself. Such requests are not immediately +executed, but added to the backlog, so you need to wait for these pending requests to +actually be processed. The advantage of having to explicitly wait for those requests is +that you can inspect the in-between state, which means that you can test even a function +that posts a request in isolation. diff --git a/docs/build/isc/v1.3-alpha/docs/solo/how-tos/view-sc.md b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/view-sc.md new file mode 100644 index 00000000000..2bac649b39e --- /dev/null +++ b/docs/build/isc/v1.3-alpha/docs/solo/how-tos/view-sc.md @@ -0,0 +1,74 @@ +--- +description: Calling smart contract view functions with Solo. +image: /img/tutorial/call_view.png +tags: + - how to + - testing + - solo + - views + - call + - synchronous + - entry points +--- + +# Calling a View + +The following snippet shows how you can call the view function `getString` of the smart contract `solotutorial` without +parameters: + +```go +res, err := chain.CallView("example1", "getString") +``` + +The call returns a collection of key/value pairs `res` and an error result `err` in the typical Go fashion. + +[![Calling a view process](/img/tutorial/call_view.png)](/img/tutorial/call_view.png) + +The basic principle of calling a view is similar to sending a request to the smart contract. The essential difference is +that calling a view does not constitute an asynchronous transaction; it is just a direct synchronous call to the view +entry point exposed by the smart contract. + +Therefore, calling a view does not involve any token transfers. Sending a request (either on-ledger or off-ledger) to a +view entry point will result in an exception, returning all attached tokens to the sender minus fees (iif any). + +Views are used to retrieve information about the smart contract's state, for example, to display on a website. Certain +Solo methods such as `chain.GetInfo`, `chain.GetGasFeePolicy`, and `chain.L2Assets` call views of +the [core smart contracts](../../reference/core-contracts/overview.md) behind the scenes to retrieve the information +about the chain or a specific smart contract. + +## Decoding Results Returned by _PostRequestSync_ and _CallView_ + +The following is a specific technicality of the Go environment of _Solo_. + +The result returned by the call to an entry point from the Solo environment is an instance of +the [`dict.Dict`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/dict/dict.go) type, which is essentially a +map of `[]byte` key/value pairs, defined as: + +```go +type Dict map[kv.Key][]byte +``` + +`Dict` is also an implementation of +the [`kv.KVStore`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/kv.go) interface. The `kv` package and +subpackages provide many useful functions to work with the `Dict` type. + +:::note + +Both view and non-view entry points can produce results. +In normal operation, retrieving the result of an on-ledger request is impossible since it is an asynchronous operation. + +However, in the Solo environment, the call to `PostRequestSync` is synchronous, allowing the caller to inspect the +result. +This is a convenient difference between the mocked Solo environment and the distributed ledger used by Wasp nodes. +You can use it to make assertions about the results of a call in the tests. + +::: + +In the example above, `res` is a dictionary where keys and values are binary slices. The `getString` view returns the +value under the `"str"` key, and the value is a `string` encoded as a byte slice. The `codec` package provides functions +to encode/decode frequently used data types, including `string`. The following is a commonly used pattern to get a value +from the `Dict` and decode it: + +```go +var value string = codec.MustDecodeString(res["str"]) +``` diff --git a/docs/build/isc/v1.3-alpha/sidebars.js b/docs/build/isc/v1.3-alpha/sidebars.js new file mode 100644 index 00000000000..a01017561cc --- /dev/null +++ b/docs/build/isc/v1.3-alpha/sidebars.js @@ -0,0 +1,504 @@ +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ + +const { directoryExists } = require('../../../../src/utils/config'); + +var iscutils_references = {}; +if (directoryExists(__dirname + '/docs/reference/iscutils')) { + iscutils_references = { + type: 'category', + label: 'ISC Utilities', + items: [ + { + type: 'autogenerated', + dirName: 'reference/iscutils', + }, + ], + }; +} + +module.exports = { + // By default, Docusaurus generates a sidebar from the docs folder structure + //tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + ISCSidebar: [ + { + type: 'doc', + label: 'Introduction', + id: 'introduction', + }, + { + type: 'category', + label: 'Getting Started', + items: [ + { + type: 'doc', + label: 'Languages & VMs', + id: 'getting-started/languages-and-vms', + }, + 'getting-started/quick-start', + 'getting-started/compatibility', + { + type: 'doc', + label: 'Networks & Chains', + id: 'getting-started/networks-and-chains', + }, + { + type: 'doc', + label: 'Tools', + id: 'getting-started/tools', + }, + ], + }, + { + type: 'category', + label: 'How To', + items: [ + 'how-tos/introduction', + { + type: 'doc', + label: 'Send Funds from L1 to L2', + id: 'how-tos/send-funds-from-L1-to-L2', + }, + { + type: 'doc', + label: 'Create a Basic Contract', + id: 'how-tos/create-a-basic-contract', + }, + { + type: 'doc', + label: 'Deploy a Smart Contract', + id: 'how-tos/deploy-a-smart-contract', + }, + { + type: 'doc', + label: 'Create Custom Tokens - ERC20', + id: 'how-tos/ERC20', + }, + { + type: 'doc', + label: 'Create NFTs - ERC721', + id: 'how-tos/ERC721', + }, + { + type: 'doc', + label: 'Test Smart Contracts', + id: 'how-tos/test-smart-contracts', + }, + { + type: 'category', + label: 'Interact with the Core Contracts', + items: [ + { + type: 'doc', + label: 'Introduction', + id: 'how-tos/core-contracts/introduction', + }, + { + type: 'category', + label: 'Basics', + items: [ + { + type: 'doc', + label: 'Get Native Assets Balance', + id: 'how-tos/core-contracts/basics/get-balance', + }, + { + type: 'category', + label: 'Allowance', + items: [ + { + type: 'doc', + label: 'Allow', + id: 'how-tos/core-contracts/basics/allowance/allow', + }, + { + type: 'doc', + label: 'Get Allowance', + id: 'how-tos/core-contracts/basics/allowance/get-allowance', + }, + { + type: 'doc', + label: 'Take Allowance', + id: 'how-tos/core-contracts/basics/allowance/take-allowance', + }, + ], + }, + { + type: 'doc', + label: 'Send Assets to L1', + id: 'how-tos/core-contracts/basics/send-assets-to-l1', + }, + ], + }, + { + type: 'category', + label: 'Token', + items: [ + { + label: 'Introduction', + type: 'doc', + id: 'how-tos/core-contracts/token/introduction', + }, + { + type: 'doc', + label: 'Create a Native Token', + id: 'how-tos/core-contracts/token/create-native-token', + }, + { + type: 'doc', + label: 'Mint Native Tokens', + id: 'how-tos/core-contracts/token/mint-token', + }, + { + type: 'doc', + label: 'Custom ERC20 Functions', + id: 'how-tos/core-contracts/token/erc20-native-token', + }, + { + type: 'doc', + label: 'Create a Foundry', + id: 'how-tos/core-contracts/token/create-foundry', + }, + { + type: 'doc', + label: 'Register Token as ERC20', + id: 'how-tos/core-contracts/token/register-token', + }, + ], + }, + { + type: 'category', + label: 'NFT', + items: [ + { + label: 'Introduction', + type: 'doc', + id: 'how-tos/core-contracts/nft/introduction', + }, + { + type: 'doc', + label: 'Mint an NFT', + id: 'how-tos/core-contracts/nft/mint-nft', + }, + { + type: 'doc', + label: 'Use as ERC721', + id: 'how-tos/core-contracts/nft/use-as-erc721', + }, + ], + }, + { + type: 'doc', + label: 'Get Randomness on L2', + id: 'how-tos/core-contracts/get-randomness-on-l2', + }, + { + type: 'doc', + label: 'Call and Call View', + id: 'how-tos/core-contracts/call-view', + }, + ], + }, + ], + }, + { + type: 'category', + label: 'Explanations', + items: [ + { + type: 'doc', + label: 'Anatomy of a Smart Contract', + id: 'explanations/smart-contract-anatomy', + }, + { + type: 'doc', + label: 'Sandbox Interface', + id: 'explanations/sandbox', + }, + { + type: 'doc', + label: 'Calling a Smart Contract', + id: 'explanations/invocation', + }, + { + type: 'doc', + label: 'State, Transitions and State Anchoring', + id: 'explanations/states', + }, + { + type: 'doc', + label: 'State manager', + id: 'explanations/state_manager', + }, + { + type: 'doc', + label: 'Validators and Access Nodes', + id: 'explanations/validators', + }, + { + type: 'doc', + label: 'Consensus', + id: 'explanations/consensus', + }, + { + type: 'doc', + label: 'How Accounts Work', + id: 'explanations/how-accounts-work', + }, + { + type: 'link', + label: 'Core Contracts', + href: '/isc/reference/core-contracts/overview', + }, + ], + }, + { + type: 'category', + label: 'Reference', + items: [ + 'reference/json-rpc-spec', + { + type: 'category', + label: 'Magic Contract', + items: [ + { + type: 'autogenerated', + dirName: 'reference/magic-contract', + }, + ], + }, + { + type: 'category', + label: 'Core Contracts', + items: [ + { + type: 'doc', + label: 'Overview', + id: 'reference/core-contracts/overview', + }, + { + type: 'doc', + label: 'root', + id: 'reference/core-contracts/root', + }, + { + type: 'doc', + label: 'accounts', + id: 'reference/core-contracts/accounts', + }, + { + type: 'doc', + label: 'blob', + id: 'reference/core-contracts/blob', + }, + { + type: 'doc', + label: 'blocklog', + id: 'reference/core-contracts/blocklog', + }, + { + type: 'doc', + label: 'governance', + id: 'reference/core-contracts/governance', + }, + { + type: 'doc', + label: 'errors', + id: 'reference/core-contracts/errors', + }, + { + type: 'doc', + label: 'EVM', + id: 'reference/core-contracts/evm', + }, + ], + }, + iscutils_references, + { + type: 'doc', + label: 'WasmLib Data Types', + id: 'reference/wasm-lib-data-types', + }, + ], + }, + { + type: 'category', + label: 'Test with Solo', + items: [ + { + label: 'Getting Started', + id: 'solo/getting-started', + type: 'doc', + }, + { + type: 'category', + label: 'How To', + items: [ + { + type: 'doc', + label: 'First Example', + id: 'solo/how-tos/first-example', + }, + { + type: 'doc', + label: 'The L1 Ledger', + id: 'solo/how-tos/the-l1-ledger', + }, + { + type: 'doc', + label: 'Deploy a Smart Contract', + id: 'solo/how-tos/deploying-sc', + }, + { + type: 'doc', + label: 'Invoke a Smart Contract', + id: 'solo/how-tos/invoking-sc', + }, + { + type: 'doc', + label: 'Call a View', + id: 'solo/how-tos/view-sc', + }, + { + type: 'doc', + label: 'Error Handling', + id: 'solo/how-tos/error-handling', + }, + { + type: 'doc', + label: 'Accounts', + id: 'solo/how-tos/the-l2-ledger', + }, + { + type: 'doc', + label: 'Test Smart Contracts', + id: 'solo/how-tos/test', + }, + { + type: 'doc', + label: 'Example Tests', + id: 'solo/how-tos/examples', + }, + { + type: 'doc', + label: 'Colored Tokens and Time Locks', + id: 'solo/how-tos/timelock', + }, + ], + }, + ], + }, + { + type: 'category', + label: 'Wasm - Schema Tool', + items: [ + { + type: 'doc', + label: 'The Schema Tool', + id: 'schema/introduction', + }, + { + type: 'doc', + label: 'Data Access Proxies', + id: 'schema/proxies', + }, + { + type: 'category', + label: 'How To', + items: [ + { + type: 'doc', + label: 'Create a Schema', + id: 'schema/how-tos/usage', + }, + { + type: 'doc', + label: 'Define the State', + id: 'schema/how-tos/state', + }, + { + type: 'doc', + label: 'Use Structured Data Types', + id: 'schema/how-tos/structs', + }, + { + type: 'doc', + label: 'Generate Type Definitions', + id: 'schema/how-tos/typedefs', + }, + { + type: 'doc', + label: 'Trigger Events', + id: 'schema/how-tos/events', + }, + { + type: 'doc', + label: 'Define Functions', + id: 'schema/how-tos/funcs', + }, + { + type: 'doc', + label: 'Limit Access', + id: 'schema/how-tos/access', + }, + { + type: 'doc', + label: 'Define Function Parameters', + id: 'schema/how-tos/params', + }, + { + type: 'doc', + label: 'Define Function Results', + id: 'schema/how-tos/results', + }, + { + type: 'doc', + label: 'Use Thunk Functions', + id: 'schema/how-tos/thunks', + }, + { + type: 'doc', + label: 'Use View-Only Functions', + id: 'schema/how-tos/views', + }, + { + type: 'doc', + label: 'Initialize a Smart Contract', + id: 'schema/how-tos/init', + }, + { + type: 'doc', + label: 'Transfer Tokens', + id: 'schema/how-tos/transfers', + }, + { + type: 'doc', + label: 'Add Function Descriptors', + id: 'schema/how-tos/funcdesc', + }, + { + type: 'doc', + label: 'Call Functions', + id: 'schema/how-tos/call', + }, + { + type: 'doc', + label: 'Post Asynchronous Requests', + id: 'schema/how-tos/post', + }, + ], + }, + ], + }, + ], +}; diff --git a/docs/external/tips b/docs/external/tips index e30ee794290..b0590b73a30 160000 --- a/docs/external/tips +++ b/docs/external/tips @@ -1 +1 @@ -Subproject commit e30ee7942900e6d9343650d3c5325673951bb159 +Subproject commit b0590b73a30a56976e82017d25cb4e757c99ae36 diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/reference/configuration.md b/docs/maintain/wasp/v1.0.0-rc.6/docs/reference/configuration.md deleted file mode 100755 index 77533ecb703..00000000000 --- a/docs/maintain/wasp/v1.0.0-rc.6/docs/reference/configuration.md +++ /dev/null @@ -1,490 +0,0 @@ ---- -# !!! DO NOT MODIFY !!! -# This file is auto-generated by the gendoc tool based on the source code of the app. -description: This section describes the configuration parameters and their types for WASP. -tags: - - IOTA Node - - Hornet Node - - WASP Node - - Smart Contracts - - L2 - - Configuration - - JSON - - Customize - - Config - - reference ---- - -# Core Configuration - -WASP uses a JSON standard format as a config file. If you are unsure about JSON syntax, you can find more information in the [official JSON specs](https://www.json.org). - -You can change the path of the config file by using the `-c` or `--config` argument while executing `wasp` executable. - -For example: - -```shell -wasp -c config_defaults.json -``` - -You can always get the most up-to-date description of the config parameters by running: - -```shell -wasp -h --full -``` - -## 1. Application - -| Name | Description | Type | Default value | -| ------------------------- | ------------------------------------------------------ | ------- | ------------- | -| checkForUpdates | Whether to check for updates of the application or not | boolean | true | -| [shutdown](#app_shutdown) | Configuration for shutdown | object | | - -### Shutdown - -| Name | Description | Type | Default value | -| ------------------------ | ------------------------------------------------------------------------------------------------------ | ------ | ------------- | -| stopGracePeriod | The maximum time to wait for background processes to finish during shutdown before terminating the app | string | "5m" | -| [log](#app_shutdown_log) | Configuration for Shutdown Log | object | | - -### Shutdown Log - -| Name | Description | Type | Default value | -| -------- | --------------------------------------------------- | ------- | -------------- | -| enabled | Whether to store self-shutdown events to a log file | boolean | true | -| filePath | The file path to the self-shutdown log | string | "shutdown.log" | - -Example: - -```json -{ - "app": { - "checkForUpdates": true, - "shutdown": { - "stopGracePeriod": "5m", - "log": { - "enabled": true, - "filePath": "shutdown.log" - } - } - } -} -``` - -## 2. Logger - -| Name | Description | Type | Default value | -| ---------------------------------------- | --------------------------------------------------------------------------- | ------- | ------------- | -| level | The minimum enabled logging level | string | "info" | -| disableCaller | Stops annotating logs with the calling function's file name and line number | boolean | true | -| disableStacktrace | Disables automatic stacktrace capturing | boolean | false | -| stacktraceLevel | The level stacktraces are captured and above | string | "panic" | -| encoding | The logger's encoding (options: "json", "console") | string | "console" | -| [encodingConfig](#logger_encodingconfig) | Configuration for encodingConfig | object | | -| outputPaths | A list of URLs, file paths or stdout/stderr to write logging output to | array | stdout | -| disableEvents | Prevents log messages from being raced as events | boolean | true | - -### EncodingConfig - -| Name | Description | Type | Default value | -| ----------- | ---------------------------------------------------------------------------------------------------------- | ------ | ------------- | -| timeEncoder | Sets the logger's timestamp encoding. (options: "nanos", "millis", "iso8601", "rfc3339" and "rfc3339nano") | string | "rfc3339" | - -Example: - -```json -{ - "logger": { - "level": "info", - "disableCaller": true, - "disableStacktrace": false, - "stacktraceLevel": "panic", - "encoding": "console", - "encodingConfig": { - "timeEncoder": "rfc3339" - }, - "outputPaths": ["stdout"], - "disableEvents": true - } -} -``` - -## 3. INX - -| Name | Description | Type | Default value | -| --------------------- | -------------------------------------------------------------------------------------------------- | ------ | ---------------- | -| address | The INX address to which to connect to | string | "localhost:9029" | -| maxConnectionAttempts | The amount of times the connection to INX will be attempted before it fails (1 attempt per second) | uint | 30 | -| targetNetworkName | The network name on which the node should operate on (optional) | string | "" | - -Example: - -```json -{ - "inx": { - "address": "localhost:9029", - "maxConnectionAttempts": 30, - "targetNetworkName": "" - } -} -``` - -## 4. Database - -| Name | Description | Type | Default value | -| ---------------------------- | ---------------------------------------- | ------- | ------------- | -| engine | The used database engine (rocksdb/mapdb) | string | "rocksdb" | -| [chainState](#db_chainstate) | Configuration for chainState | object | | -| debugSkipHealthCheck | Ignore the check for corrupted databases | boolean | true | - -### ChainState - -| Name | Description | Type | Default value | -| ---- | -------------------------------------------- | ------ | -------------------- | -| path | The path to the chain state databases folder | string | "waspdb/chains/data" | - -Example: - -```json -{ - "db": { - "engine": "rocksdb", - "chainState": { - "path": "waspdb/chains/data" - }, - "debugSkipHealthCheck": true - } -} -``` - -## 5. P2p - -| Name | Description | Type | Default value | -| ------------------------- | -------------------------- | ------ | ------------- | -| [identity](#p2p_identity) | Configuration for identity | object | | -| [db](#p2p_db) | Configuration for Database | object | | - -### Identity - -| Name | Description | Type | Default value | -| ---------- | ------------------------------------------------------- | ------ | ------------------------------ | -| privateKey | Private key used to derive the node identity (optional) | string | "" | -| filePath | The path to the node identity PEM file | string | "waspdb/identity/identity.key" | - -### Database - -| Name | Description | Type | Default value | -| ---- | ---------------------------- | ------ | ----------------- | -| path | The path to the p2p database | string | "waspdb/p2pstore" | - -Example: - -```json -{ - "p2p": { - "identity": { - "privateKey": "", - "filePath": "waspdb/identity/identity.key" - }, - "db": { - "path": "waspdb/p2pstore" - } - } -} -``` - -## 6. Registries - -| Name | Description | Type | Default value | -| -------------------------------------------- | -------------------------------- | ------ | ------------- | -| [chains](#registries_chains) | Configuration for chains | object | | -| [dkShares](#registries_dkshares) | Configuration for dkShares | object | | -| [trustedPeers](#registries_trustedpeers) | Configuration for trustedPeers | object | | -| [consensusState](#registries_consensusstate) | Configuration for consensusState | object | | - -### Chains - -| Name | Description | Type | Default value | -| -------- | ----------------------------------- | ------ | ----------------------------------- | -| filePath | The path to the chain registry file | string | "waspdb/chains/chain_registry.json" | - -### DkShares - -| Name | Description | Type | Default value | -| ---- | -------------------------------------------------------- | ------ | ----------------- | -| path | The path to the distributed key shares registries folder | string | "waspdb/dkshares" | - -### TrustedPeers - -| Name | Description | Type | Default value | -| -------- | ------------------------------------------- | ------ | --------------------------- | -| filePath | The path to the trusted peers registry file | string | "waspdb/trusted_peers.json" | - -### ConsensusState - -| Name | Description | Type | Default value | -| ---- | ------------------------------------------------- | ------ | ------------------------- | -| path | The path to the consensus state registries folder | string | "waspdb/chains/consensus" | - -Example: - -```json -{ - "registries": { - "chains": { - "filePath": "waspdb/chains/chain_registry.json" - }, - "dkShares": { - "path": "waspdb/dkshares" - }, - "trustedPeers": { - "filePath": "waspdb/trusted_peers.json" - }, - "consensusState": { - "path": "waspdb/chains/consensus" - } - } -} -``` - -## 7. Peering - -| Name | Description | Type | Default value | -| ---------- | ---------------------------------------------------- | ------ | -------------- | -| peeringURL | Node host address as it is recognized by other peers | string | "0.0.0.0:4000" | -| port | Port for Wasp committee connection/peering | int | 4000 | - -Example: - -```json -{ - "peering": { - "peeringURL": "0.0.0.0:4000", - "port": 4000 - } -} -``` - -## 8. Chains - -| Name | Description | Type | Default value | -| -------------------------------- | ------------------------------------------------------------------------------------------------------- | ------- | ------------- | -| broadcastUpToNPeers | Number of peers an offledger request is broadcasted to | int | 2 | -| broadcastInterval | Time between re-broadcast of offledger requests | string | "5s" | -| apiCacheTTL | Time to keep processed offledger requests in api cache | string | "5m" | -| pullMissingRequestsFromCommittee | Whether or not to pull missing requests from other committee members | boolean | true | -| deriveAliasOutputByQuorum | False means we propose own AliasOutput, true - by majority vote. | boolean | true | -| pipeliningLimit | -1 -- infinite, 0 -- disabled, X -- build the chain if there is up to X transactions unconfirmed by L1. | int | -1 | -| consensusDelay | Minimal delay between consensus runs. | string | "500ms" | - -Example: - -```json -{ - "chains": { - "broadcastUpToNPeers": 2, - "broadcastInterval": "5s", - "apiCacheTTL": "5m", - "pullMissingRequestsFromCommittee": true, - "deriveAliasOutputByQuorum": true, - "pipeliningLimit": -1, - "consensusDelay": "500ms" - } -} -``` - -## 9. StateManager - -| Name | Description | Type | Default value | -| --------------------------------- | --------------------------------------------------------------------------------------------- | ------ | ------------- | -| blockCacheMaxSize | How many blocks may be stored in cache before old ones start being deleted | int | 1000 | -| blockCacheBlocksInCacheDuration | How long should the block stay in block cache before being deleted | string | "1h" | -| blockCacheBlockCleaningPeriod | How often should the block cache be cleaned | string | "1m" | -| stateManagerGetBlockRetry | How often get block requests should be repeated | string | "3s" | -| stateManagerRequestCleaningPeriod | How often requests waiting for response should be checked for expired context | string | "1s" | -| stateManagerTimerTickPeriod | How often timer tick fires in state manager | string | "1s" | -| pruningMinStatesToKeep | This number of states will always be available in the store; if 0 - store pruning is disabled | int | 10000 | -| pruningMaxStatesToDelete | On single store pruning attempt at most this number of states will be deleted | int | 1000 | - -Example: - -```json -{ - "stateManager": { - "blockCacheMaxSize": 1000, - "blockCacheBlocksInCacheDuration": "1h", - "blockCacheBlockCleaningPeriod": "1m", - "stateManagerGetBlockRetry": "3s", - "stateManagerRequestCleaningPeriod": "1s", - "stateManagerTimerTickPeriod": "1s", - "pruningMinStatesToKeep": 10000, - "pruningMaxStatesToDelete": 1000 - } -} -``` - -## 10. Validator - -| Name | Description | Type | Default value | -| ------- | ------------------------------------------------------------------------------------------------------------------ | ------ | ------------- | -| address | Bech32 encoded address to identify the node (as access node on gov contract and to collect validator fee payments) | string | "" | - -Example: - -```json -{ - "validator": { - "address": "" - } -} -``` - -## 11. Write-Ahead Logging - -| Name | Description | Type | Default value | -| ------- | -------------------------------------------- | ------- | ------------- | -| enabled | Whether the "write-ahead logging" is enabled | boolean | true | -| path | The path to the "write-ahead logging" folder | string | "waspdb/wal" | - -Example: - -```json -{ - "wal": { - "enabled": true, - "path": "waspdb/wal" - } -} -``` - -## 12. Web API - -| Name | Description | Type | Default value | -| ------------------------- | -------------------------------------------------------- | ------- | -------------- | -| enabled | Whether the web api plugin is enabled | boolean | true | -| bindAddress | The bind address for the node web api | string | "0.0.0.0:9090" | -| [auth](#webapi_auth) | Configuration for auth | object | | -| [limits](#webapi_limits) | Configuration for limits | object | | -| debugRequestLoggerEnabled | Whether the debug logging for requests should be enabled | boolean | false | - -### Auth - -| Name | Description | Type | Default value | -| --------------------------- | -------------------------------------- | ------ | ------------- | -| scheme | Selects which authentication to choose | string | "jwt" | -| [jwt](#webapi_auth_jwt) | Configuration for JWT Auth | object | | -| [basic](#webapi_auth_basic) | Configuration for Basic Auth | object | | -| [ip](#webapi_auth_ip) | Configuration for IP-based Auth | object | | - -### JWT Auth - -| Name | Description | Type | Default value | -| -------- | ------------------ | ------ | ------------- | -| duration | Jwt token lifetime | string | "24h" | - -### Basic Auth - -| Name | Description | Type | Default value | -| -------- | ----------------------------------------------- | ------ | ------------- | -| username | The username which grants access to the service | string | "wasp" | - -### IP-based Auth - -| Name | Description | Type | Default value | -| --------- | ---------------------------------------------------- | ----- | ------------- | -| whitelist | A list of ips that are allowed to access the service | array | 0.0.0.0 | - -### Limits - -| Name | Description | Type | Default value | -| ------------------------------ | ----------------------------------------------------------------------------- | ------ | ------------- | -| timeout | The timeout after which a long running operation will be canceled | string | "30s" | -| readTimeout | The read timeout for the HTTP request body | string | "10s" | -| writeTimeout | The write timeout for the HTTP response body | string | "1m" | -| maxBodyLength | The maximum number of characters that the body of an API call may contain | string | "2M" | -| maxTopicSubscriptionsPerClient | Defines the max amount of subscriptions per client. 0 = deactivated (default) | int | 0 | -| confirmedStateLagThreshold | The threshold that define a chain is unsynchronized | uint | 2 | - -Example: - -```json -{ - "webapi": { - "enabled": true, - "bindAddress": "0.0.0.0:9090", - "auth": { - "scheme": "jwt", - "jwt": { - "duration": "24h" - }, - "basic": { - "username": "wasp" - }, - "ip": { - "whitelist": ["0.0.0.0"] - } - }, - "limits": { - "timeout": "30s", - "readTimeout": "10s", - "writeTimeout": "1m", - "maxBodyLength": "2M", - "maxTopicSubscriptionsPerClient": 0, - "confirmedStateLagThreshold": 2 - }, - "debugRequestLoggerEnabled": false - } -} -``` - -## 13. Profiling - -| Name | Description | Type | Default value | -| ----------- | ------------------------------------------------- | ------- | ---------------- | -| enabled | Whether the profiling component is enabled | boolean | false | -| bindAddress | The bind address on which the profiler listens on | string | "localhost:6060" | - -Example: - -```json -{ - "profiling": { - "enabled": false, - "bindAddress": "localhost:6060" - } -} -``` - -## 14. ProfilingRecorder - -| Name | Description | Type | Default value | -| ------- | ----------------------------------------------- | ------- | ------------- | -| enabled | Whether the ProfilingRecorder plugin is enabled | boolean | false | - -Example: - -```json -{ - "profilingRecorder": { - "enabled": false - } -} -``` - -## 15. Prometheus - -| Name | Description | Type | Default value | -| ----------- | ------------------------------------------------------------ | ------- | -------------- | -| enabled | Whether the prometheus plugin is enabled | boolean | true | -| bindAddress | The bind address on which the Prometheus exporter listens on | string | "0.0.0.0:2112" | - -Example: - -```json -{ - "prometheus": { - "enabled": true, - "bindAddress": "0.0.0.0:2112" - } -} -``` diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/chain-management.md b/docs/maintain/wasp/v1.1/docs/how-tos/chain-management.md similarity index 100% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/chain-management.md rename to docs/maintain/wasp/v1.1/docs/how-tos/chain-management.md diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/running-a-node.md b/docs/maintain/wasp/v1.1/docs/how-tos/running-a-node.md similarity index 68% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/running-a-node.md rename to docs/maintain/wasp/v1.1/docs/how-tos/running-a-node.md index 9a9b995b53a..79b1f5040f2 100644 --- a/docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/running-a-node.md +++ b/docs/maintain/wasp/v1.1/docs/how-tos/running-a-node.md @@ -27,10 +27,8 @@ We recommend that you run the docker image on a server with: ## Set Up -Follow the instructions on the [hornet setup](/hornet/how_tos/using_docker/). +Clone and follow the instructions on the [node-docker-setup repo](https://github.com/iotaledger/node-docker-setup). :::note - -This how-to is meant to be used for a production-ready deployment. For local testing or development, please see the [IOTA Sandbox](/iota-sandbox/welcome). - +This is aimed at production-ready deployment. If you're looking to spawn a local node for testing/development, please see the [local-setup](https://github.com/iotaledger/wasp/tree/develop/tools/local-setup) ::: diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/running-an-access-node.md b/docs/maintain/wasp/v1.1/docs/how-tos/running-an-access-node.md similarity index 100% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/running-an-access-node.md rename to docs/maintain/wasp/v1.1/docs/how-tos/running-an-access-node.md diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/setting-up-a-chain.md b/docs/maintain/wasp/v1.1/docs/how-tos/setting-up-a-chain.md similarity index 100% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/setting-up-a-chain.md rename to docs/maintain/wasp/v1.1/docs/how-tos/setting-up-a-chain.md diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/wasp-cli.md b/docs/maintain/wasp/v1.1/docs/how-tos/wasp-cli.md similarity index 100% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/wasp-cli.md rename to docs/maintain/wasp/v1.1/docs/how-tos/wasp-cli.md diff --git a/docs/maintain/wasp/v1.1/docs/reference/configuration.md b/docs/maintain/wasp/v1.1/docs/reference/configuration.md new file mode 100755 index 00000000000..bfe1181b5b5 --- /dev/null +++ b/docs/maintain/wasp/v1.1/docs/reference/configuration.md @@ -0,0 +1,573 @@ +--- +# !!! DO NOT MODIFY !!! +# This file is auto-generated by the gendoc tool based on the source code of the app. +description: This section describes the configuration parameters and their types for WASP. +tags: + - IOTA Node + - Hornet Node + - WASP Node + - Smart Contracts + - L2 + - Configuration + - JSON + - Customize + - Config + - reference +--- + + +# Core Configuration + +WASP uses a JSON standard format as a config file. If you are unsure about JSON syntax, you can find more information in the [official JSON specs](https://www.json.org). + +You can change the path of the config file by using the `-c` or `--config` argument while executing `wasp` executable. + +For example: +```shell +wasp -c config_defaults.json +``` + +You can always get the most up-to-date description of the config parameters by running: + +```shell +wasp -h --full +``` + +## 1. Application + +| Name | Description | Type | Default value | +| ------------------------- | ------------------------------------------------------ | ------- | ------------- | +| checkForUpdates | Whether to check for updates of the application or not | boolean | true | +| [shutdown](#app_shutdown) | Configuration for shutdown | object | | + +### Shutdown + +| Name | Description | Type | Default value | +| ------------------------ | ------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| stopGracePeriod | The maximum time to wait for background processes to finish during shutdown before terminating the app | string | "5m" | +| [log](#app_shutdown_log) | Configuration for Shutdown Log | object | | + +### Shutdown Log + +| Name | Description | Type | Default value | +| -------- | --------------------------------------------------- | ------- | -------------- | +| enabled | Whether to store self-shutdown events to a log file | boolean | true | +| filePath | The file path to the self-shutdown log | string | "shutdown.log" | + +Example: + +```json + { + "app": { + "checkForUpdates": true, + "shutdown": { + "stopGracePeriod": "5m", + "log": { + "enabled": true, + "filePath": "shutdown.log" + } + } + } + } +``` + +## 2. Logger + +| Name | Description | Type | Default value | +| ---------------------------------------- | --------------------------------------------------------------------------- | ------- | ------------- | +| level | The minimum enabled logging level | string | "info" | +| disableCaller | Stops annotating logs with the calling function's file name and line number | boolean | true | +| disableStacktrace | Disables automatic stacktrace capturing | boolean | false | +| stacktraceLevel | The level stacktraces are captured and above | string | "panic" | +| encoding | The logger's encoding (options: "json", "console") | string | "console" | +| [encodingConfig](#logger_encodingconfig) | Configuration for encodingConfig | object | | +| outputPaths | A list of URLs, file paths or stdout/stderr to write logging output to | array | stdout | +| disableEvents | Prevents log messages from being raced as events | boolean | true | + +### EncodingConfig + +| Name | Description | Type | Default value | +| ----------- | ---------------------------------------------------------------------------------------------------------- | ------ | ------------- | +| timeEncoder | Sets the logger's timestamp encoding. (options: "nanos", "millis", "iso8601", "rfc3339" and "rfc3339nano") | string | "rfc3339" | + +Example: + +```json + { + "logger": { + "level": "info", + "disableCaller": true, + "disableStacktrace": false, + "stacktraceLevel": "panic", + "encoding": "console", + "encodingConfig": { + "timeEncoder": "rfc3339" + }, + "outputPaths": [ + "stdout" + ], + "disableEvents": true + } + } +``` + +## 3. INX + +| Name | Description | Type | Default value | +| --------------------- | -------------------------------------------------------------------------------------------------- | ------ | ---------------- | +| address | The INX address to which to connect to | string | "localhost:9029" | +| maxConnectionAttempts | The amount of times the connection to INX will be attempted before it fails (1 attempt per second) | uint | 30 | +| targetNetworkName | The network name on which the node should operate on (optional) | string | "" | + +Example: + +```json + { + "inx": { + "address": "localhost:9029", + "maxConnectionAttempts": 30, + "targetNetworkName": "" + } + } +``` + +## 4. Cache + +| Name | Description | Type | Default value | +| ------------------ | -------------------------------------- | ------- | ------------- | +| cacheSize | Cache size | string | "64MiB" | +| cacheStatsInterval | Interval for printing cache statistics | string | "30s" | +| enabled | Whether the cache plugin is enabled | boolean | true | + +Example: + +```json + { + "cache": { + "cacheSize": "64MiB", + "cacheStatsInterval": "30s", + "enabled": true + } + } +``` + +## 5. Database + +| Name | Description | Type | Default value | +| ---------------------------- | ---------------------------------------- | ------- | ------------- | +| engine | The used database engine (rocksdb/mapdb) | string | "rocksdb" | +| [chainState](#db_chainstate) | Configuration for chainState | object | | +| debugSkipHealthCheck | Ignore the check for corrupted databases | boolean | true | + +### ChainState + +| Name | Description | Type | Default value | +| --------- | -------------------------------------------- | ------ | -------------------- | +| path | The path to the chain state databases folder | string | "waspdb/chains/data" | +| cacheSize | Size of the RocksDB block cache | uint | 33554432 | + +Example: + +```json + { + "db": { + "engine": "rocksdb", + "chainState": { + "path": "waspdb/chains/data", + "cacheSize": 33554432 + }, + "debugSkipHealthCheck": true + } + } +``` + +## 6. P2p + +| Name | Description | Type | Default value | +| ------------------------- | -------------------------- | ------ | ------------- | +| [identity](#p2p_identity) | Configuration for identity | object | | +| [db](#p2p_db) | Configuration for Database | object | | + +### Identity + +| Name | Description | Type | Default value | +| ---------- | ------------------------------------------------------- | ------ | ------------------------------ | +| privateKey | Private key used to derive the node identity (optional) | string | "" | +| filePath | The path to the node identity PEM file | string | "waspdb/identity/identity.key" | + +### Database + +| Name | Description | Type | Default value | +| ---- | ---------------------------- | ------ | ----------------- | +| path | The path to the p2p database | string | "waspdb/p2pstore" | + +Example: + +```json + { + "p2p": { + "identity": { + "privateKey": "", + "filePath": "waspdb/identity/identity.key" + }, + "db": { + "path": "waspdb/p2pstore" + } + } + } +``` + +## 7. Registries + +| Name | Description | Type | Default value | +| -------------------------------------------- | -------------------------------- | ------ | ------------- | +| [chains](#registries_chains) | Configuration for chains | object | | +| [dkShares](#registries_dkshares) | Configuration for dkShares | object | | +| [trustedPeers](#registries_trustedpeers) | Configuration for trustedPeers | object | | +| [consensusState](#registries_consensusstate) | Configuration for consensusState | object | | + +### Chains + +| Name | Description | Type | Default value | +| -------- | ----------------------------------- | ------ | ----------------------------------- | +| filePath | The path to the chain registry file | string | "waspdb/chains/chain_registry.json" | + +### DkShares + +| Name | Description | Type | Default value | +| ---- | -------------------------------------------------------- | ------ | ----------------- | +| path | The path to the distributed key shares registries folder | string | "waspdb/dkshares" | + +### TrustedPeers + +| Name | Description | Type | Default value | +| -------- | ------------------------------------------- | ------ | --------------------------- | +| filePath | The path to the trusted peers registry file | string | "waspdb/trusted_peers.json" | + +### ConsensusState + +| Name | Description | Type | Default value | +| ---- | ------------------------------------------------- | ------ | ------------------------- | +| path | The path to the consensus state registries folder | string | "waspdb/chains/consensus" | + +Example: + +```json + { + "registries": { + "chains": { + "filePath": "waspdb/chains/chain_registry.json" + }, + "dkShares": { + "path": "waspdb/dkshares" + }, + "trustedPeers": { + "filePath": "waspdb/trusted_peers.json" + }, + "consensusState": { + "path": "waspdb/chains/consensus" + } + } + } +``` + +## 8. Peering + +| Name | Description | Type | Default value | +| ---------- | ---------------------------------------------------- | ------ | -------------- | +| peeringURL | Node host address as it is recognized by other peers | string | "0.0.0.0:4000" | +| port | Port for Wasp committee connection/peering | int | 4000 | + +Example: + +```json + { + "peering": { + "peeringURL": "0.0.0.0:4000", + "port": 4000 + } + } +``` + +## 9. Chains + +| Name | Description | Type | Default value | +| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------- | +| broadcastUpToNPeers | Number of peers an offledger request is broadcasted to | int | 2 | +| broadcastInterval | Time between re-broadcast of offledger requests; 0 value means that re-broadcasting is disabled | string | "0s" | +| apiCacheTTL | Time to keep processed offledger requests in api cache | string | "5m" | +| pullMissingRequestsFromCommittee | Whether or not to pull missing requests from other committee members | boolean | true | +| deriveAliasOutputByQuorum | False means we propose own AliasOutput, true - by majority vote. | boolean | true | +| pipeliningLimit | -1 -- infinite, 0 -- disabled, X -- build the chain if there is up to X transactions unconfirmed by L1. | int | -1 | +| postponeRecoveryMilestones | Number of milestones to wait until a chain transition is considered as rejected | int | 3 | +| consensusDelay | Minimal delay between consensus runs. | string | "500ms" | +| recoveryTimeout | Time after which another consensus attempt is made. | string | "20s" | +| redeliveryPeriod | The resend period for msg. | string | "2s" | +| printStatusPeriod | The period to print consensus instance status. | string | "3s" | +| consensusInstsInAdvance | | int | 3 | +| awaitReceiptCleanupEvery | For every this number AwaitReceipt will be cleaned up | int | 100 | +| mempoolTTL | Time that requests are allowed to sit in the mempool without being processed | string | "24h" | +| mempoolMaxOffledgerInPool | Maximum number of off-ledger requests kept in the mempool | int | 2000 | +| mempoolMaxOnledgerInPool | Maximum number of on-ledger requests kept in the mempool | int | 1000 | +| mempoolMaxTimedInPool | Maximum number of timed on-ledger requests kept in the mempool | int | 100 | +| mempoolMaxOffledgerToPropose | Maximum number of off-ledger requests to propose for the next block | int | 500 | +| mempoolMaxOnledgerToPropose | Maximum number of on-ledger requests to propose for the next block (includes timed requests) | int | 100 | +| mempoolOnLedgerRefreshMinInterval | Minimum interval to try to refresh the list of on-ledger requests after some have been dropped from the pool (this interval is introduced to avoid dropping/refreshing cycle if there are too many requests on L1 to process) | string | "10m" | + +Example: + +```json + { + "chains": { + "broadcastUpToNPeers": 2, + "broadcastInterval": "0s", + "apiCacheTTL": "5m", + "pullMissingRequestsFromCommittee": true, + "deriveAliasOutputByQuorum": true, + "pipeliningLimit": -1, + "postponeRecoveryMilestones": 3, + "consensusDelay": "500ms", + "recoveryTimeout": "20s", + "redeliveryPeriod": "2s", + "printStatusPeriod": "3s", + "consensusInstsInAdvance": 3, + "awaitReceiptCleanupEvery": 100, + "mempoolTTL": "24h", + "mempoolMaxOffledgerInPool": 2000, + "mempoolMaxOnledgerInPool": 1000, + "mempoolMaxTimedInPool": 100, + "mempoolMaxOffledgerToPropose": 500, + "mempoolMaxOnledgerToPropose": 100, + "mempoolOnLedgerRefreshMinInterval": "10m" + } + } +``` + +## 10. Snapshots + +| Name | Description | Type | Default value | +| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------------- | +| snapshotsToLoad | List of snapshots to load; can be either single block hash of a snapshot (if a single chain has to be configured) or list of `:` to configure many chains | array | | +| period | How often state snapshots should be made: 1000 meaning "every 1000th state", 0 meaning "making snapshots is disabled" | uint | 0 | +| delay | How many states should pass before snapshot is produced | uint | 20 | +| localPath | The path to the snapshots folder in this node's disk | string | "waspdb/snap" | +| networkPaths | The list of paths to the remote (http(s)) snapshot locations; each of listed locations must contain 'INDEX' file with list of snapshot files | array | | + +Example: + +```json + { + "snapshots": { + "snapshotsToLoad": [], + "period": 0, + "delay": 20, + "localPath": "waspdb/snap", + "networkPaths": [] + } + } +``` + +## 11. StateManager + +| Name | Description | Type | Default value | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| blockCacheMaxSize | How many blocks may be stored in cache before old ones start being deleted | int | 1000 | +| blockCacheBlocksInCacheDuration | How long should the block stay in block cache before being deleted | string | "1h" | +| blockCacheBlockCleaningPeriod | How often should the block cache be cleaned | string | "1m" | +| stateManagerGetBlockNodeCount | How many nodes should get block request be sent to | int | 5 | +| stateManagerGetBlockRetry | How often get block requests should be repeated | string | "3s" | +| stateManagerRequestCleaningPeriod | How often requests waiting for response should be checked for expired context | string | "5m" | +| stateManagerStatusLogPeriod | How often state manager status information should be written to log | string | "1m" | +| stateManagerTimerTickPeriod | How often timer tick fires in state manager | string | "1s" | +| pruningMinStatesToKeep | This number of states will always be available in the store; if 0 - store pruning is disabled | int | 10000 | +| pruningMaxStatesToDelete | On single store pruning attempt at most this number of states will be deleted; NOTE: pruning takes considerable amount of time; setting this parameter large may seriously damage Wasp responsiveness if many blocks require pruning | int | 10 | + +Example: + +```json + { + "stateManager": { + "blockCacheMaxSize": 1000, + "blockCacheBlocksInCacheDuration": "1h", + "blockCacheBlockCleaningPeriod": "1m", + "stateManagerGetBlockNodeCount": 5, + "stateManagerGetBlockRetry": "3s", + "stateManagerRequestCleaningPeriod": "5m", + "stateManagerStatusLogPeriod": "1m", + "stateManagerTimerTickPeriod": "1s", + "pruningMinStatesToKeep": 10000, + "pruningMaxStatesToDelete": 10 + } + } +``` + +## 12. Validator + +| Name | Description | Type | Default value | +| ------- | ------------------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| address | Bech32 encoded address to identify the node (as access node on gov contract and to collect validator fee payments) | string | "" | + +Example: + +```json + { + "validator": { + "address": "" + } + } +``` + +## 13. Write-Ahead Logging + +| Name | Description | Type | Default value | +| ----------- | ---------------------------------------------------------------- | ------- | ------------- | +| loadToStore | Load blocks from "write-ahead log" to the store on node start-up | boolean | false | +| enabled | Whether the "write-ahead logging" is enabled | boolean | true | +| path | The path to the "write-ahead logging" folder | string | "waspdb/wal" | + +Example: + +```json + { + "wal": { + "loadToStore": false, + "enabled": true, + "path": "waspdb/wal" + } + } +``` + +## 14. Web API + +| Name | Description | Type | Default value | +| ------------------------- | ------------------------------------------------------------------------------------------ | ------- | --------------------- | +| enabled | Whether the web api plugin is enabled | boolean | true | +| bindAddress | The bind address for the node web api | string | "0.0.0.0:9090" | +| [auth](#webapi_auth) | Configuration for auth | object | | +| indexDbPath | Directory for storing indexes of historical data (only archive nodes will create/use them) | string | "waspdb/chains/index" | +| [limits](#webapi_limits) | Configuration for limits | object | | +| debugRequestLoggerEnabled | Whether the debug logging for requests should be enabled | boolean | false | + +### Auth + +| Name | Description | Type | Default value | +| ----------------------- | -------------------------------------- | ------ | ------------- | +| scheme | Selects which authentication to choose | string | "jwt" | +| [jwt](#webapi_auth_jwt) | Configuration for JWT Auth | object | | + +### JWT Auth + +| Name | Description | Type | Default value | +| -------- | ------------------ | ------ | ------------- | +| duration | Jwt token lifetime | string | "24h" | + +### Limits + +| Name | Description | Type | Default value | +| --------------------------------- | ----------------------------------------------------------------------------- | ------ | ------------- | +| timeout | The timeout after which a long running operation will be canceled | string | "30s" | +| readTimeout | The read timeout for the HTTP request body | string | "10s" | +| writeTimeout | The write timeout for the HTTP response body | string | "1m" | +| maxBodyLength | The maximum number of characters that the body of an API call may contain | string | "2M" | +| maxTopicSubscriptionsPerClient | Defines the max amount of subscriptions per client. 0 = deactivated (default) | int | 0 | +| confirmedStateLagThreshold | The threshold that define a chain is unsynchronized | uint | 2 | +| [jsonrpc](#webapi_limits_jsonrpc) | Configuration for jsonrpc | object | | + +### Jsonrpc + +| Name | Description | Type | Default value | +| ----------------------------------- | -------------------------------------------------------------- | ------ | ------------- | +| maxBlocksInLogsFilterRange | Maximum amount of blocks in eth_getLogs filter range | int | 1000 | +| maxLogsInResult | Maximum amount of logs in eth_getLogs result | int | 10000 | +| websocketRateLimitMessagesPerSecond | The websocket rate limit (messages per second) | int | 20 | +| websocketRateLimitBurst | The websocket burst limit | int | 5 | +| websocketConnectionCleanupDuration | Defines in which interval stale connections will be cleaned up | string | "5m" | +| websocketClientBlockDuration | The duration a misbehaving client will be blocked | string | "5m" | + +Example: + +```json + { + "webapi": { + "enabled": true, + "bindAddress": "0.0.0.0:9090", + "auth": { + "scheme": "jwt", + "jwt": { + "duration": "24h" + } + }, + "indexDbPath": "waspdb/chains/index", + "limits": { + "timeout": "30s", + "readTimeout": "10s", + "writeTimeout": "1m", + "maxBodyLength": "2M", + "maxTopicSubscriptionsPerClient": 0, + "confirmedStateLagThreshold": 2, + "jsonrpc": { + "maxBlocksInLogsFilterRange": 1000, + "maxLogsInResult": 10000, + "websocketRateLimitMessagesPerSecond": 20, + "websocketRateLimitBurst": 5, + "websocketConnectionCleanupDuration": "5m", + "websocketClientBlockDuration": "5m" + } + }, + "debugRequestLoggerEnabled": false + } + } +``` + +## 15. Profiling + +| Name | Description | Type | Default value | +| ----------- | ------------------------------------------------- | ------- | ---------------- | +| enabled | Whether the profiling component is enabled | boolean | false | +| bindAddress | The bind address on which the profiler listens on | string | "localhost:6060" | + +Example: + +```json + { + "profiling": { + "enabled": false, + "bindAddress": "localhost:6060" + } + } +``` + +## 16. ProfilingRecorder + +| Name | Description | Type | Default value | +| ------- | ----------------------------------------------- | ------- | ------------- | +| enabled | Whether the ProfilingRecorder plugin is enabled | boolean | false | + +Example: + +```json + { + "profilingRecorder": { + "enabled": false + } + } +``` + +## 17. Prometheus + +| Name | Description | Type | Default value | +| ----------- | ------------------------------------------------------------ | ------- | -------------- | +| enabled | Whether the prometheus plugin is enabled | boolean | true | +| bindAddress | The bind address on which the Prometheus exporter listens on | string | "0.0.0.0:2112" | + +Example: + +```json + { + "prometheus": { + "enabled": true, + "bindAddress": "0.0.0.0:2112" + } + } +``` + diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/reference/metrics.md b/docs/maintain/wasp/v1.1/docs/reference/metrics.md similarity index 100% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/reference/metrics.md rename to docs/maintain/wasp/v1.1/docs/reference/metrics.md diff --git a/docs/maintain/wasp/v1.0.0-rc.6/sidebars.js b/docs/maintain/wasp/v1.1/sidebars.js similarity index 100% rename from docs/maintain/wasp/v1.0.0-rc.6/sidebars.js rename to docs/maintain/wasp/v1.1/sidebars.js diff --git a/docs/maintain/wasp/v1.3-alpha/docs/how-tos/chain-management.md b/docs/maintain/wasp/v1.3-alpha/docs/how-tos/chain-management.md new file mode 100644 index 00000000000..b6273d1dd93 --- /dev/null +++ b/docs/maintain/wasp/v1.3-alpha/docs/how-tos/chain-management.md @@ -0,0 +1,74 @@ +--- +description: 'How to manage a chain using the Grafana dashboard, a client to receive published events, logging, and +validators.' +image: /img/logo/WASP_logo_dark.png +tags: + + - Smart Contracts + - Chain + - Management + - Grafana + +--- + +# Manage a Chain + +## Monitoring + +You can view the chain state using the dashboard (`/wasp/dashboard` when using `node-docker-setup`). + +## Manage Chain Configuration and Validators + +You can manage the chain configuration and committee of validators by interacting with +the [Governance contract](/isc/reference/core-contracts/governance). + +The “Chain Owner” is the only one who can perform administrative tasks. + +### Change Chain Ownership + +To change the chain ownership, the current “Chain Owner” must call `delegateChainOwnership` specifying the `agentID` of +the next owner. The next owner must call `claimChainOwnership` to finalize the process. + +### Change Access Nodes + +For new access nodes to join the network, they need to: + +- Be added as a trusted peer to at least 1 of the existing nodes. +- Be added by the administrator to the list of access nodes by calling `changeAccessNodes`. There is a helper in + wasp-cli to do so: + +```shell +wasp-cli chain gov-change-access-nodes accept +``` + +After this, new nodes should be able to sync the state and execute view queries (call view entry points). + +You can remove an access node by calling `changeAccessNodes`. + +Alternatively, you can add "non-permissioned" access nodes without the signature from the chain owner to add any node as an "access node". +You can do this by using the following command: + +```shell +wasp-cli chain access-nodes +``` + +This node won't be "officially" recognized by the committee but will still be able to sync the state and provide all regular functionality. + +### Change the Set of Validators + +You can do this in different ways, depending on who controls the [governor address](/tips/tips/TIP-0018#alias-output) +from the alias output of the chain. + +- If the chain governor address is the chain committee, you can perform the rotation by calling + `rotateStateController` after adding the next state controller via `addAllowedStateControllerAddress`. +- If the chain governor address is a regular user wallet that you control, you can issue the rotation transaction using wasp-cli: + +```shell +wasp-cli chain rotate +``` + +Or: + +```shell +wasp-cli chain rotate-with-dkg --peers=<...> +``` diff --git a/docs/maintain/wasp/v1.3-alpha/docs/how-tos/running-a-node.md b/docs/maintain/wasp/v1.3-alpha/docs/how-tos/running-a-node.md new file mode 100644 index 00000000000..79b1f5040f2 --- /dev/null +++ b/docs/maintain/wasp/v1.3-alpha/docs/how-tos/running-a-node.md @@ -0,0 +1,34 @@ +--- +description: How to run a node. Requirements, configuration parameters, dashboard configuration, and tests. +image: /img/logo/WASP_logo_dark.png +tags: + - Smart Contracts + - Running a node + - Go-lang + - Hornet + - Requirements + - Configuration + - Dashboard + - Grafana + - Prometheus +--- + +# Running a Node + +As Wasp is an INX plugin, you must run the wasp node alongside your _hornet node_. You can use the simple docker-compose setup to do so. + +## Recommended Hardware Requirements + +We recommend that you run the docker image on a server with: + +* **CPU**: 8 core. +* **RAM**: 16 GB. +* **Disk space**: ~ 250 GB SSD, depending on your pruning configuration. + +## Set Up + +Clone and follow the instructions on the [node-docker-setup repo](https://github.com/iotaledger/node-docker-setup). + +:::note +This is aimed at production-ready deployment. If you're looking to spawn a local node for testing/development, please see the [local-setup](https://github.com/iotaledger/wasp/tree/develop/tools/local-setup) +::: diff --git a/docs/maintain/wasp/v1.3-alpha/docs/how-tos/running-an-access-node.md b/docs/maintain/wasp/v1.3-alpha/docs/how-tos/running-an-access-node.md new file mode 100644 index 00000000000..f0baa0b5429 --- /dev/null +++ b/docs/maintain/wasp/v1.3-alpha/docs/how-tos/running-an-access-node.md @@ -0,0 +1,228 @@ +--- +description: How to setup an access node. +image: /img/logo/WASP_logo_dark.png +tags: + - Smart Contracts + - Running a node + - ISC +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Running an ISC Access Node + +## Set Up Wasp and Hornet + +First, you should [set up a Wasp Node](./running-a-node.md) but don't run `docker compose up` to start the docker containers yet. Continue with the following steps first: + +### Download the Chain State + +You can configure how much of the state you wish to keep on your node by uncommenting and changing the `WASP_PRUNING_MIN_STATES_TO_KEEP` environment variable in the node-docker-setup. The default value is 10000 blocks. + +### Run a Non-archive Node + +If you wish to run a non-archive node (only keep the last N blocks), you must uncomment `WASP_SNAPSHOT_NETWORK_PATHS`. + +### Run An Archive Node + +If you wish to have a full archive node, you need to set `WASP_PRUNING_MIN_STATES_TO_KEEP` to `0` and comment `WASP_SNAPSHOT_NETWORK_PATHS` out. + +You can then download the historical state using the following command (this will take a while): + + + + + +```sh +wget https://files.shimmer.network/dbs/wasp/latest-wasp_chains_wal.tgz -O - | tar xzv -C data/wasp +``` + + + + +```sh +wget https://files.testnet.shimmer.network/dbs/wasp/latest-wasp_chains_wal.tgz -O - | tar xzv -C data/wasp +``` + + + + +:::note Disk Space + +Operating as a full archive node requires a lot of disk space. We recommend at least 500Gb of free space to operate without issues + +::: + +### Run Everything + +```sh +docker compose up -d +``` + +It will take a few minutes until the hornet node is synced. + +You can check the sync status by following the logs with `docker logs -f hornet`, or in the web dashboard. + +## Use Wasp-Cli to configure the chain and add peers +### Download Wasp-Cli + +You can download a Wasp-Cli that matches your Wasp version from the [Wasp releases](https://github.com/iotaledger/wasp/releases). +You can use a commands like the following to for example download version 1.1.0: + +```sh +curl -sL https://github.com/iotaledger/wasp/releases/download/v1.1.0/wasp-cli_1.1.0_Linux_x86_64.tar.gz | tar xzv +``` + +Change directory into the newly-downloaded `wasp-cli` directory: + +```sh +cd wasp-cli_1.1.0_Linux_x86_64/ +``` + +### Set the L1 API Address + +Set the L1 API address. You can set it to what you configured as `NODE_HOST` in the `.env` file + +:::tip HTTP + +If you use the http setup, don't forget to replace `https` with `http` + +::: + +```sh +./wasp-cli set l1.apiaddress https://{NODE_HOST} +``` + +### Set Wasp API Address + +Set the WASP API address. It is your configured `NODE_HOST` and the `/wasp/api` path. + +```sh +./wasp-cli wasp add my-node https://{NODE_HOST}/wasp/api +``` + +### Login + +Login to wasp using your credentials. You can update your current credentials or add new ones in the wasp dashboard. + +```sh +./wasp-cli login +``` +```sh title=Output +Username: wasp +Password: (default is wasp) +Successfully authenticated +``` + +### Obtain Peering Info + +Get your peering info which you will need to share with your peers: + +```sh +./wasp-cli peering info +``` +```sh title=Output +PubKey: 0x20a56daa0b5e86b196c37f802089a2b6007a655a12337d287f7313a214af2ec0 +PeeringURL: 0.0.0.0:4000 +``` + +Please note the PubKey: 0x20a56daa0b5e86b196c37f802089a2b6007a655a12337d287f7313a214af2ec0 output. +Send it together with your domain/IP to node operators that you want to peer with. + +### Wait for the other party to peer + +Wait until peer added you as trusted and access peer. + +### Use wasp-cli to add nodes as peers + +Now you can add your peer as trusted peer. + +```sh +./wasp-cli peering trust peer1 : +./wasp-cli peering trust peer2 : +``` + +### Add Chain + +Add the chain with its chain id and name: + + + + +```sh +./wasp-cli chain add shimmer-evm smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s +``` + + + + +```sh +./wasp-cli chain add shimmer-evm-testnet rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex +``` + + + + +### Activate + +Activate the chain using its name: + + + + + +```sh +./wasp-cli chain activate --chain shimmer-evm +``` + + + + +```sh +./wasp-cli chain activate --chain shimmer-evm-testnet +``` + + + + +### Add Peers as Access Nodes of the Chain + +Add the peers as access nodes. + +:::info + +This is normally only needed for peers that you plan to add as access nodes to your own node + +::: + +```sh +./wasp-cli chain access-nodes add --peers=peer1,peer2 +``` + +### Check if Wasp Synced + +You can follow the progress using `docker logs -f wasp`. If you chose to create a [full-archive node](#run-and-archive-node), this can take several minutes, maybe hours. + +### Test Your Endpoint + +You should have a working EVM JSON-RPC endpoint on: + + + + +``` +/wasp/api/v1/chains/smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s +/evm +``` + + + + +``` +/wasp/api/v1/chains/rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex +/evm +``` + + + diff --git a/docs/maintain/wasp/v1.3-alpha/docs/how-tos/setting-up-a-chain.md b/docs/maintain/wasp/v1.3-alpha/docs/how-tos/setting-up-a-chain.md new file mode 100644 index 00000000000..d71c78d5372 --- /dev/null +++ b/docs/maintain/wasp/v1.3-alpha/docs/how-tos/setting-up-a-chain.md @@ -0,0 +1,176 @@ +--- +description: 'Setting up a chain: requirements, configuration parameters, validators, and tests.' +image: /img/logo/WASP_logo_dark.png +tags: + - Smart Contracts + - Chain + - Set up + - Configuration + - Nodes + - Tests +--- + +# Set Up a Chain + +:::note + +It is possible to run a "committee" of a single Wasp node, which is okay for testing purposes. + +However, in normal operation, multiple Wasp _nodes_ should be used. + +::: + +## Requirements + +- [`wasp-cli` configured](wasp-cli.md) to interact with your wasp node. + +## Trust Setup + +After starting all the `wasp` nodes, you should make them trust each other. Node operators should do this manually. It's +their responsibility to accept trusted nodes only. + +The operator can read their node's public key and PeeringURL by running `wasp-cli peering info`: + +```shell +wasp-cli peering info +``` + +Example response: + +```log +PubKey: 8oQ9xHWvfnShRxB22avvjbMyAumZ7EXKujuthqrzapNM +PeeringURL: 127.0.0.1:4000 +``` + +You should provide your `PubKey` and `PeeringURL` to other node operators. +They can use this info to trust and accept communications with your node. +That's done by invoking `wasp-cli peering trust `, e.g.: + +```shell +wasp-cli peering trust another-node 8oQ9xHWvfnShRxB22avvjbMyAumZ7EXKujuthqrzapNM 127.0.0.1:4000 +``` + +You can view the list of your wasp node's trusted peers by calling: + +```shell +wasp-cli peering list-trusted +``` + +All the nodes in a committee must trust each other to run the chain. + +## Start the Chain + +### Request Test Funds (only for Testnet) + +You can request test funds to safely develop your application by calling: + +```shell +wasp-cli request-funds +``` + +### Deploy the IOTA Smart Contracts Chain + +You can deploy your IOTA Smart Contracts chain by running: + +```shell +wasp-cli chain deploy --peers=foo,bar,baz --chain=mychain --block-keep-amount=10000 +``` + +The names in `--peers=foo,bar,baz` correspond to the names of the node's trusted peers. + +The `--chain=mychain` flag sets up an alias for the chain. +From now on, all chain commands will target this chain. + +The `--quorum` flag indicates the minimum number of nodes required to form a _consensus_. +The recommended formula to obtain this number is `floor(N*2/3)+1` where `N` is the number of nodes in your committee. + +The `--block-keep-amount` parameter determines how many blocks are stored in the [`blocklog`](/isc/reference/core-contracts/blocklog) core contract. + +After deployment, the chain must be activated by the node operators of all peers. + +```shell +wasp-cli chain add # adds the chain to the wasp-cli config, can be skipped on the wasp-cli that initiated the deployment +wasp-cli chain activate --chain= +``` + +## Test If It Works + +You can check that the chain was deployed correctly in the Wasp node dashboard (`/wasp/dashboard` when using `node-docker-setup`). +Note that the chain was deployed with some [core contracts](/isc/reference/core-contracts/overview). + +You should also have an EVM-JSONRPC server opened on: + +```info +/chain//evm +``` + +### Deploying a Wasm Contract + +:::warning +The WASM _VM_ is experimental. However, similar commands can be used to interact with the core contracts +::: + +Now you can deploy a Wasm contract to the chain: + +```shell +wasp-cli chain deploy-contract wasmtime inccounter "inccounter SC" tools/cluster/tests/wasm/inccounter_bg.wasm +``` + +The `inccounter_bg.wasm` file is a precompiled Wasm contract included in the Wasp repo as an example. + +If you recheck the dashboard, you should see that the `inccounter` contract is listed in the chain. + +### Interacting With a Smart Contract + +You can interact with a contract by calling its exposed functions and views. + +For instance, the [`inccounter`](https://github.com/iotaledger/wasp/tree/master/contracts/wasm/inccounter/src) contract +exposes the `increment` function, which simply increments a counter stored in the state. It also has the `getCounter` +view that returns the current value of the counter. + +You can call the `getCounter` view by running: + +```shell +wasp-cli chain call-view inccounter getCounter | wasp-cli decode string counter int +``` + +Example response: + +```log +counter: 0 +``` + +:::note + +The part after `|` is necessary because the return value is encoded, and you need to know the _schema_ to +decode it. **The schema definition is in its early stages and will likely change in the future.** + +::: + +You can now call the `increment` function by running: + +```shell +wasp-cli chain post-request inccounter increment +``` + +After the committee has processed the request, you should get a new +counter value after calling `getCounter`: + +```shell +wasp-cli chain call-view inccounter getCounter | wasp-cli decode string counter int +``` + +Example response: + +```log +counter: 1 +``` + +### Troubleshooting + +Common issues can be caused by using an incompatible version of `wasp` / `wasp-cli`. +You can verify that `wasp-cli` and `wasp` nodes are on the same version by running: + +```shell +wasp-cli check-versions +``` diff --git a/docs/maintain/wasp/v1.3-alpha/docs/how-tos/wasp-cli.md b/docs/maintain/wasp/v1.3-alpha/docs/how-tos/wasp-cli.md new file mode 100644 index 00000000000..a09445e0aaf --- /dev/null +++ b/docs/maintain/wasp/v1.3-alpha/docs/how-tos/wasp-cli.md @@ -0,0 +1,67 @@ +--- +description: How to configure wasp-cli. Requirements and configuration parameters. +image: /img/logo/WASP_logo_dark.png +tags: + - Wasp-cli + - Configuration + - Hornet + - command line +--- + +# Configure wasp-cli + +You can use these step-by-step instructions on how to use wasp-cli to interact with Wasp nodes on the Hornet network. + +## Download wasp-cli + +Download the latest wasp-cli binary from the repo [releases page](https://github.com/iotaledger/wasp/releases). +(For ease of use, it is recommended to add `wasp-cli` to your system `PATH`). + +## Configuration + +You can create a basic default configuration by running: + +```shell +wasp-cli init +``` + +This command will create a configuration file named `wasp-cli.json` in `~/.wasp-cli/wasp-cli.json` (you can change the default with the `-c, --config` flag). + +:::info Wallet Provider + +By default wasp-cli will store the seed in your OS keychain. You can change this behavior by running + +```shell +wasp-cli wallet-provider (keychain, sdk_ledger, sdk_stronghold) [flags] +``` + +::: + +:::info Deprecated Seed storage + +If you use a version older then [1.0.3](https://github.com/iotaledger/wasp/releases/tag/v1.0.3-alpha.1) your seed is still stored as plain text. You can migrate to the keychain by using the following command: + +```shell +wasp-cli wallet-migrate (keychain) [flags] +``` + +::: + +After this, you will need to tell the `wasp-cli` the location of the _Hornet node_ and the committee of Wasp nodes: + +```shell +wasp-cli set l1.apiaddress http://localhost:14265 +# the faucet only exists for test networks +wasp-cli set l1.faucetaddress http://localhost:8091 + +# You can add as many nodes as you'd like +wasp-cli wasp add wasp-0 127.0.0.1:9090 +wasp-cli wasp add wasp-1 127.0.0.1:9091 +``` + +If you configure the Wasp node to use JWT authentication, you will need to log in +after you save the configuration. + +```shell +wasp-cli login +``` diff --git a/docs/maintain/wasp/v1.3-alpha/docs/reference/configuration.md b/docs/maintain/wasp/v1.3-alpha/docs/reference/configuration.md new file mode 100755 index 00000000000..bfe1181b5b5 --- /dev/null +++ b/docs/maintain/wasp/v1.3-alpha/docs/reference/configuration.md @@ -0,0 +1,573 @@ +--- +# !!! DO NOT MODIFY !!! +# This file is auto-generated by the gendoc tool based on the source code of the app. +description: This section describes the configuration parameters and their types for WASP. +tags: + - IOTA Node + - Hornet Node + - WASP Node + - Smart Contracts + - L2 + - Configuration + - JSON + - Customize + - Config + - reference +--- + + +# Core Configuration + +WASP uses a JSON standard format as a config file. If you are unsure about JSON syntax, you can find more information in the [official JSON specs](https://www.json.org). + +You can change the path of the config file by using the `-c` or `--config` argument while executing `wasp` executable. + +For example: +```shell +wasp -c config_defaults.json +``` + +You can always get the most up-to-date description of the config parameters by running: + +```shell +wasp -h --full +``` + +## 1. Application + +| Name | Description | Type | Default value | +| ------------------------- | ------------------------------------------------------ | ------- | ------------- | +| checkForUpdates | Whether to check for updates of the application or not | boolean | true | +| [shutdown](#app_shutdown) | Configuration for shutdown | object | | + +### Shutdown + +| Name | Description | Type | Default value | +| ------------------------ | ------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| stopGracePeriod | The maximum time to wait for background processes to finish during shutdown before terminating the app | string | "5m" | +| [log](#app_shutdown_log) | Configuration for Shutdown Log | object | | + +### Shutdown Log + +| Name | Description | Type | Default value | +| -------- | --------------------------------------------------- | ------- | -------------- | +| enabled | Whether to store self-shutdown events to a log file | boolean | true | +| filePath | The file path to the self-shutdown log | string | "shutdown.log" | + +Example: + +```json + { + "app": { + "checkForUpdates": true, + "shutdown": { + "stopGracePeriod": "5m", + "log": { + "enabled": true, + "filePath": "shutdown.log" + } + } + } + } +``` + +## 2. Logger + +| Name | Description | Type | Default value | +| ---------------------------------------- | --------------------------------------------------------------------------- | ------- | ------------- | +| level | The minimum enabled logging level | string | "info" | +| disableCaller | Stops annotating logs with the calling function's file name and line number | boolean | true | +| disableStacktrace | Disables automatic stacktrace capturing | boolean | false | +| stacktraceLevel | The level stacktraces are captured and above | string | "panic" | +| encoding | The logger's encoding (options: "json", "console") | string | "console" | +| [encodingConfig](#logger_encodingconfig) | Configuration for encodingConfig | object | | +| outputPaths | A list of URLs, file paths or stdout/stderr to write logging output to | array | stdout | +| disableEvents | Prevents log messages from being raced as events | boolean | true | + +### EncodingConfig + +| Name | Description | Type | Default value | +| ----------- | ---------------------------------------------------------------------------------------------------------- | ------ | ------------- | +| timeEncoder | Sets the logger's timestamp encoding. (options: "nanos", "millis", "iso8601", "rfc3339" and "rfc3339nano") | string | "rfc3339" | + +Example: + +```json + { + "logger": { + "level": "info", + "disableCaller": true, + "disableStacktrace": false, + "stacktraceLevel": "panic", + "encoding": "console", + "encodingConfig": { + "timeEncoder": "rfc3339" + }, + "outputPaths": [ + "stdout" + ], + "disableEvents": true + } + } +``` + +## 3. INX + +| Name | Description | Type | Default value | +| --------------------- | -------------------------------------------------------------------------------------------------- | ------ | ---------------- | +| address | The INX address to which to connect to | string | "localhost:9029" | +| maxConnectionAttempts | The amount of times the connection to INX will be attempted before it fails (1 attempt per second) | uint | 30 | +| targetNetworkName | The network name on which the node should operate on (optional) | string | "" | + +Example: + +```json + { + "inx": { + "address": "localhost:9029", + "maxConnectionAttempts": 30, + "targetNetworkName": "" + } + } +``` + +## 4. Cache + +| Name | Description | Type | Default value | +| ------------------ | -------------------------------------- | ------- | ------------- | +| cacheSize | Cache size | string | "64MiB" | +| cacheStatsInterval | Interval for printing cache statistics | string | "30s" | +| enabled | Whether the cache plugin is enabled | boolean | true | + +Example: + +```json + { + "cache": { + "cacheSize": "64MiB", + "cacheStatsInterval": "30s", + "enabled": true + } + } +``` + +## 5. Database + +| Name | Description | Type | Default value | +| ---------------------------- | ---------------------------------------- | ------- | ------------- | +| engine | The used database engine (rocksdb/mapdb) | string | "rocksdb" | +| [chainState](#db_chainstate) | Configuration for chainState | object | | +| debugSkipHealthCheck | Ignore the check for corrupted databases | boolean | true | + +### ChainState + +| Name | Description | Type | Default value | +| --------- | -------------------------------------------- | ------ | -------------------- | +| path | The path to the chain state databases folder | string | "waspdb/chains/data" | +| cacheSize | Size of the RocksDB block cache | uint | 33554432 | + +Example: + +```json + { + "db": { + "engine": "rocksdb", + "chainState": { + "path": "waspdb/chains/data", + "cacheSize": 33554432 + }, + "debugSkipHealthCheck": true + } + } +``` + +## 6. P2p + +| Name | Description | Type | Default value | +| ------------------------- | -------------------------- | ------ | ------------- | +| [identity](#p2p_identity) | Configuration for identity | object | | +| [db](#p2p_db) | Configuration for Database | object | | + +### Identity + +| Name | Description | Type | Default value | +| ---------- | ------------------------------------------------------- | ------ | ------------------------------ | +| privateKey | Private key used to derive the node identity (optional) | string | "" | +| filePath | The path to the node identity PEM file | string | "waspdb/identity/identity.key" | + +### Database + +| Name | Description | Type | Default value | +| ---- | ---------------------------- | ------ | ----------------- | +| path | The path to the p2p database | string | "waspdb/p2pstore" | + +Example: + +```json + { + "p2p": { + "identity": { + "privateKey": "", + "filePath": "waspdb/identity/identity.key" + }, + "db": { + "path": "waspdb/p2pstore" + } + } + } +``` + +## 7. Registries + +| Name | Description | Type | Default value | +| -------------------------------------------- | -------------------------------- | ------ | ------------- | +| [chains](#registries_chains) | Configuration for chains | object | | +| [dkShares](#registries_dkshares) | Configuration for dkShares | object | | +| [trustedPeers](#registries_trustedpeers) | Configuration for trustedPeers | object | | +| [consensusState](#registries_consensusstate) | Configuration for consensusState | object | | + +### Chains + +| Name | Description | Type | Default value | +| -------- | ----------------------------------- | ------ | ----------------------------------- | +| filePath | The path to the chain registry file | string | "waspdb/chains/chain_registry.json" | + +### DkShares + +| Name | Description | Type | Default value | +| ---- | -------------------------------------------------------- | ------ | ----------------- | +| path | The path to the distributed key shares registries folder | string | "waspdb/dkshares" | + +### TrustedPeers + +| Name | Description | Type | Default value | +| -------- | ------------------------------------------- | ------ | --------------------------- | +| filePath | The path to the trusted peers registry file | string | "waspdb/trusted_peers.json" | + +### ConsensusState + +| Name | Description | Type | Default value | +| ---- | ------------------------------------------------- | ------ | ------------------------- | +| path | The path to the consensus state registries folder | string | "waspdb/chains/consensus" | + +Example: + +```json + { + "registries": { + "chains": { + "filePath": "waspdb/chains/chain_registry.json" + }, + "dkShares": { + "path": "waspdb/dkshares" + }, + "trustedPeers": { + "filePath": "waspdb/trusted_peers.json" + }, + "consensusState": { + "path": "waspdb/chains/consensus" + } + } + } +``` + +## 8. Peering + +| Name | Description | Type | Default value | +| ---------- | ---------------------------------------------------- | ------ | -------------- | +| peeringURL | Node host address as it is recognized by other peers | string | "0.0.0.0:4000" | +| port | Port for Wasp committee connection/peering | int | 4000 | + +Example: + +```json + { + "peering": { + "peeringURL": "0.0.0.0:4000", + "port": 4000 + } + } +``` + +## 9. Chains + +| Name | Description | Type | Default value | +| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------- | +| broadcastUpToNPeers | Number of peers an offledger request is broadcasted to | int | 2 | +| broadcastInterval | Time between re-broadcast of offledger requests; 0 value means that re-broadcasting is disabled | string | "0s" | +| apiCacheTTL | Time to keep processed offledger requests in api cache | string | "5m" | +| pullMissingRequestsFromCommittee | Whether or not to pull missing requests from other committee members | boolean | true | +| deriveAliasOutputByQuorum | False means we propose own AliasOutput, true - by majority vote. | boolean | true | +| pipeliningLimit | -1 -- infinite, 0 -- disabled, X -- build the chain if there is up to X transactions unconfirmed by L1. | int | -1 | +| postponeRecoveryMilestones | Number of milestones to wait until a chain transition is considered as rejected | int | 3 | +| consensusDelay | Minimal delay between consensus runs. | string | "500ms" | +| recoveryTimeout | Time after which another consensus attempt is made. | string | "20s" | +| redeliveryPeriod | The resend period for msg. | string | "2s" | +| printStatusPeriod | The period to print consensus instance status. | string | "3s" | +| consensusInstsInAdvance | | int | 3 | +| awaitReceiptCleanupEvery | For every this number AwaitReceipt will be cleaned up | int | 100 | +| mempoolTTL | Time that requests are allowed to sit in the mempool without being processed | string | "24h" | +| mempoolMaxOffledgerInPool | Maximum number of off-ledger requests kept in the mempool | int | 2000 | +| mempoolMaxOnledgerInPool | Maximum number of on-ledger requests kept in the mempool | int | 1000 | +| mempoolMaxTimedInPool | Maximum number of timed on-ledger requests kept in the mempool | int | 100 | +| mempoolMaxOffledgerToPropose | Maximum number of off-ledger requests to propose for the next block | int | 500 | +| mempoolMaxOnledgerToPropose | Maximum number of on-ledger requests to propose for the next block (includes timed requests) | int | 100 | +| mempoolOnLedgerRefreshMinInterval | Minimum interval to try to refresh the list of on-ledger requests after some have been dropped from the pool (this interval is introduced to avoid dropping/refreshing cycle if there are too many requests on L1 to process) | string | "10m" | + +Example: + +```json + { + "chains": { + "broadcastUpToNPeers": 2, + "broadcastInterval": "0s", + "apiCacheTTL": "5m", + "pullMissingRequestsFromCommittee": true, + "deriveAliasOutputByQuorum": true, + "pipeliningLimit": -1, + "postponeRecoveryMilestones": 3, + "consensusDelay": "500ms", + "recoveryTimeout": "20s", + "redeliveryPeriod": "2s", + "printStatusPeriod": "3s", + "consensusInstsInAdvance": 3, + "awaitReceiptCleanupEvery": 100, + "mempoolTTL": "24h", + "mempoolMaxOffledgerInPool": 2000, + "mempoolMaxOnledgerInPool": 1000, + "mempoolMaxTimedInPool": 100, + "mempoolMaxOffledgerToPropose": 500, + "mempoolMaxOnledgerToPropose": 100, + "mempoolOnLedgerRefreshMinInterval": "10m" + } + } +``` + +## 10. Snapshots + +| Name | Description | Type | Default value | +| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------------- | +| snapshotsToLoad | List of snapshots to load; can be either single block hash of a snapshot (if a single chain has to be configured) or list of `:` to configure many chains | array | | +| period | How often state snapshots should be made: 1000 meaning "every 1000th state", 0 meaning "making snapshots is disabled" | uint | 0 | +| delay | How many states should pass before snapshot is produced | uint | 20 | +| localPath | The path to the snapshots folder in this node's disk | string | "waspdb/snap" | +| networkPaths | The list of paths to the remote (http(s)) snapshot locations; each of listed locations must contain 'INDEX' file with list of snapshot files | array | | + +Example: + +```json + { + "snapshots": { + "snapshotsToLoad": [], + "period": 0, + "delay": 20, + "localPath": "waspdb/snap", + "networkPaths": [] + } + } +``` + +## 11. StateManager + +| Name | Description | Type | Default value | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| blockCacheMaxSize | How many blocks may be stored in cache before old ones start being deleted | int | 1000 | +| blockCacheBlocksInCacheDuration | How long should the block stay in block cache before being deleted | string | "1h" | +| blockCacheBlockCleaningPeriod | How often should the block cache be cleaned | string | "1m" | +| stateManagerGetBlockNodeCount | How many nodes should get block request be sent to | int | 5 | +| stateManagerGetBlockRetry | How often get block requests should be repeated | string | "3s" | +| stateManagerRequestCleaningPeriod | How often requests waiting for response should be checked for expired context | string | "5m" | +| stateManagerStatusLogPeriod | How often state manager status information should be written to log | string | "1m" | +| stateManagerTimerTickPeriod | How often timer tick fires in state manager | string | "1s" | +| pruningMinStatesToKeep | This number of states will always be available in the store; if 0 - store pruning is disabled | int | 10000 | +| pruningMaxStatesToDelete | On single store pruning attempt at most this number of states will be deleted; NOTE: pruning takes considerable amount of time; setting this parameter large may seriously damage Wasp responsiveness if many blocks require pruning | int | 10 | + +Example: + +```json + { + "stateManager": { + "blockCacheMaxSize": 1000, + "blockCacheBlocksInCacheDuration": "1h", + "blockCacheBlockCleaningPeriod": "1m", + "stateManagerGetBlockNodeCount": 5, + "stateManagerGetBlockRetry": "3s", + "stateManagerRequestCleaningPeriod": "5m", + "stateManagerStatusLogPeriod": "1m", + "stateManagerTimerTickPeriod": "1s", + "pruningMinStatesToKeep": 10000, + "pruningMaxStatesToDelete": 10 + } + } +``` + +## 12. Validator + +| Name | Description | Type | Default value | +| ------- | ------------------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| address | Bech32 encoded address to identify the node (as access node on gov contract and to collect validator fee payments) | string | "" | + +Example: + +```json + { + "validator": { + "address": "" + } + } +``` + +## 13. Write-Ahead Logging + +| Name | Description | Type | Default value | +| ----------- | ---------------------------------------------------------------- | ------- | ------------- | +| loadToStore | Load blocks from "write-ahead log" to the store on node start-up | boolean | false | +| enabled | Whether the "write-ahead logging" is enabled | boolean | true | +| path | The path to the "write-ahead logging" folder | string | "waspdb/wal" | + +Example: + +```json + { + "wal": { + "loadToStore": false, + "enabled": true, + "path": "waspdb/wal" + } + } +``` + +## 14. Web API + +| Name | Description | Type | Default value | +| ------------------------- | ------------------------------------------------------------------------------------------ | ------- | --------------------- | +| enabled | Whether the web api plugin is enabled | boolean | true | +| bindAddress | The bind address for the node web api | string | "0.0.0.0:9090" | +| [auth](#webapi_auth) | Configuration for auth | object | | +| indexDbPath | Directory for storing indexes of historical data (only archive nodes will create/use them) | string | "waspdb/chains/index" | +| [limits](#webapi_limits) | Configuration for limits | object | | +| debugRequestLoggerEnabled | Whether the debug logging for requests should be enabled | boolean | false | + +### Auth + +| Name | Description | Type | Default value | +| ----------------------- | -------------------------------------- | ------ | ------------- | +| scheme | Selects which authentication to choose | string | "jwt" | +| [jwt](#webapi_auth_jwt) | Configuration for JWT Auth | object | | + +### JWT Auth + +| Name | Description | Type | Default value | +| -------- | ------------------ | ------ | ------------- | +| duration | Jwt token lifetime | string | "24h" | + +### Limits + +| Name | Description | Type | Default value | +| --------------------------------- | ----------------------------------------------------------------------------- | ------ | ------------- | +| timeout | The timeout after which a long running operation will be canceled | string | "30s" | +| readTimeout | The read timeout for the HTTP request body | string | "10s" | +| writeTimeout | The write timeout for the HTTP response body | string | "1m" | +| maxBodyLength | The maximum number of characters that the body of an API call may contain | string | "2M" | +| maxTopicSubscriptionsPerClient | Defines the max amount of subscriptions per client. 0 = deactivated (default) | int | 0 | +| confirmedStateLagThreshold | The threshold that define a chain is unsynchronized | uint | 2 | +| [jsonrpc](#webapi_limits_jsonrpc) | Configuration for jsonrpc | object | | + +### Jsonrpc + +| Name | Description | Type | Default value | +| ----------------------------------- | -------------------------------------------------------------- | ------ | ------------- | +| maxBlocksInLogsFilterRange | Maximum amount of blocks in eth_getLogs filter range | int | 1000 | +| maxLogsInResult | Maximum amount of logs in eth_getLogs result | int | 10000 | +| websocketRateLimitMessagesPerSecond | The websocket rate limit (messages per second) | int | 20 | +| websocketRateLimitBurst | The websocket burst limit | int | 5 | +| websocketConnectionCleanupDuration | Defines in which interval stale connections will be cleaned up | string | "5m" | +| websocketClientBlockDuration | The duration a misbehaving client will be blocked | string | "5m" | + +Example: + +```json + { + "webapi": { + "enabled": true, + "bindAddress": "0.0.0.0:9090", + "auth": { + "scheme": "jwt", + "jwt": { + "duration": "24h" + } + }, + "indexDbPath": "waspdb/chains/index", + "limits": { + "timeout": "30s", + "readTimeout": "10s", + "writeTimeout": "1m", + "maxBodyLength": "2M", + "maxTopicSubscriptionsPerClient": 0, + "confirmedStateLagThreshold": 2, + "jsonrpc": { + "maxBlocksInLogsFilterRange": 1000, + "maxLogsInResult": 10000, + "websocketRateLimitMessagesPerSecond": 20, + "websocketRateLimitBurst": 5, + "websocketConnectionCleanupDuration": "5m", + "websocketClientBlockDuration": "5m" + } + }, + "debugRequestLoggerEnabled": false + } + } +``` + +## 15. Profiling + +| Name | Description | Type | Default value | +| ----------- | ------------------------------------------------- | ------- | ---------------- | +| enabled | Whether the profiling component is enabled | boolean | false | +| bindAddress | The bind address on which the profiler listens on | string | "localhost:6060" | + +Example: + +```json + { + "profiling": { + "enabled": false, + "bindAddress": "localhost:6060" + } + } +``` + +## 16. ProfilingRecorder + +| Name | Description | Type | Default value | +| ------- | ----------------------------------------------- | ------- | ------------- | +| enabled | Whether the ProfilingRecorder plugin is enabled | boolean | false | + +Example: + +```json + { + "profilingRecorder": { + "enabled": false + } + } +``` + +## 17. Prometheus + +| Name | Description | Type | Default value | +| ----------- | ------------------------------------------------------------ | ------- | -------------- | +| enabled | Whether the prometheus plugin is enabled | boolean | true | +| bindAddress | The bind address on which the Prometheus exporter listens on | string | "0.0.0.0:2112" | + +Example: + +```json + { + "prometheus": { + "enabled": true, + "bindAddress": "0.0.0.0:2112" + } + } +``` + diff --git a/docs/maintain/wasp/v1.3-alpha/docs/reference/metrics.md b/docs/maintain/wasp/v1.3-alpha/docs/reference/metrics.md new file mode 100644 index 00000000000..385ec322f55 --- /dev/null +++ b/docs/maintain/wasp/v1.3-alpha/docs/reference/metrics.md @@ -0,0 +1,22 @@ +--- +description: IOTA Smart Contract Protocol is IOTA's solution for running smart contracts on top of the IOTA _tangle_. +image: /img/logo/WASP_logo_dark.png +tags: + - smart contracts + - metrics + - reference +--- + +# Exposed Metrics + +Refer to the [testnet endpoints description](/build/networks-endpoints/#testnet-evm) for access details. + +| Metric | Description | +| ------------------------------------------ | ---------------------------------------------------- | +| `wasp_off_ledger_requests_counter` | Off-ledger requests per chain. | +| `wasp_on_ledger_request_counter` | On-ledger requests per chain. | +| `wasp_processed_request_counter` | Total number of requests processed. | +| `messages_received_per_chain` | Number of messages received per chain. | +| `receive_requests_acknowledgement_message` | Number of request acknowledgment messages per chain. | +| `request_processing_time` | Time to process request. | +| `vm_run_time` | Time it takes to run the VM. | diff --git a/docs/maintain/wasp/v1.3-alpha/sidebars.js b/docs/maintain/wasp/v1.3-alpha/sidebars.js new file mode 100644 index 00000000000..9aec98e9373 --- /dev/null +++ b/docs/maintain/wasp/v1.3-alpha/sidebars.js @@ -0,0 +1,65 @@ +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ + +module.exports = { + // By default, Docusaurus generates a sidebar from the docs folder structure + //tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + waspSidebar: [ + { + type: 'category', + label: 'How To', + collapsed: false, + items: [ + { + type: 'doc', + id: 'how-tos/running-a-node', + label: 'Run a Node', + }, + { + type: 'doc', + id: 'how-tos/running-an-access-node', + label: 'Run an Access Node', + }, + { + id: 'how-tos/wasp-cli', + label: 'Configure wasp-cli', + type: 'doc', + }, + { + id: 'how-tos/setting-up-a-chain', + label: 'Set Up a Chain', + type: 'doc', + }, + { + id: 'how-tos/chain-management', + label: 'Manage a Chain', + type: 'doc', + }, + ], + }, + { + type: 'category', + label: 'Reference', + items: [ + { + type: 'doc', + id: 'reference/configuration', + }, + { + type: 'doc', + id: 'reference/metrics', + }, + ], + }, + ], +}; diff --git a/tutorials/pages/create-nft-with-iota-sdk.md b/docs/tutorials/create-nft-with-iota-sdk.md similarity index 99% rename from tutorials/pages/create-nft-with-iota-sdk.md rename to docs/tutorials/create-nft-with-iota-sdk.md index 4f6fd843b15..f168b0a9bb1 100644 --- a/tutorials/pages/create-nft-with-iota-sdk.md +++ b/docs/tutorials/create-nft-with-iota-sdk.md @@ -58,7 +58,7 @@ Add your desired `*.jpg` file to the `wallet-setup` folder you created and renam For this tutorial we'll use the following image: -![NFT Image](/nft-image.jpg) +![NFT Image](/img/tutorials/nft-image.jpg) --- diff --git a/tutorials/pages/hornet-inx-interaction.md b/docs/tutorials/hornet-inx-interaction.md similarity index 100% rename from tutorials/pages/hornet-inx-interaction.md rename to docs/tutorials/hornet-inx-interaction.md diff --git a/tutorials/pages/proof-inclusion-of-a-block.md b/docs/tutorials/proof-inclusion-of-a-block.md similarity index 99% rename from tutorials/pages/proof-inclusion-of-a-block.md rename to docs/tutorials/proof-inclusion-of-a-block.md index 6081099142f..4721c1e0f08 100644 --- a/tutorials/pages/proof-inclusion-of-a-block.md +++ b/docs/tutorials/proof-inclusion-of-a-block.md @@ -16,7 +16,7 @@ Since the pattern assumes trusted access to the network, we recommend that both Please note that this pattern does not rely on a Permanode storing the entire Tangle history, as it was the case in almost all data-related use cases in the past. In comparison to a Permanode, storing selected blocks with their proof of inclusion to the Tangle, drastically reduces the node operator's storage requirements. -![PoI-Architecture](/proof-inclusion-of-a-block-architecture.png) +![PoI-Architecture](/img/tutorials/proof-inclusion-of-a-block-architecture.png) --- diff --git a/tutorials/pages/send-shimmer-tokens-with-iota-sdk.md b/docs/tutorials/send-shimmer-tokens-with-iota-sdk.md similarity index 100% rename from tutorials/pages/send-shimmer-tokens-with-iota-sdk.md rename to docs/tutorials/send-shimmer-tokens-with-iota-sdk.md diff --git a/tutorials/pages/setup_iota-js_for_development.md b/docs/tutorials/setup_iota-js_for_development.md similarity index 98% rename from tutorials/pages/setup_iota-js_for_development.md rename to docs/tutorials/setup_iota-js_for_development.md index 7dcb438432b..609fde90eec 100644 --- a/tutorials/pages/setup_iota-js_for_development.md +++ b/docs/tutorials/setup_iota-js_for_development.md @@ -180,7 +180,7 @@ Now, you can go to the [Shimmer Testnet Faucet Website](https://faucet.testnet.s The 'Request' button will become clickable as soon as a valid Shimmer address is recognized. ::: -![Shimmer Testnet Faucet](/shimmer-testnet-faucet.png) +![Shimmer Testnet Faucet](/img/tutorials/shimmer-testnet-faucet.png) --- diff --git a/tutorials/pages/shimmerevm-dapp-voting.md b/docs/tutorials/shimmerevm-dapp-voting.md similarity index 99% rename from tutorials/pages/shimmerevm-dapp-voting.md rename to docs/tutorials/shimmerevm-dapp-voting.md index 88a3e027241..13c05346b53 100644 --- a/tutorials/pages/shimmerevm-dapp-voting.md +++ b/docs/tutorials/shimmerevm-dapp-voting.md @@ -337,4 +337,4 @@ let tx = contractSigner.vote(i); ## Result If you followed everything above, it should look something like this: -![Voting Demo](/voting-dapp.jpg 'Voting dApp UI') +![Voting Demo](/img/tutorials/voting-dapp.jpg 'Voting dApp UI') diff --git a/tutorials/pages/shimmerevm-hardhat.md b/docs/tutorials/shimmerevm-hardhat.md similarity index 98% rename from tutorials/pages/shimmerevm-hardhat.md rename to docs/tutorials/shimmerevm-hardhat.md index baa75398e07..e1d85e011e9 100644 --- a/tutorials/pages/shimmerevm-hardhat.md +++ b/docs/tutorials/shimmerevm-hardhat.md @@ -48,7 +48,7 @@ The sample project used here comes from the [Hardhat Quickstart guide](https://h You should see the following prompt: -![Hardhat Setup](/shimmer-hardhat-setup.png 'Hardhat Setup') +![Hardhat Setup](/img/tutorials/shimmer-hardhat-setup.png 'Hardhat Setup') Choose the JavaScript project and go through these steps to compile, test and deploy the sample contract. diff --git a/tutorials/pages/shimmerevm-setup.mdx b/docs/tutorials/shimmerevm-setup.mdx similarity index 95% rename from tutorials/pages/shimmerevm-setup.mdx rename to docs/tutorials/shimmerevm-setup.mdx index 7cd3444d03c..eada2d97a90 100644 --- a/tutorials/pages/shimmerevm-setup.mdx +++ b/docs/tutorials/shimmerevm-setup.mdx @@ -30,7 +30,7 @@ To add the ShimmerEVM network manually to your Metamask use following info: - Currency Symbol: `SMR` - Explorer URL: https://explorer.evm.shimmer.network -![Metamask Adding New Network](/metamask-shimmerevm-mainnet.png 'Metamask Adding New Network') +![Metamask Adding New Network](/img/tutorials/metamask-shimmerevm-mainnet.png 'Metamask Adding New Network') Hit `Save` and wait for Metamask to connect to the network. diff --git a/tutorials/pages/shimmerevm-testnet-hardhat.md b/docs/tutorials/shimmerevm-testnet-hardhat.md similarity index 98% rename from tutorials/pages/shimmerevm-testnet-hardhat.md rename to docs/tutorials/shimmerevm-testnet-hardhat.md index c7f0ecf47ca..b39d38a66f0 100644 --- a/tutorials/pages/shimmerevm-testnet-hardhat.md +++ b/docs/tutorials/shimmerevm-testnet-hardhat.md @@ -48,7 +48,7 @@ The sample project used here comes from the [Hardhat Quickstart guide](https://h You should see the following prompt: -![Hardhat Setup](/shimmer-hardhat-setup.png 'Hardhat Setup') +![Hardhat Setup](/img/tutorials/shimmer-hardhat-setup.png 'Hardhat Setup') Choose the JavaScript project and go through these steps to compile, test and deploy the sample contract. diff --git a/tutorials/pages/shimmerevm-testnet-setup.mdx b/docs/tutorials/shimmerevm-testnet-setup.mdx similarity index 92% rename from tutorials/pages/shimmerevm-testnet-setup.mdx rename to docs/tutorials/shimmerevm-testnet-setup.mdx index 0698310411e..5124e19576d 100644 --- a/tutorials/pages/shimmerevm-testnet-setup.mdx +++ b/docs/tutorials/shimmerevm-testnet-setup.mdx @@ -27,7 +27,7 @@ To add the ShimmerEVM Testnet network manually to your Metamask use following in - Currency Symbol: `SMR` - Explorer URL: https://explorer.evm.testnet.shimmer.network -![Metamask Adding New Network](/metamask-shimmerevm.png 'Metamask Adding New Network') +![Metamask Adding New Network](/img/tutorials/metamask-shimmerevm.png 'Metamask Adding New Network') Alternatively, you can setup your own EVM Smart Contract Chain on top of the Shimmer network and provide a custom URL, which might look something like: `https://api.sc.testnet.shimmer.network/chain/rms1prr4r7az8e46qhagz5atugjm6x0xrg27d84677e3lurg0s6s76jr59dw4ls/evm/jsonrpc` as well as your own custom Chain ID. @@ -38,10 +38,10 @@ At this point, our Metamask wallet is connected to the Shimmer EVM Testnet, but ## Get EVM Account Funded Open [EVM Toolkit](https://evm-toolkit.evm.testnet.shimmer.network/) and enter your EVM address as shown below: -![EVM Toolkit](/evm-toolkit.png 'EVM Toolkit') +![EVM Toolkit](/img/tutorials/evm-toolkit.png 'EVM Toolkit') In case, you've setup a custom EVM chain, you'd need to add your custom network first. Please add your own chain address and select the relevant network as shown below: -![EVM Toolkit Custom Network](/evm-toolkit-custom-network.png 'EVM Toolkit Custom Network') +![EVM Toolkit Custom Network](/img/tutorials/evm-toolkit-custom-network.png 'EVM Toolkit Custom Network') Once you're done, click on `Send funds` and wait for a few minutes for the faucet to process. You should start seeing some funds on your Metamask wallet soon. diff --git a/tutorials/pages/wallet-setup.md b/docs/tutorials/wallet-setup.md similarity index 99% rename from tutorials/pages/wallet-setup.md rename to docs/tutorials/wallet-setup.md index 95782c52ba7..47fd0d9c871 100644 --- a/tutorials/pages/wallet-setup.md +++ b/docs/tutorials/wallet-setup.md @@ -395,7 +395,7 @@ The 'Request' button will become clickable as soon as a valid Shimmer address is ::: -![Shimmer Testnet Faucet](/shimmer-testnet-faucet.png) +![Shimmer Testnet Faucet](/img/tutorials/shimmer-testnet-faucet.png) --- diff --git a/docusaurus.config.js b/docusaurus.config.js index 4e841c6ce72..e9ac41d4bd7 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -1,13 +1,14 @@ const { glob, merge } = require('./src/utils/config'); const path = require('path'); const { create_doc_plugin } = require('./src/utils/config'); -const contentConfigs = require('./contentPlugins'); -const articleRedirectsFile = require('./articleRedirects'); -const switcherConfig = require('./switcherConfig'); +const contentConfigs = require('./config/contentPlugins'); +const articleRedirectsFile = require('./config/articleRedirects'); +const switcherConfig = require('./config/switcherConfig'); +const tutorials = require('./config/tutorials'); const { buildPluginsConfig, maintainPluginsConfig, -} = require('./versionedConfig'); +} = require('./config/versionedConfig'); const { createVersionRedirects, } = require('./src/utils/pluginConfigGenerators'); @@ -210,6 +211,7 @@ module.exports = async () => { ], ], plugins: [ + ...tutorials, ...contentPlugins, [ '@docusaurus/plugin-content-docs', @@ -433,15 +435,6 @@ module.exports = async () => { ], 'plugin-image-zoom', ], - stylesheets: [ - { - href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', - type: 'text/css', - integrity: - 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', - crossorigin: 'anonymous', - }, - ], themes: [ 'docusaurus-theme-openapi-docs', '@saucelabs/theme-github-codeblock', diff --git a/scripts/get_wasp_references.sh b/scripts/get_wasp_references.sh index a9e19a4c50b..35036f26915 100755 --- a/scripts/get_wasp_references.sh +++ b/scripts/get_wasp_references.sh @@ -5,11 +5,17 @@ mkdir tmp cd tmp # Download and copy docs -curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.0/iscmagic.tar.gz | tar xzv -cp -Rv docs/iscmagic/* ../docs/build/isc/v1.0.0-rc.6/docs/reference/magic-contract/ +curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.1/iscmagic.tar.gz | tar xzv +cp -Rv docs/iscmagic/* ../docs/build/isc/v1.1/docs/reference/magic-contract/ -curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.0/iscutils.tar.gz | tar xzv -cp -Rv docs/iscutils ../docs/build/isc/v1.0.0-rc.6/docs/reference/ +curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.1/iscutils.tar.gz | tar xzv +cp -Rv docs/iscutils ../docs/build/isc/v1.1/docs/reference/ + +curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.3/iscmagic.tar.gz | tar xzv +cp -Rv docs/iscmagic/* ../docs/build/isc/v1.3-alpha/docs/reference/magic-contract/ + +curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.3/iscutils.tar.gz | tar xzv +cp -Rv docs/iscutils ../docs/build/isc/v1.3-alpha/docs/reference/ # Return to root and cleanup cd - diff --git a/src/plugins/docs/index.d.ts b/src/plugins/docs/index.d.ts index 4e4e03b0a83..572ba55a8f7 100644 --- a/src/plugins/docs/index.d.ts +++ b/src/plugins/docs/index.d.ts @@ -1,25 +1,14 @@ import { Options as DocsOptions, PluginOptions as DocsPluginOptions, - LoadedContent as DocsLoadedContent, - DocMetadata as DocsDocMetadata, } from '@docusaurus/plugin-content-docs'; import { OptionValidationContext as DocsOptionValidationContext, Validate, } from '@docusaurus/types'; -export type DocMetadata = DocsDocMetadata & { - bannerContent?: string; -}; - -export type LoadedContent = DocsLoadedContent & { - bannerContent?: string; -}; - export type PluginOptions = DocsPluginOptions & { globalSidebars: string[]; - bannerPath?: string; }; export type Options = Partial; diff --git a/src/plugins/docs/index.js b/src/plugins/docs/index.js index f35a7ee8c7a..fa2630add3d 100644 --- a/src/plugins/docs/index.js +++ b/src/plugins/docs/index.js @@ -43,57 +43,21 @@ var __importStar = __setModuleDefault(result, mod); return result; }; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.validateOptions = void 0; const plugin_content_docs_1 = __importStar( require('@docusaurus/plugin-content-docs'), ); -const promises_1 = __importDefault(require('fs/promises')); -const path_1 = __importDefault(require('path')); async function pluginDocs(context, options) { // Destructure to separate the Docusaurus docs plugin options // and initialize the Docusaurus docs plugin to wrap. - const { bannerPath, globalSidebars, ...docsOptions } = options; + const { globalSidebars, ...docsOptions } = options; const plugin = await (0, plugin_content_docs_1.default)(context, docsOptions); return { ...plugin, - getPathsToWatch: () => { - const pathsToWatch = plugin.getPathsToWatch(); - if (bannerPath) - pathsToWatch.push(path_1.default.resolve(context.siteDir, bannerPath)); - return pathsToWatch; - }, - loadContent: async () => { - const docsLoadedContent = await plugin.loadContent(); - return { - ...docsLoadedContent, - // Load banner content from file - bannerContent: bannerPath - ? await promises_1.default.readFile(bannerPath, { - encoding: 'utf-8', - }) - : undefined, - }; - }, - translateContent: ({ content, ...args }) => { - // Propagate banner content - const { bannerContent, ...docsContent } = content; - const docsContentLoaded = plugin.translateContent({ - content: docsContent, - ...args, - }); - return { - ...docsContentLoaded, - bannerContent, - }; - }, // Override the `contentLoaded` function to add sidebars to the // global data exposed by the Docusaurus docs plugin. contentLoaded: async ({ actions, content, ...args }) => { - const { bannerContent, ...docsContent } = content; const globalSidebarEntries = []; const createData = async (name, data) => { // Hook into the `createData` call to extract the sidebars we need. @@ -105,18 +69,7 @@ async function pluginDocs(context, options) { .filter(([sidebarId]) => globalSidebars.includes(sidebarId)) .forEach((entry) => globalSidebarEntries.push(entry)); } - return await actions.createData( - name, - // Expose banner content to be used by the DocBanner theme component - JSON.stringify( - { - ...versionMetadata, - bannerContent, - }, - null, - 2, - ), - ); + return await actions.createData(name, data); }; const setGlobalData = (data) => { actions.setGlobalData({ @@ -126,7 +79,7 @@ async function pluginDocs(context, options) { }; await plugin.contentLoaded({ ...args, - content: docsContent, + content, actions: { ...actions, createData, @@ -136,15 +89,46 @@ async function pluginDocs(context, options) { }, }; } -pluginDocs.validateOptions = ({ validate, options }) => { - const { bannerPath, globalSidebars = [], ...docsOptions } = options; +exports.default = pluginDocs; +function validateOptions({ validate, options }) { + const { versions = {}, globalSidebars = [], ...docsOptions } = options; + const versionEntries = Object.entries(versions); + if (versionEntries.length > 1) + throw 'Multiple Docusuaurus doc versions not allowed in the Wiki'; + // Handle version banner. + const versionBannerMap = {}; + const docsVersionEntries = versionEntries.map( + ([versionLabel, versionOptions]) => { + // TODO: validate banner + const { banner, ...docsVersionOptions } = versionOptions; + versionBannerMap[versionLabel] = banner; + return [versionLabel, docsVersionOptions]; + }, + ); + const validatedDocsOptions = (0, plugin_content_docs_1.validateOptions)({ + validate, + options: { + ...docsOptions, + versions: Object.fromEntries(docsVersionEntries), + }, + }); + // Re-add banner. + validatedDocsOptions.versions = Object.fromEntries( + Object.entries(validatedDocsOptions.versions).map( + ([versionLabel, versionOptions]) => { + return [ + versionLabel, + { + ...versionOptions, + banner: versionBannerMap[versionLabel], + }, + ]; + }, + ), + ); return { - ...(0, plugin_content_docs_1.validateOptions)({ - validate, - options: docsOptions, - }), + ...validatedDocsOptions, globalSidebars, - bannerPath, }; -}; -module.exports = pluginDocs; +} +exports.validateOptions = validateOptions; diff --git a/src/theme/DocBanner/index.tsx b/src/theme/DocBanner/index.tsx deleted file mode 100644 index b36a42951c4..00000000000 --- a/src/theme/DocBanner/index.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import { useDoc } from '@docusaurus/theme-common/internal'; -import { DocMetadata } from '../../../../src/plugins/docs'; -import ReactMarkdown from 'react-markdown'; -import './styles.css'; - -export default function DocBanner() { - const { bannerContent } = useDoc().metadata as DocMetadata; - - if (!bannerContent) return null; - - return ( - - {bannerContent} - - ); -} diff --git a/src/theme/DocBanner/styles.css b/src/theme/DocBanner/styles.css deleted file mode 100644 index 6af2f55eacf..00000000000 --- a/src/theme/DocBanner/styles.css +++ /dev/null @@ -1,7 +0,0 @@ -.doc-banner p { - margin: 0; -} - -.doc-banner p + p { - margin: var(--ifm-paragraph-margin-bottom) 0 0; -} diff --git a/src/theme/DocItem/Layout/index.tsx b/src/theme/DocItem/Layout/index.tsx deleted file mode 100644 index bd5419b2661..00000000000 --- a/src/theme/DocItem/Layout/index.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/** - * SWIZZLED VERSION: 2.4.1 - * REASONS: - * - Add custom Banner component. - */ - -import React from 'react'; -import clsx from 'clsx'; -import { useWindowSize } from '@docusaurus/theme-common'; -import { useDoc } from '@docusaurus/theme-common/internal'; -import DocItemPaginator from '@theme/DocItem/Paginator'; -import DocVersionBanner from '@theme/DocVersionBanner'; -import DocVersionBadge from '@theme/DocVersionBadge'; -import DocItemFooter from '@theme/DocItem/Footer'; -import DocItemTOCMobile from '@theme/DocItem/TOC/Mobile'; -import DocItemTOCDesktop from '@theme/DocItem/TOC/Desktop'; -import DocItemContent from '@theme/DocItem/Content'; -import DocBreadcrumbs from '@theme/DocBreadcrumbs'; -import type { Props } from '@theme/DocItem/Layout'; -import DocBanner from '@theme/DocBanner'; - -import styles from './styles.module.css'; - -/** - * Decide if the toc should be rendered, on mobile or desktop viewports - */ -function useDocTOC() { - const { frontMatter, toc } = useDoc(); - const windowSize = useWindowSize(); - - const hidden = frontMatter.hide_table_of_contents; - const canRender = !hidden && toc.length > 0; - - const mobile = canRender ? : undefined; - - const desktop = - canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? ( - - ) : undefined; - - return { - hidden, - mobile, - desktop, - }; -} - -export default function DocItemLayout({ children }: Props): JSX.Element { - const docTOC = useDocTOC(); - return ( -
-
- - -
-
- - - {docTOC.mobile} - {children} - -
- -
-
- {docTOC.desktop &&
{docTOC.desktop}
} -
- ); -} diff --git a/src/theme/DocItem/Layout/styles.module.css b/src/theme/DocItem/Layout/styles.module.css deleted file mode 100644 index d5aaec1322c..00000000000 --- a/src/theme/DocItem/Layout/styles.module.css +++ /dev/null @@ -1,10 +0,0 @@ -.docItemContainer header + *, -.docItemContainer article > *:first-child { - margin-top: 0; -} - -@media (min-width: 997px) { - .docItemCol { - max-width: 75% !important; - } -} diff --git a/src/theme/DocVersionBanner/index.tsx b/src/theme/DocVersionBanner/index.tsx new file mode 100644 index 00000000000..90bbff23f15 --- /dev/null +++ b/src/theme/DocVersionBanner/index.tsx @@ -0,0 +1,200 @@ +/** + * SWIZZLED VERSION: 2.4.3 + * REASONS: + * - Remove use of siteTitle as it is irrelevant in our setup. + * - Link to our own latest version. + * - Update text pointing to latest version + * - Add `staging` banner. + */ +import React, { type ComponentType } from 'react'; +import clsx from 'clsx'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import Link from '@docusaurus/Link'; +import Translate from '@docusaurus/Translate'; +import { type GlobalVersion } from '@docusaurus/plugin-content-docs/client'; +import { ThemeClassNames } from '@docusaurus/theme-common'; +import { useDocsVersion } from '@docusaurus/theme-common/internal'; +import type { Props } from '@theme/DocVersionBanner'; +import type { + VersionBanner, + PropVersionMetadata, +} from '@docusaurus/plugin-content-docs'; +import { useWikiPreferredVersion } from '@site/src/utils/wikiPreferredVersion'; +import { useLocation } from '@docusaurus/router'; +import { + useAllLatestVersion, + useCurrentDocPlugins, +} from '@site/src/utils/wikiVersion'; + +type WikiVersionBanner = VersionBanner & 'staging'; + +type BannerLabelComponentProps = { + siteTitle: string; + versionMetadata: PropVersionMetadata; +}; + +function UnreleasedVersionLabel({ + versionMetadata, +}: BannerLabelComponentProps) { + return ( + {versionMetadata.label}, + }} + > + {'This is unreleased documentation for {versionLabel} version.'} + + ); +} + +function StagingVersionLabel({ versionMetadata }: BannerLabelComponentProps) { + return ( + {versionMetadata.label}, + }} + > + { + 'This is documentation for {versionLabel} version wich is currently running on our staging network.' + } + + ); +} + +function UnmaintainedVersionLabel({ + versionMetadata, +}: BannerLabelComponentProps) { + return ( + {versionMetadata.label}, + }} + > + { + 'This is documentation for {versionLabel}, which is no longer actively maintained.' + } + + ); +} + +const BannerLabelComponents: { + [banner in WikiVersionBanner]: ComponentType; +} = { + unreleased: UnreleasedVersionLabel, + staging: StagingVersionLabel, + unmaintained: UnmaintainedVersionLabel, +}; + +function BannerLabel(props: BannerLabelComponentProps) { + const BannerLabelComponent = + BannerLabelComponents[props.versionMetadata.banner!]; + return ; +} + +function LatestVersionSuggestionLabel({ + versionLabel, + to, + onClick, +}: { + to: string; + onClick: () => void; + versionLabel: string; +}) { + return ( + + + + latest version + + + + ), + }} + > + { + 'For the latest stable release, see the {latestVersionLink} ({versionLabel}).' + } + + ); +} + +function DocVersionBannerEnabled({ + className, + versionMetadata, +}: Props & { + versionMetadata: PropVersionMetadata; +}): JSX.Element { + const { + siteConfig: { title: siteTitle }, + } = useDocusaurusContext(); + const { pathname } = useLocation(); + const pluginIds = useCurrentDocPlugins(pathname); + + const getVersionMainDoc = (version: GlobalVersion) => + version.docs.find((doc) => doc.id === version.mainDocId)!; + + const { savePreferredVersionName } = useWikiPreferredVersion( + pathname, + pluginIds, + ); + + const latestVersionSuggestion = useAllLatestVersion(pluginIds); + const latestDocSuggestion = getVersionMainDoc(latestVersionSuggestion); + + // Try to link to same doc in latest version (not always possible), falling + // back to main doc of latest version + const latestVersionSuggestedDoc = + latestDocSuggestion ?? getVersionMainDoc(latestVersionSuggestion); + + return ( +
+
+ +
+
+ savePreferredVersionName(latestVersionSuggestion.name)} + /> +
+
+ ); +} + +export default function DocVersionBanner({ + className, +}: Props): JSX.Element | null { + const versionMetadata = useDocsVersion(); + if (versionMetadata.banner) { + return ( + + ); + } + return null; +} diff --git a/src/theme/Glossary/index.tsx b/src/theme/Glossary/index.tsx index f012b4d75b7..b8237730fcc 100644 --- a/src/theme/Glossary/index.tsx +++ b/src/theme/Glossary/index.tsx @@ -4,7 +4,7 @@ import { toTitleCase } from '@artsy/to-title-case'; import { clsx } from 'clsx'; export default function Glossary() { - const glossary = require('@site/common/jargon.js'); + const glossary = require('@site/config/jargon.js'); const parse = require('html-react-parser'); const sortedGlossary = Object.keys(glossary) diff --git a/src/utils/config.js b/src/utils/config.js index 4d6564422bd..437e2a3ecba 100644 --- a/src/utils/config.js +++ b/src/utils/config.js @@ -1,5 +1,5 @@ const path = require('path'); -const defaultSettings = require('../common/defaultContentPlugin'); +const defaultSettings = require('./defaultContentPlugin'); const fs = require('fs'); /** diff --git a/src/common/defaultContentPlugin.js b/src/utils/defaultContentPlugin.js similarity index 89% rename from src/common/defaultContentPlugin.js rename to src/utils/defaultContentPlugin.js index a2079d57bb0..050ec334931 100644 --- a/src/common/defaultContentPlugin.js +++ b/src/utils/defaultContentPlugin.js @@ -1,7 +1,7 @@ /** @type {import('@docusaurus/plugin-content-docs').Options} */ module.exports = async () => { const jargonPlugin = (await import('rehype-jargon')).default; - const jargonConfig = (await import('./../../common/jargon.js')).default; + const jargonConfig = (await import('../../config/jargon.js')).default; return { editUrl: 'https://github.com/iotaledger/iota-wiki/edit/main/', diff --git a/src/utils/pluginConfigGenerators.js b/src/utils/pluginConfigGenerators.js index 864841a20a6..4cd7f6769f3 100644 --- a/src/utils/pluginConfigGenerators.js +++ b/src/utils/pluginConfigGenerators.js @@ -23,19 +23,22 @@ function generatePluginConfig(pluginConfig, basePath) { return doc.versions.map((version) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { label, badges, ...rest } = version; + const { label, badges, banner, ...rest } = version; // TODO: This could be removed once we don't use points in paths anymore. const plugin_name_path = doc.routeBasePath ? doc.routeBasePath : doc.id; - const extended_base_path = - basePath + plugin_name_path + '/' + (label ? label : ''); + const extended_base_path = [ + basePath, + plugin_name_path, + ...(label ? [label] : []), + ].join('/'); plugin = { id: doc.id + (label ? '-' + label.replace(/\./g, '-') : ''), - path: path.resolve(extended_base_path + '/docs'), + path: path.resolve(extended_base_path, 'docs'), routeBasePath: plugin_name_path, - sidebarPath: path.resolve(extended_base_path + '/sidebars.js'), + sidebarPath: path.resolve(extended_base_path, 'sidebars.js'), ...(doc.versions.length > 1 ? { versions: { @@ -43,6 +46,7 @@ function generatePluginConfig(pluginConfig, basePath) { label, path: mainVersion.label === label ? undefined : label, badge: true, + banner, }, }, } diff --git a/src/utils/tags.ts b/src/utils/tags.ts index 367cf687caf..465660936b2 100644 --- a/src/utils/tags.ts +++ b/src/utils/tags.ts @@ -1,5 +1,5 @@ //TODO tutorial.json should propably be a key-value dictionary -import config from '../../tutorials/tags.json'; +import config from '../../config/tags.json'; export interface Tag { label: string; diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-A.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-A.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-A.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-A.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-B.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-B.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-B.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-B.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-C.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-C.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-C.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-C.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-D.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-D.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-D.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-D.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-E.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-E.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-E.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-E.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-F.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-F.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-F.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-F.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-G.png b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-G.png similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-G.png rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-G.png diff --git a/tutorials/static/connect-shimmerevm-and-deploy.png b/static/img/tutorials/connect-shimmerevm-and-deploy.png similarity index 100% rename from tutorials/static/connect-shimmerevm-and-deploy.png rename to static/img/tutorials/connect-shimmerevm-and-deploy.png diff --git a/tutorials/static/connect-shimmerevm-testnet-and-deploy.png b/static/img/tutorials/connect-shimmerevm-testnet-and-deploy.png similarity index 100% rename from tutorials/static/connect-shimmerevm-testnet-and-deploy.png rename to static/img/tutorials/connect-shimmerevm-testnet-and-deploy.png diff --git a/tutorials/static/create-nft-with-wallet-lib.png b/static/img/tutorials/create-nft-with-wallet-lib.png similarity index 100% rename from tutorials/static/create-nft-with-wallet-lib.png rename to static/img/tutorials/create-nft-with-wallet-lib.png diff --git a/tutorials/static/evm-toolkit-custom-network.png b/static/img/tutorials/evm-toolkit-custom-network.png similarity index 100% rename from tutorials/static/evm-toolkit-custom-network.png rename to static/img/tutorials/evm-toolkit-custom-network.png diff --git a/tutorials/static/evm-toolkit.png b/static/img/tutorials/evm-toolkit.png similarity index 100% rename from tutorials/static/evm-toolkit.png rename to static/img/tutorials/evm-toolkit.png diff --git a/tutorials/static/hornet-inx-interaction.png b/static/img/tutorials/hornet-inx-interaction.png similarity index 100% rename from tutorials/static/hornet-inx-interaction.png rename to static/img/tutorials/hornet-inx-interaction.png diff --git a/tutorials/static/metamask-shimmerevm-mainnet.png b/static/img/tutorials/metamask-shimmerevm-mainnet.png similarity index 100% rename from tutorials/static/metamask-shimmerevm-mainnet.png rename to static/img/tutorials/metamask-shimmerevm-mainnet.png diff --git a/tutorials/static/metamask-shimmerevm.png b/static/img/tutorials/metamask-shimmerevm.png similarity index 100% rename from tutorials/static/metamask-shimmerevm.png rename to static/img/tutorials/metamask-shimmerevm.png diff --git a/tutorials/static/nft-image.jpg b/static/img/tutorials/nft-image.jpg similarity index 100% rename from tutorials/static/nft-image.jpg rename to static/img/tutorials/nft-image.jpg diff --git a/tutorials/static/proof-inclusion-of-a-block-architecture.png b/static/img/tutorials/proof-inclusion-of-a-block-architecture.png similarity index 100% rename from tutorials/static/proof-inclusion-of-a-block-architecture.png rename to static/img/tutorials/proof-inclusion-of-a-block-architecture.png diff --git a/tutorials/static/proof-inclusion-of-a-block.png b/static/img/tutorials/proof-inclusion-of-a-block.png similarity index 100% rename from tutorials/static/proof-inclusion-of-a-block.png rename to static/img/tutorials/proof-inclusion-of-a-block.png diff --git a/tutorials/static/send-iota-tokens-with-javascript.svg b/static/img/tutorials/send-iota-tokens-with-javascript.svg similarity index 100% rename from tutorials/static/send-iota-tokens-with-javascript.svg rename to static/img/tutorials/send-iota-tokens-with-javascript.svg diff --git a/tutorials/static/send-shimmer-tokens-with-iota-sdk.png b/static/img/tutorials/send-shimmer-tokens-with-iota-sdk.png similarity index 100% rename from tutorials/static/send-shimmer-tokens-with-iota-sdk.png rename to static/img/tutorials/send-shimmer-tokens-with-iota-sdk.png diff --git a/tutorials/static/send-shimmer-tokens-with-javascript.png b/static/img/tutorials/send-shimmer-tokens-with-javascript.png similarity index 100% rename from tutorials/static/send-shimmer-tokens-with-javascript.png rename to static/img/tutorials/send-shimmer-tokens-with-javascript.png diff --git a/tutorials/static/setup_iota-js_for_development.png b/static/img/tutorials/setup_iota-js_for_development.png similarity index 100% rename from tutorials/static/setup_iota-js_for_development.png rename to static/img/tutorials/setup_iota-js_for_development.png diff --git a/tutorials/static/shimmer-hardhat-setup.png b/static/img/tutorials/shimmer-hardhat-setup.png similarity index 100% rename from tutorials/static/shimmer-hardhat-setup.png rename to static/img/tutorials/shimmer-hardhat-setup.png diff --git a/tutorials/static/shimmer-testnet-faucet.png b/static/img/tutorials/shimmer-testnet-faucet.png similarity index 100% rename from tutorials/static/shimmer-testnet-faucet.png rename to static/img/tutorials/shimmer-testnet-faucet.png diff --git a/tutorials/static/shimmerevm-dapp-voting.jpg b/static/img/tutorials/shimmerevm-dapp-voting.jpg similarity index 100% rename from tutorials/static/shimmerevm-dapp-voting.jpg rename to static/img/tutorials/shimmerevm-dapp-voting.jpg diff --git a/tutorials/static/shimmerevm-hardhat.jpg b/static/img/tutorials/shimmerevm-hardhat.jpg similarity index 100% rename from tutorials/static/shimmerevm-hardhat.jpg rename to static/img/tutorials/shimmerevm-hardhat.jpg diff --git a/tutorials/static/voting-dapp.jpg b/static/img/tutorials/voting-dapp.jpg similarity index 100% rename from tutorials/static/voting-dapp.jpg rename to static/img/tutorials/voting-dapp.jpg diff --git a/tutorials/static/wallet-setup.png b/static/img/tutorials/wallet-setup.png similarity index 100% rename from tutorials/static/wallet-setup.png rename to static/img/tutorials/wallet-setup.png diff --git a/tutorials/static/wasp-setup-shimmer.png b/static/img/tutorials/wasp-setup-shimmer.png similarity index 100% rename from tutorials/static/wasp-setup-shimmer.png rename to static/img/tutorials/wasp-setup-shimmer.png diff --git a/screenshot.css b/tests/screenshot.css similarity index 100% rename from screenshot.css rename to tests/screenshot.css diff --git a/screenshot.spec.ts b/tests/screenshot.spec.ts similarity index 91% rename from screenshot.spec.ts rename to tests/screenshot.spec.ts index 4ca0a67a310..fc120009b8c 100644 --- a/screenshot.spec.ts +++ b/tests/screenshot.spec.ts @@ -5,8 +5,8 @@ import { extractSitemapPathnames, pathnameToArgosName } from './utils'; // Constants const siteUrl = 'http://localhost:3000'; -const sitemapPath = './build/sitemap.xml'; -const stylesheetPath = './screenshot.css'; +const sitemapPath = require.resolve('../build/sitemap.xml'); +const stylesheetPath = require.resolve('./screenshot.css'); const stylesheet = fs.readFileSync(stylesheetPath).toString(); // Wait for hydration, requires Docusaurus v2.4.3+ diff --git a/utils.ts b/tests/utils.ts similarity index 100% rename from utils.ts rename to tests/utils.ts diff --git a/tutorials/docusaurus.config.js b/tutorials/docusaurus.config.js deleted file mode 100644 index 54a6b42d287..00000000000 --- a/tutorials/docusaurus.config.js +++ /dev/null @@ -1,256 +0,0 @@ -const path = require('path'); -const pluginTutorial = require('../src/plugins/tutorial'); - -module.exports = { - plugins: [ - [ - '@docusaurus/plugin-content-pages', - { - id: 'single-page-tutorials', - path: path.resolve(__dirname, 'pages'), - routeBasePath: '/tutorials', - }, - ], - [ - pluginTutorial, - { - title: 'Run a Wasp Node', - description: 'In this tutorial you will learn how to run a wasp node.', - preview: '/IOTA-Smart-Contract-Tutorials-A.jpg', - route: '/wasp/how-tos/running-a-node', - tags: ['text', 'video'], - }, - ], - [ - pluginTutorial, - { - title: 'Run a Wasp Chain', - description: 'In this tutorial you will learn how to run a wasp chain.', - preview: '/IOTA-Smart-Contract-Tutorials-B.jpg', - route: '/wasp/how-tos/setting-up-a-chain', - tags: ['text', 'video'], - }, - ], - [ - pluginTutorial, - { - title: 'Deploy a WASM Smart Contract', - description: - 'In this tutorial you will learn how to deploy a wasm smart contract.', - preview: '/IOTA-Smart-Contract-Tutorials-C.jpg', - route: '/wasp/how-tos/setting-up-a-chain#deploying-a-wasm-contract', - tags: ['text', 'video'], - }, - ], - [ - pluginTutorial, - { - title: 'Deploy a Solidity Smart Contract Using Remix + Metamask', - description: - 'In this tutorial you will learn how to deploy a solidity smart contract on EVM using remix and metamask.', - preview: '/IOTA-Smart-Contract-Tutorials-E.jpg', - route: '/isc/getting-started/tools#remix', - tags: ['text', 'video'], - }, - ], - [ - pluginTutorial, - { - title: 'Generate a WASM Smart Contract Using the Schema Tool', - description: - 'In this tutorial you will learn how to use schema tool to generate smart contract template code on rust and golang', - preview: '/IOTA-Smart-Contract-Tutorials-G.png', - route: '/isc/schema/how-tos/usage', - tags: ['text', 'video'], - }, - ], - [ - pluginTutorial, - { - title: - 'Generate a WASM Smart Contract Using the Schema Tool in Typescript', - description: - 'In this tutorial you will learn how to use schema tool to generate smart contract template code on typescript', - preview: '/IOTA-Smart-Contract-Tutorials-G.png', - route: 'https://www.youtube.com/watch?v=P5HMgmY3DMM', - tags: ['video'], - }, - ], - [ - pluginTutorial, - { - title: 'Interact with IOTA Node Extension (INX)', - description: - 'In this tutorial you will learn how to interact with the IOTA Node Extension (INX) interface based on gRPC.', - preview: '/hornet-inx-interaction.png', - route: 'tutorials/hornet-inx-interaction', - tags: ['text', 'getting-started', 'shimmer', 'js'], - }, - ], - [ - pluginTutorial, - { - title: 'Tokenless Data Notarization', - description: - 'Proove that a block was part of the past Tangle, even if this part of the Tangle was already pruned from network nodes.', - preview: '/proof-inclusion-of-a-block.png', - route: 'tutorials/proof-inclusion-of-a-block', - tags: ['text', 'getting-started', 'js', 'client', 'shimmer'], - }, - ], - [ - pluginTutorial, - { - title: 'Set Up a Testnet Address and Receive Funds From the Faucet', - description: - 'In this tutorial you will learn how to create a seed and address with wallet.rs and receive testnet tokens from the faucet.', - preview: '/wallet-setup.png', - route: 'tutorials/wallet-setup', - tags: ['text', 'getting-started', 'node_js', 'wallet', 'shimmer'], - }, - ], - [ - pluginTutorial, - { - title: 'How to Set Up iota.js for Development', - description: - 'In this tutorial you will learn how to create a new project, generate a new address and receive x funds from the faucet.', - preview: '/setup_iota-js_for_development.png', - route: 'tutorials/setup_iota-js_for_development', - tags: ['text', 'getting-started', 'client', 'shimmer', 'js'], - }, - ], - [ - pluginTutorial, - { - title: - 'Connect to Shimmer EVM Testnet and Deploy a Solidity Smart Contract', - description: - 'In this tutorial, we will connect to Shimmer EVM Testnet, connect Metamask to it, get funded and deploy a smart contract in Solidity.', - preview: '/connect-shimmerevm-testnet-and-deploy.png', - route: 'tutorials/shimmerevm-testnet-setup', - tags: [ - 'text', - 'shimmer', - 'solidity', - 'getting-started', - 'wasp', - 'iscp', - 'video', - ], - }, - ], - [ - pluginTutorial, - { - title: - 'Tutorial - Deploy a Solidity Smart Contract on ShimmerEVM Testnet Using Hardhat', - description: - 'In this tutorial, you will learn how to set up Hardhat and use it to build, test and deploy a simple smart contract on ShimmerEVM.', - preview: '/shimmerevm-hardhat.jpg', - route: 'tutorials/shimmerevm-testnet-hardhat', - tags: [ - 'text', - 'shimmer', - 'solidity', - 'shimmerevm', - 'hardhat', - 'iscp', - 'video', - ], - }, - ], - [ - pluginTutorial, - { - title: 'Create a Simple Voting dApp on ShimmerEVM', - description: - 'This tutorial will guide you as you write and deploy a voting dApp on ShimmerEVM. You can vote on a few options and view the results; all data will be stored on-chain.', - preview: '/shimmerevm-dapp-voting.jpg', - route: 'tutorials/shimmerevm-dapp-voting', - tags: ['text', 'shimmer', 'solidity', 'iscp'], - }, - ], - [ - pluginTutorial, - { - title: 'Set Up WASP locally Using Docker', - description: - 'In this tutorial you will learn how to set up WASP and Hornet locally for Development setup.', - preview: '/wasp-setup-shimmer.png', - route: 'https://youtu.be/ltem9Bh_4hA', - tags: ['text', 'shimmer', 'video', 'wasp', 'iscp'], - }, - ], - [ - pluginTutorial, - { - title: 'Create an NFT with the IOTA SDK and IPFS in NodeJs', - description: - 'In this tutorial you will learn how to create a NFT on the Shimmer network with iota-sdk and IPFS.', - preview: '/create-nft-with-wallet-lib.png', - route: 'tutorials/create-nft-with-iota-sdk', - tags: [ - 'text', - 'getting-started', - 'node_js', - 'iota-sdk', - 'ipfs', - 'shimmer', - 'sdk', - ], - }, - ], - [ - pluginTutorial, - { - title: 'Send Shimmer Tokens with IOTA SDK in NodeJs', - description: - 'In this tutorial you will learn how to send Shimmer Tokens with IOTA SDK in NodeJs.', - preview: '/send-shimmer-tokens-with-iota-sdk.png', - route: 'tutorials/send-shimmer-tokens-with-iota-sdk', - tags: ['text', 'iota-sdk', 'sdk', 'getting-started', 'rust', 'shimmer'], - }, - ], - [ - pluginTutorial, - { - title: 'Connect to Shimmer EVM and Deploy a Solidity Smart Contract', - description: - 'In this tutorial, we will connect to Shimmer EVM, connect Metamask to it, get funded and deploy a smart contract in Solidity.', - preview: '/connect-shimmerevm-and-deploy.png', - route: 'tutorials/shimmerevm-setup', - tags: [ - 'text', - 'shimmer', - 'solidity', - 'getting-started', - 'wasp', - 'iscp', - 'video', - ], - }, - ], - [ - pluginTutorial, - { - title: - 'Tutorial - Deploy a Solidity Smart Contract on ShimmerEVM Using Hardhat', - description: - 'In this tutorial, you will learn how to set up Hardhat and use it to build, test and deploy a simple smart contract on ShimmerEVM.', - preview: '/shimmerevm-hardhat.jpg', - route: 'tutorials/shimmerevm-hardhat', - tags: [ - 'text', - 'shimmer', - 'solidity', - 'shimmerevm', - 'hardhat', - 'iscp', - 'video', - ], - }, - ], - ], - staticDirectories: [path.resolve(__dirname, 'static')], -};