PageSourceSearch

https://calimero-network.github.io/assets/js/1530097d.ba872c5a.js

js calimero-network.github.io collected 2026-10-03 08:45:29 UTC 36,637 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2584],{9115:(e,n,t)=>{t.d(n,{A:()=>l});t(30758);var i=t(13526);const r={tabItem:"tabItem_dpxk"};var o=t(86070);function l({children:e,hidden:n,className:t}){return(0,o.jsx)("div",{role:"tabpanel",className:(0,i.A)(r.tabItem,t),hidden:n,children:e})}},59221:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>s,default:()=>h,frontMatter:()=>l,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"tutorials/awesome-projects/building-with-stellar","title":"Building with Stellar","description":"Step-by-Step Guide to Building an Application for Calimero with Stellar","source":"@site/docs/06-tutorials/07-awesome-projects/04-building-with-stellar.mdx","sourceDirName":"06-tutorials/07-awesome-projects","slug":"/tutorials/awesome-projects/building-with-stellar","permalink":"/tutorials/awesome-projects/building-with-stellar","draft":false,"unlisted":false,"editUrl":"https://github.com/calimero-network/calimero-network.github.io/edit/master/docs/06-tutorials/07-awesome-projects/04-building-with-stellar.mdx","tags":[],"version":"current","lastUpdatedAt":1759836146000,"sidebarPosition":4,"frontMatter":{"id":"building-with-stellar","title":"Building with Stellar"},"sidebar":"tutorialSidebar","previous":{"title":"Building with Internet Computer (ICP)","permalink":"/tutorials/awesome-projects/building-with-icp"},"next":{"title":"Building with Ethereum","permalink":"/tutorials/awesome-projects/building-with-ethereum"}}');var r=t(86070),o=t(68820);t(83078),t(9115);const l={id:"building-with-stellar",title:"Building with Stellar"},s="Building with Stellar",a={},c=[{value:"Requirements",id:"requirements",level:2},{value:"Smart contract overview",id:"smart-contract-overview",level:2},{value:"Contracts overview",id:"contracts-overview",level:3},{value:"Context and Proxy Contract",id:"context-and-proxy-contract",level:2},{value:"Context contract",id:"context-contract",level:3},{value:"Proxy contract",id:"proxy-contract",level:3},{value:"Setting up and configuring nodes",id:"setting-up-and-configuring-nodes",level:2},{value:"Initialize and Start Nodes",id:"initialize-and-start-nodes",level:4},{value:"Install application",id:"install-application",level:4},{value:"Fund Proxy Contract",id:"fund-proxy-contract",level:4},{value:"Blockchain Demo Application",id:"blockchain-demo-application",level:2},{value:"Change Approval Threshold Proposal",id:"change-approval-threshold-proposal",level:3},{value:"Cross-Contract Call Proposal",id:"cross-contract-call-proposal",level:3},{value:"Conclusion",id:"conclusion",level:2}];function d(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"building-with-stellar",children:"Building with Stellar"})}),"\n",(0,r.jsx)(n.p,{children:"Step-by-Step Guide to Building an Application for Calimero with Stellar"}),"\n",(0,r.jsx)(n.p,{children:"This tutorial will cover the following topics:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Smart contract overview"})," - Overview of the smart contracts and their\nfunctionality."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Configuring Nodes"})," - Setting and configuring nodes, installing demo\napplication, creating context and inviting nodes into the context."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Installing a Blockchain Demo Application"})," - Setup demo application that\ncontains all functionalities for interaction with smart contracts."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Creating a Proposal"}),' - Creating a proposal to execute cross-contract call\nto "Greet" smart contract deployed in step 3.']}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsx)(n.p,{children:"For easier guidance, we have named each terminal block by their purpose."})}),"\n",(0,r.jsx)(n.h2,{id:"requirements",children:"Requirements"}),"\n",(0,r.jsx)(n.p,{children:"To follow this tutorial, you'll need the following:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Calimero Core - Installation instructions -\n",(0,r.jsx)(n.a,{href:"/getting-started/packaged#installation",children:"Instructions"})]}),"\n",(0,r.jsxs)(n.li,{children:["Demo Blockchain Integrations -\n",(0,r.jsx)(n.a,{href:"https://github.com/calimero-network/demo-blockchain-integrations",children:"Repository"})]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"You also need following tools:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Cargo"}),": Version ",(0,r.jsx)(n.code,{children:"1.86.0-nightly"})," used for tutorial -\n",(0,r.jsx)(n.a,{href:"https://www.rust-lang.org/tools/install",children:"url"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Pnpm"}),": Version ",(0,r.jsx)(n.code,{children:"9.6.0"})," used for tutorial -\n",(0,r.jsx)(n.a,{href:"https://pnpm.io/installation",children:"url"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Stellar CLI"})," - Installation instructions -\n",(0,r.jsx)(n.a,{href:"https://developers.stellar.org/docs/build/smart-contracts/getting-started/setup#install-the-stellar-cli",children:"Instructions"})]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"smart-contract-overview",children:"Smart contract overview"}),"\n",(0,r.jsx)(n.h3,{id:"contracts-overview",children:"Contracts overview"}),"\n",(0,r.jsx)(n.p,{children:"Both contracts are written in Rust, you can find their implementations in the\nfollowing repositories:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://github.com/calimero-network/core/tree/master/contracts/stellar/context-config",children:"Context contract"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://github.com/calimero-network/core/tree/master/contracts/stellar/context-proxy",children:"Proxy contract"})}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"context-and-proxy-contract",children:"Context and Proxy Contract"}),"\n",(0,r.jsx)(n.h3,{id:"context-contract",children:"Context contract"}),"\n",(0,r.jsx)(n.p,{children:"Context contract is deployed on Stellar testnet and implemented into Calimero.\nIt is used to create and manage contexts and their members."}),"\n",(0,r.jsx)("lb",{}),"\n",(0,r.jsxs)(n.p,{children:["More information about context contract can be found\n",(0,r.jsx)(n.a,{href:"/core-concepts/blockchains-integration#context-contract",children:"here"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"proxy-contract",children:"Proxy contract"}),"\n",(0,r.jsx)(n.p,{children:"With each context creation a proxy contract for that context is deployed. Proxy\ncontract is used to handle blockchain operations such as cross-contract calls\nand transfers as well as storing variables."}),"\n",(0,r.jsx)("lb",{}),"\n",(0,r.jsxs)(n.p,{children:["More information about proxy contract can be found\n",(0,r.jsx)(n.a,{href:"/core-concepts/blockchains-integration#functionality-details",children:"here"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"setting-up-and-configuring-nodes",children:"Setting up and configuring nodes"}),"\n",(0,r.jsx)(n.admonition,{type:"info",children:(0,r.jsx)(n.p,{children:"By deafult proposal needs 3 approvals before it is executed so we will setup 3\nnodes."})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Initialize and start 3 nodes"}),"\n",(0,r.jsxs)(n.li,{children:["Install\n",(0,r.jsx)(n.a,{href:"https://github.com/calimero-network/demo-blockchain-integrations/tree/master/logic",children:"blockchain demo application"})]}),"\n",(0,r.jsx)(n.li,{children:"Create context for blockchain demo application"}),"\n",(0,r.jsx)(n.li,{children:"Invite all nodes in the same context"}),"\n"]}),"\n",(0,r.jsx)(n.h4,{id:"initialize-and-start-nodes",children:"Initialize and Start Nodes"}),"\n",(0,r.jsx)(n.p,{children:"Open 3 terminals side by side."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node1 Terminal"',children:"merod --node-name node1 init --server-port 2427 --swarm-port 2527\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node2 Terminal"',children:"merod --node-name node2 init --server-port 2428 --swarm-port 2528\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node3 Terminal"',children:"merod --node-name node3 init --server-port 2429 --swarm-port 2529\n"})}),"\n",(0,r.jsx)(n.p,{children:"The output should look like this:"}),"\n",(0,r.jsx)("img",{src:"/icp-tutorial/12_init_cali_nodes.png",alt:"init-nodes"}),"\n",(0,r.jsxs)(n.p,{children:["You can verify nodes initialization files by looking into ",(0,r.jsx)(n.code,{children:"~/.calimero"})," folder."]}
1),"\n",(0,r.jsxs)(n.admonition,{title:"Self signer vs. Relayer signer",type:"note",children:[(0,r.jsxs)(n.p,{children:["In ",(0,r.jsx)(n.code,{children:"config.toml"})," file you can see default configuration:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'[context.config.stellar]\nsigner = "self"\nprotocol = "stellar"\nnetwork = "testnet"\ncontract_id = <CONFIG_CONTRACT_ID>\n'})}),(0,r.jsxs)(n.p,{children:["If you use ",(0,r.jsx)(n.code,{children:"self"}),"\xa0for signer then you also need to change ",(0,r.jsx)(n.code,{children:"public"})," and ",(0,r.jsx)(n.code,{children:"secret"}),"\nkey."]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'[context.config.signer.self.stellar.testnet]\nrpc_url = "https://soroban-testnet.stellar.org/"\npublic_key = <YOUR_PUBLIC_KEY>\nsecret_key = <YOUR_SECRET_KEY>\n'})}),(0,r.jsxs)(n.p,{children:["The values auto-generated only represent the format needed for self signing\nfeature and are not real Stellar accounts. To create your own Stellar account\nwith CLI follow the Stellar\n",(0,r.jsx)(n.a,{href:"https://developers.stellar.org/docs/build/guides/cli",children:"Docs"})]}),(0,r.jsxs)(n.p,{children:["If signer is changed to ",(0,r.jsx)(n.code,{children:'signer = "relayer"'})," you don't need to changed anything\nas relayer will handle all the blockchain operations."]})]}),"\n",(0,r.jsxs)(n.p,{children:["More on node initialization can be found ",(0,r.jsx)(n.a,{href:"/getting-started/setup/",children:"here"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"Now we are going to start the nodes with the commands:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node1 Terminal"',children:"merod --node-name node1 run\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node2 Terminal"',children:"merod --node-name node2 run\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node3 Terminal"',children:"merod --node-name node3 run\n"})}),"\n",(0,r.jsx)(n.p,{children:"After running the nodes you should see the similar to this one:"}),"\n",(0,r.jsx)("img",{src:"/icp-tutorial/14_start_cali_nodes.png",alt:"running-nodes"}),"\n",(0,r.jsx)(n.h4,{id:"install-application",children:"Install application"}),"\n",(0,r.jsx)(n.p,{children:"Inside the node1 terminal we are going to install blockchain demo application."}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["Clone the\n",(0,r.jsx)(n.a,{href:"https://github.com/calimero-network/demo-blockchain-integrations",children:"Demo Blockchain Integrations"}),"\nrepository."]}),"\n",(0,r.jsxs)(n.li,{children:["Navigate to the ",(0,r.jsx)(n.code,{children:"logic"})," directory."]}),"\n",(0,r.jsxs)(n.li,{children:["Build the application using the ",(0,r.jsx)(n.code,{children:"build.sh"})," script, script will compile wasm\nfile in /res directory."]}),"\n",(0,r.jsxs)(n.li,{children:["Copy the ",(0,r.jsx)(n.code,{children:"blockchain.wasm"})," file path"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Applications are installed with the following command:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node1 Terminal"',children:"application install file <PATH_TO_blockchain.wasm_FILE>\n>Installed application: <APPLICATION_ID>\n"})}),"\n",(0,r.jsx)(n.p,{children:"After installing the application we can create context:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node1 Terminal"',children:"context create <APPLICATION_ID> --protocol stellar\n>Created context <CONTEXT_ID> with identity <CONTEXT_IDENTITY>\n"})}),"\n",(0,r.jsx)(n.p,{children:"After creating context we need to add node2 and node3 to it."}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)("br",{})," To be able to do that we need to create identities for node2 and node3\nwith whom they will join to the created context."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node2 Terminal"',children:"identity new\n>> Private key: <PRIVATE_KEY>\n>> Public key: <PUBLIC_KEY>\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node3 Terminal"',children:"identity new\n>> Private key: <PRIVATE_KEY>\n>> Public key: <PUBLIC_KEY>\n"})}),"\n",(0,r.jsx)(n.p,{children:"The output should look like this:"}),"\n",(0,r.jsx)("img",{src:"/icp-tutorial/16_create_new_identity.png",alt:"create-identity"}),"\n",(0,r.jsx)(n.p,{children:"After creating identities we can invite node2 and node3 to join the created\ncontext."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node1 Terminal"',children:"context invite <CONTEXT_ID> <PUBLIC_KEY_OF_NODE2> --as <CONTEXT_IDENTITY>\n>> Invitation payload: <INVITATION_PAYLOAD>\n"})}),"\n",(0,r.jsx)(n.p,{children:"This will generate a invitation payload which can node2 use to join the context.\nCopy the invitation payload and do the following command in node2 terminal:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node2 Terminal"',children:"context join <PRIVATE_KEY_OF_NODE2> <INVITATION_PAYLOAD>\n>> Joined context <CONTEXT_ID>\n"})}),"\n",(0,r.jsx)(n.p,{children:"Repeat the same steps for Node3."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node1 Terminal"',children:"context invite <CONTEXT_ID> <PUBLIC_KEY_OF_NODE3> --as <CONTEXT_IDENTITY>\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node3 Terminal"',children:"context join <PRIVATE_KEY_OF_NODE3> <INVITATION_PAYLOAD>\n>> Joined context <CONTEXT_ID>\n"})}),"\n",(0,r.jsx)(n.p,{children:"The output in terminal after inviting and joining nodes should look like this:"}),"\n",(0,r.jsx)("img",{src:"/icp-tutorial/16_invite_nodes.png",alt:"join-context"}),"\n",(0,r.jsx)("br",{}),"\n",(0,r.jsxs)(n.p,{children:["More on invitations and joining the context c
1an be found\n",(0,r.jsx)(n.a,{href:"https://calimero-network.github.io/tutorials/invitations-and-joinings",children:"here"})]}),"\n",(0,r.jsx)(n.p,{children:"Lastly we can check if all nodes are connected in context with:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node1 Terminal"',children:"context ls\n> <CONTEXT_ID>\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node1 Terminal"',children:"identity ls <CONTEXT_ID>\n"})}),"\n",(0,r.jsx)("img",{src:"/icp-tutorial/18_verify_context.png",alt:"context-members"}),"\n",(0,r.jsx)(n.p,{children:"We can see there are 3 nodes connected in context."}),"\n",(0,r.jsx)(n.h4,{id:"fund-proxy-contract",children:"Fund Proxy Contract"}),"\n",(0,r.jsx)(n.p,{children:"We have now installed the application and created context. To be able to fully\nuse proxy contract we need to fund it. To get proxy contract address we need to\nuse API GET call to retrieve it from the node."}),"\n",(0,r.jsx)(n.p,{children:"The 3 running nodes are located on:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://localhost:2427",children:"https://localhost:2427"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://localhost:2428",children:"https://localhost:2428"})}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"https://localhost:2429",children:"https://localhost:2429"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Any of them can be queried to get the value of proxy contract id."}),"\n",(0,r.jsxs)(n.p,{children:["API endpoint to fetch proxy contract id is:\n",(0,r.jsx)(n.code,{children:"http://localhost:2428/admin-api/contexts/CONTEXT_ID/proxy-contract"})]}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsx)(n.p,{children:"CONTEXT_ID can be copied from previous steps"}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["And for our case it is:\n",(0,r.jsx)(n.code,{children:"http://localhost:2428/admin-api/contexts/7krojDziAKRWP8KrUD8aYGL3z5peScNxPXaBWTKCFr2h/proxy-contract"})]}),"\n",(0,r.jsx)(n.p,{children:"Example of request in postman:"}),"\n",(0,r.jsx)("img",{src:"/icp-tutorial/proxy_contract_stellar.png",alt:"proxy-contract"}),"\n",(0,r.jsx)(n.p,{children:"With proxy contract id we can now fund it using Stellar CLI."}),"\n",(0,r.jsx)(n.p,{children:"To be able to fund the contract we need to create a testnet account and seed it\nwith tokens."}),"\n",(0,r.jsx)(n.p,{children:"You can create a testnet account and automatically fund it by using Stellar CLI:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"stellar keys generate --global <NAME_OF_ACCOUNT> --network testnet --fund\n"})}),"\n",(0,r.jsx)(n.p,{children:"Where:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"<NAME_OF_ACCOUNT>"})," is the name of the account you want to create."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"To get the account address you can use the following command:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"stellar keys address <NAME_OF_ACCOUNT>\n> <ACCOUNT_ADDRESS>\n"})}),"\n",(0,r.jsx)(n.p,{children:"Now you can fund the contract by using the following command:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"stellar contract invoke \\\n  --id CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC \\\n  --source <NAME_OF_ACCOUNT> \\\n  --network testnet \\\n  -- transfer \\\n  --from <ACCOUNT_ADDRESS> \\\n  --to <PROXY_CONTRACT_ID> \\\n  --amount 100000000\n"})}),"\n",(0,r.jsx)(n.p,{children:"Where:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"<NAME_OF_ACCOUNT>"})," is the name of the account for signing the transaction."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC"})," is the address of\nthe Stellar testnet ledger contract."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"<ACCOUNT_ADDRESS>"})," is the address of the account you created."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"<PROXY_CONTRACT_ID>"})," is the address of the proxy contract you want to fund."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"100000000"})," is the amount of lumens you want to fund the contract with. (1 XLM\n= 10000000)"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"To verify contract balance you can check it on Stellar Explorer by visiting:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.code,{children:"https://stellar.expert/explorer/testnet/contract/<PROXY_CONTRACT_ID>"})}),"\n",(0,r.jsx)(n.h2,{id:"blockchain-demo-application",children:"Blockchain Demo Application"}),"\n",(0,r.jsx)(n.p,{children:"This application is used to demonstrate how to interact with Calimero Proxy\ncontract through creating, approving and executing proposals."}),"\n",(0,r.jsx)(n.p,{children:"The proxy contract supports the following types of proposals:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Exter
1nal function call"})," - Enables cross-contract call execution."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Transfer"})," - Allows transferring funds."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Set approval threshold"})," - Specifies the number of approvals required for\nproposal execution."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Set active proposal limit"})," - Defines the maximum number of active\nproposals."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Set context variables"})," - Allows setting key-value pairs for context\nvariables."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"While the demo focuses on specific functionality, you can customize the\napplication to suit your needs. Instead of building a complete frontend, this\ndemo serves as a foundation that you can extend to create a fully-featured\nfrontend application tailored to your requirements."}),"\n",(0,r.jsx)(n.p,{children:"Navigate to frontend directory and install dependencies."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Terminal"',children:"cd demo-blockchain-integrations/app && pnpm install\n"})}),"\n",(0,r.jsx)(n.p,{children:"Since we have 3 nodes we will need to setup frontend for each of them. Open 3\nterminals side by side and run the following commands in each of them from /app\ndirectory:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Terminal 1 | Terminal 2 | Terminal 3"',children:"pnpm run dev\n"})}),"\n",(0,r.jsx)(n.p,{children:"After running the frontend you should see the following output in each of the\nterminals:"}),"\n",(0,r.jsx)("img",{src:"/icp-tutorial/Demo_blockchain_app_start.png",alt:"frontend-running"}),"\n",(0,r.jsx)(n.p,{children:"Open the applications in by clicking on the link in each of the terminals and\nyou will see form with input fields for node URL and application ID."}),"\n",(0,r.jsx)(n.p,{children:"To get application ID you can use following command from any of node terminals:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Node1 Terminal"',children:"application ls\n> <APPLICATION_ID>\n"})}),"\n",(0,r.jsx)(n.p,{children:"The node URL of the nodes are respectively:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"http://localhost:2427",children:"http://localhost:2427"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"http://localhost:2428",children:"http://localhost:2428"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"http://localhost:2429",children:"http://localhost:2429"})}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"After submitting the form you will be redirected to admin dashboard where you\nwill see the login page with wallet selector."}),"\n",(0,r.jsx)("lb",{}),"\n",(0,r.jsx)(n.p,{children:"Select a wallet you wish to login with and afterwards you will be prompted to\nselect the context and context identity you wish to use."}),"\n",(0,r.jsx)("lb",{}),"\n",(0,r.jsx)(n.p,{children:"After selecting both you will be logged in and automatically redirected to the\napplication."}),"\n",(0,r.jsx)(n.h3,{id:"change-approval-threshold-proposal",children:"Change Approval Threshold Proposal"}),"\n",(0,r.jsx)(n.p,{children:"First we are going to create an approval threshold change proposal so future\nproposals can be executed by only 1 node. As mentioned earlier each proposal by\ndefault needs 3 approvals to be executed."}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:'Click on "Create Proposal" button and select "Change number of approvals\nneeded" from dropdown.'}),"\n",(0,r.jsx)(n.li,{children:"In the input field set the number of approvals to 1 (this means that proposal\nwill be executed on creation)."}),"\n",(0,r.jsx)(n.li,{children:'Click on "Create Proposal" button to create the proposal.'}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"After proposal is created you will get the alert that proposal is created and it\nwill be shown in other frontend applications by selecting it in select field."}),"\n",(0,r.jsx)(n.p,{children:'After selecting proposal on other frontend applications (node2 and node3) you\ncan see that it is created and can be approved by clicking on "Approve Proposal"\nbutton.'}),"\n",(0,r.jsx)(n.h3,{id:"cross-contract-call-proposal",children:"Cross-Contract Call Proposal"}),"\n",(0,r.jsx)(n.p,{children:"At this point proposal approval threshold is 1, meaning proposal will be\nexecuted on creation. This means when we create cross-contract call proposal it\nwill instantly be executed."}),"\n",(0,r.jsxs)(n.p,{children:["We have created a ",(0,r.jsx)(n.code,{children:"<DEMO_EXTERNAL_CONTRACT_ID>"})," and deployed it on Stellar\ntestnet."]}),"\n",(0,r.jsx)(n.p,{children:"Its address is:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"CAJF5BPK4AT7UNVF4NDXMUXDKXCBFV56H2TNMUJIX6WUSNFP4UMH7W46\n"})}),"\n",(0,r.jsx)(n.p,{children:"It contains following methods:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"no_deposit"})," - This method does not require a deposit for execution, it sets\nsent arguments in its storage."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"deposit"})," - This method requires a deposit for execution, it first transfers\nthe funds to the contract from proxy contract and then sets sent arguments in\nits storage, if the transfer is completed successfully."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"get_calls"})," - This method returns all calls stored in the contract."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"clear_state"})," - This method clears the storage of the contract."]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["You can see the contract itself and its implementation\n",(0,r.jsx)(n.a,{href:"https://github.com/calimero-network/core/tree/master/contracts/stellar/context-proxy/mock_external",children:"here"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"When creating cross-contract call proposal we need to provide following values:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Contract ID"}),": ",(0,r.jsx)(n.code,{children:"{DEMO_EXTERNAL_CONTRACT_ID}"})," - Address of the external\ncontract"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Method Name"}),": ",(0,r.jsx)(n.code,{children:"deposit"})," - Name of the contract method that will be called"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Deposit"}),": 10000000 - Deposit for transfer (1 XLM)"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Arguments"}),": The following arguments correspond to the deposit method\nparameters:"]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Type"}),(0,r.jsx)(n.th,{children:"Value"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"address"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"{PROXY_CONTRACT_ID}"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"i128"}),(0,r.jsx)(n.td,{children:"10000000"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"string"}),(0,r.jsx)(n.td,{children:"testKEY"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"string"}),(0,r.jsx)(n.td,{children:"testVALUE"})]})]})]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)("img",{src:"/stellar-tutorial/stellar_proposal_deposit_call.png",alt:"create-ccc",style:{width:"50%"}}),"\n",(0,r.jsx)(n.p,{children:"Supported Soroban argument types:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"i32"})," - 32-bit signed integer"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"u32"})," - 32-bit unsigned integer"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"i64"})," - 64-bit signed integer"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"u64"})," - 64-bit unsigned integer"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"i128"})," - 128-bit signed integer"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"u128"})," - 128-bit unsigned integer"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"bool"})," - Boolean value"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"string"})," - Text string"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"address"})," - Contract or account address"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"symbol"})," - Symbol value"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"bytes"})," - Byte array"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["After we create proposal it will be executed, and the success of the execution\ncan be checked calling demo external 
1contract method ",(0,r.jsx)(n.strong,{children:"get_value"})," with Stellar\nCLI:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'stellar contract invoke \\\n  --id <DEMO_EXTERNAL_CONTRACT_ID> \\\n  --network testnet \\\n  --source <NAME_OF_ACCOUNT> \\\n  -- \\\n  get_value \\\n  --key "testKEY"\n'})}),"\n",(0,r.jsx)(n.p,{children:"To check if transfer was successful we can use Stellar Explorer by visiting:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.code,{children:"https://stellar.expert/explorer/testnet/contract/<DEMO_EXTERNAL_CONTRACT_ID>"})}),"\n",(0,r.jsx)(n.p,{children:"There you will see the current funds attached to the contract."}),"\n",(0,r.jsxs)(n.admonition,{type:"caution",children:[(0,r.jsx)(n.p,{children:"The implementation of cross-contract call with deposit is based on the following\nsteps:"}),(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"The contract detects that an attached deposit is present."}),"\n",(0,r.jsx)(n.li,{children:"It calls the ledger contract to enable the external contract (the contract\nbeing called) to withdraw funds."}),"\n",(0,r.jsx)(n.li,{children:"The external contract is called, and it must contain logic to withdraw the\nfunds that have been allocated for it in the ledger contract."}),"\n",(0,r.jsx)(n.li,{children:"After the cross-contract call is completed, the proxy contract sets the\nallowance back to 0 to ensure security."}),"\n"]})]}),"\n",(0,r.jsx)(n.h2,{id:"conclusion",children:"Conclusion"}),"\n",(0,r.jsx)(n.p,{children:"This tutorial has covered all the essential steps developers need to build an\napplication for Calimero and Stellar, from environment overview to deploying a\nfully functional smart contract. By following this guide, you should now have a\nsolid understanding of the development workflow and how to build your own\nStellar application for Calimero."}),"\n",(0,r.jsx)(n.p,{children:"Feel free to use our demo applications as a starting point to build and\ncustomize your own application. If you have any questions or need assistance,\ndon't hesitate to reach out to us on Socials. We're here to help!"})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},68820:(e,n,t)=>{t.d(n,{R:()=>l,x:()=>s});var i=t(30758);const r={},o=i.createContext(r);function l(e){const n=i.useContext(o);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:l(e.components),i.createElement(o.Provider,{value:n},e.children)}},83078:(e,n,t)=>{t.d(n,{A:()=>T});var i=t(30758),r=t(13526),o=t(9773),l=t(10470),s=t(25557),a=t(72147),c=t(60827),d=t(52056),h=t(37666);function u(e){return i.Children.toArray(e).filter(e=>"\n"!==e).map(e=>{if(!e||(0,i.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return e;throw new Error(`Docusaurus error: Bad <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)})?.filter(Boolean)??[]}function p(e){const{values:n,children:t}=e;return(0,i.useMemo)(()=>{const e=n??function(e){return u(e).map(({props:{value:e,label:n,attributes:t,default:i}})=>({value:e,label:n,attributes:t,default:i}))}(t);return function(e){const n=(0,d.XI)(e,(e,n)=>e.value===n.value);if(n.length>0)throw new Error(`Docusaurus error: Duplicate values "${n.map(e=>e.value).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e},[n,t])}function x({value:e,tabValues:n}){return n.some(n=>n.value===e)}function j({queryString:e=!1,groupId:n}){const t=(0,s.W6)(),r=function({queryString:e=!1,groupId:n}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!n)throw new Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return n??null}({queryString:e,groupId:n});return[(0,c.aZ)(r),(0,i.useCallback)(e=>{if(!r)return;const n=new URLSearchParams(t.location.search);n.set(r,e),t.replace({...t.location,search:n.toString()})},[r,t])]}function g(e){const{defaultValue:n,queryString:t=!1,groupId:r}=e,o=p(e),[l,s]=(0,i.useState)(()=>function({defaultValue:e,tabValues:n}){if(0===n.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!x({value:e,tabValues:n}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${n.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}const t=n.find(e=>e.default)??n[0];if(!t)throw new Error("Unexpected error: 0 tabValues");return t.value}({defaultValue:n,tabValues:o})),[c,d]=j({queryString:t,groupId:r}),[u,g]=function({groupId:e}){const n=function(e){return e?`docusaurus.tab.${e}`:null}(e),[t,r]=(0,h.Dv)(n);return[t,(0,i.useCallback)(e=>{n&&r.set(e)},[n,r])]}({groupId:r}),m=(()=>{const e=c??u;return x({value:e,tabValues:o})?e:null})();(0,a.A)(()=>{m&&s(m)},[m]);return{selectedValue:l,selectValue:(0,i.useCallback)(e=>{if(!x({value:e,tabValues:o}))throw new Error(`Can't select invalid tab value=${e}`);s(e),d(e),g(e)},[d,g,o]),tabValues:o}}var m=t(9329);const f={tabList:"tabList_xYaz",tabItem:"tabItem_kD6L"};var b=t(86070);function w({className:e,block:n,selectedValue:t,selectValue:i,tabValues:o}){const s=[],{blockElementScrollPositionUntilNextRender:a}=(0,l.a_)(),c=e=>{const n=e.currentTarget,r=s.indexOf(n),l=o[r].value;l!==t&&(a(n),i(l))},d=e=>{let n=null;switch(e.key){case"Enter":c(e);break;case"ArrowRight":{const t=s.indexOf(e.currentTarget)+1;n=s[t]??s[0];break}case"ArrowLeft":{const t=s.indexOf(e.currentTarget)-1;n=s[t]??s[s.length-1];break}}n?.focus()};return(0,b.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs",{"tabs--block":n},e),children:o.map(({value:e,label:n,attributes:i})=>(0,b.jsx)("li",{role:"tab",tabIndex:t===e?0:-1,"aria-selected":t===e,ref:e=>{s.push(e)},onKeyDown:d,onClick:c,...i,className:(0,r.A)("tabs__item",f.tabItem,i?.className,{"tabs__item--active":t===e}),children:n??e},e))})}function y({lazy:e,children:n,selectedValue:t}
1){const o=(Array.isArray(n)?n:[n]).filter(Boolean);if(e){const e=o.find(e=>e.props.value===t);return e?(0,i.cloneElement)(e,{className:(0,r.A)("margin-top--md",e.props.className)}):null}return(0,b.jsx)("div",{className:"margin-top--md",children:o.map((e,n)=>(0,i.cloneElement)(e,{key:n,hidden:e.props.value!==t}))})}function v(e){const n=g(e);return(0,b.jsxs)("div",{className:(0,r.A)(o.G.tabs.container,"tabs-container",f.tabList),children:[(0,b.jsx)(w,{...n,...e}),(0,b.jsx)(y,{...n,...e})]})}function T(e){const n=(0,m.A)();return(0,b.jsx)(v,{...e,children:u(e.children)},String(n))}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.