{"id":18437832,"url":"https://github.com/zilliqa/zilliqa-rs","last_synced_at":"2025-04-07T20:34:34.230Z","repository":{"id":210226246,"uuid":"725648852","full_name":"Zilliqa/zilliqa-rs","owner":"Zilliqa","description":"Zilliqa rust SDK","archived":false,"fork":false,"pushed_at":"2024-06-18T05:16:33.000Z","size":243,"stargazers_count":5,"open_issues_count":6,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-07T13:36:40.577Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Zilliqa.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-30T15:30:13.000Z","updated_at":"2024-06-18T05:16:36.000Z","dependencies_parsed_at":"2023-12-22T21:28:32.252Z","dependency_job_id":"9996cd2f-2c83-4d4f-b01b-e75b0207e60e","html_url":"https://github.com/Zilliqa/zilliqa-rs","commit_stats":null,"previous_names":["zilliqa/zilliqa-rs"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zilliqa%2Fzilliqa-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zilliqa%2Fzilliqa-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zilliqa%2Fzilliqa-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zilliqa%2Fzilliqa-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Zilliqa","download_url":"https://codeload.github.com/Zilliqa/zilliqa-rs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223291499,"owners_count":17120965,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T06:16:22.735Z","updated_at":"2024-11-06T06:16:23.326Z","avatar_url":"https://github.com/Zilliqa.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Getting started\n## Create a new Rust app\nThe very first step is to create a binary rust project.\n\n```bash\ncargo new zilliqa-rs-demo\n```\n\nthen we need to add zilliqa-rs and tokio to the project's dependencies:\n\n```bash\ncargo add zilliqa-rs tokio\n```\n\n## Call a simple JSON-RPC API\n### Run the isolated-server using docker\nHere we run an isolated server using docker to use it as the target network, but you can use any zilliqa network you want.\n```bash\ndocker run -d -p 5555:5555 --name iso-server zilliqa-isolated-server:latest\n```\n\n### Call GetBalance\nFirst, we need to create a provider. In the first line of the main, we create an HTTP provider. We use the URL of the isolated server we ran in the previous step. The chain ID of this network is 222. \nThen we can call the `get_balance` function of the provider, passing the address of the account we want its balance.\n\n```rust\nuse std::error::Error;\n\nuse zilliqa_rs::middlewares::Middleware;\nuse zilliqa_rs::providers::{Http, Provider};\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn Error\u003e\u003e {\n    let provider = Provider::\u003cHttp\u003e::try_from(\"http://127.0.0.1:5555\")?.with_chain_id(222);\n    let balance = provider\n        .get_balance(\"0x381f4008505e940ad7681ec3468a719060caf796\")\n        .await;\n\n    println!(\"{balance:?}\");\n    Ok(())\n}\n```\n\n## Sending transactions\n### Provider with a signer\nTo start sending transactions, we need to change the provider. The provider we had so far, didn't have a signer. That was because we didn't want to send transactions. But now we want, so we need to provide a signer for it:\n\n```rust,ignore\n    let wallet = \"0xe53d1c3edaffc7a7bab5418eb836cf75819a82872b4a1a0f1c7fcf5c3e020b89\"\n        .parse::\u003cLocalWallet\u003e()?;\n\n    let provider = Provider::\u003cHttp\u003e::try_from(\"http://127.0.0.1:5555\")?\n        .with_chain_id(222)\n        .with_signer(wallet.clone());\n```\nHere, we create a new wallet from a private key and a provider with that signer. This provider now can be used to send transactions.\n\nLet's transfer some ZIL to a random address. First, we create a random wallet:\n```rust,ignore\n    let receiver = LocalWallet::create_random()?;\n```\nThen we need to compose a transaction. `TransactionBuilder` is used to build a transaction:\n```rust,ignore\n    let tx = TransactionBuilder::default()\n        .to_address(receiver.address.clone())\n        .amount(parse_zil(\"2.0\")?)\n        .gas_price(2000000000u128)\n        .gas_limit(50u64)\n        .build();\n```\nHere we are going to transfer 2.0 ZIL to the receiver. Now we need to send the transaction:\n```rust,ignore\n    provider\n        .send_transaction_without_confirm::\u003cCreateTransactionResponse\u003e(tx)\n        .await?;\n```\nNow, let's check the balance:\n```rust,ignore\n    let balance = provider.get_balance(\u0026receiver.address).await;\n    println!(\"{balance:?}\");\n```\n```bash\ncargo run\n\nOk(BalanceResponse { nonce: 138, balance: 899999994124734000000000 })\nOk(BalanceResponse { nonce: 0, balance: 2000000000000 })\n```\n### Using pay function\nTransactionBuilder has an auxiliary function named `pay` to simplify payment transaction creation:\n```rust,ignore\n    let tx = TransactionBuilder::default().pay(amount, receiver.address.clone()).build();\n```\n\n## Working with contracts\n### Technical notes\nOne of the coolest features of zilliqa-rs is generating rust code for your scilla contracts during build time. It means if your contract has a transition like `transfer`, you can call it the same as a normal rust function. If it has a parameter of an address, you must pass an address to this function. And this means all of the beauties of type-checking of rust come to working with scilla contracts.\n\n### Generating rust code from scilla contracts\nWe want to deploy a simple contract named `HelloWorld` and call its `setHello` transition. First, we need to create a folder next to `src`. Let's call it `contracts`. Then we move [HelloWorld.scilla](./tests/contracts/HelloWorld.scilla) to this folder. To let zilliqa-rs scilla-to-rust code generation know about the contracts path, we need to export `CONTRACTS_PATH` environment variable. The simplest way is to create `.cargo/config.toml` file and change it like:\n\n```toml\n[env]\nCONTRACTS_PATH = {value = \"contracts\", relative = true}\n```\nsetting `relative` to `true` is crucial. Otherwise, your scilla contracts won't be transpiled to rust. Now, if you build the project using `cargo build`, your HelloWorld.scilla gets converted to rust under the hood.\n\nThe generated code is something like this:\n\n```rust,ignore\nimpl\u003cT: Middleware\u003e HelloWorld\u003cT\u003e {\n    pub async fn deploy(client: Arc\u003cT\u003e , owner: ZilAddress) -\u003e Result\u003cSelf, Error\u003e {\n    }\n\n    pub fn address(\u0026self) -\u003e \u0026ZilAddress  {\n    }\n    \n    pub fn set_hello(\u0026self , msg: String) -\u003e RefMut\u003c'_, transition_call::TransitionCall\u003cT\u003e\u003e {\n    }\n\n    pub fn get_hello(\u0026self ) -\u003e RefMut\u003c'_, transition_call::TransitionCall\u003cT\u003e\u003e {\n    }\n\n    pub async fn welcome_msg(\u0026self) -\u003e Result\u003cString, Error\u003e {\n    }\n\n    pub async fn owner(\u0026self) -\u003e Result\u003cZilAddress, Error\u003e {\n    }\n}\n```\n* The `deploy` deploys the contract to the network. Because HelloWorld.scilla contract accepts an address, `owner`, as a deployment parameter, the `deploy` function needs that too. It means you can't deploy it without providing a valid address.\n* The `address` function returns the address of the deployed contract.\n* `set_hello` corresponds to `setHello` transition in the contract. Again, because the transition accepts a string parameter, the `set_hello` function does too. \n* `get_hello` corresponds to the `getHello` transition.\n* The contract has a field named, `welcome_msg`, to get the value of this field, the `welcome_msg` function should be called.\n* The contract has an immutable state named, `owner` and we passed the value during deployment. To get the value of the owner, we need to call `owner`\n\n### Contract Deployment\nNow it's time to deploy the contract:\n```rust,ignore\n    let contract = HelloWorld::deploy(provider.into(), wallet.address).await?;\n    println!(\"Contract address: {:?}\", contract.address());\n```\nThe first parameter to `deploy` is the provider. The rest depends on the contract and how many immutable states it has. Here in HelloWorld.scilla we only have `owner`, so we just pass an address. It's type-safe, it means you can't pass an integer or even a raw string to `deploy` function as `owner`.\n\nRun the code: \n\n```bash\ncargo run\n\nOk(BalanceResponse { nonce: 138, balance: 899999994124734000000000 })\nContract address: ZilAddress(\"0xC50C93831F6eAB4e4F011076dca6e887288cc872\")\n```\n\nInstead of `deploy`, you can use `deploy_compressed` if you like to deploy a compressed version of the contract.\n\n### Getting contract states\nOur contract has `owner`, an immutable state, and `welcome_msg`, a mutable one. We can get these states by calling the corresponding functions:\n```rust,ignore\n    println!(\"Contract owner: {:?}\", contract.owner().await?);\n    println!(\"Welcome msg: {}\", contract.welcome_msg().await?);\n```\n\n### Calling a transition\nOur contract has a `setHello` transition. Calling this transition is not harder than calling a rust function:\n\n```rust,ignore\n    contract.set_hello(\"Salaam\".to_string()).call().await?;\n```\nPay attention, here we need to call `call` too. That's because everything you do before `call` is like configuring the transition call. For example, you can set the amount of ZIL you want to pass to a transition before calling `call` function:\n```rust,ignore\n    contract.transfer(receiver).amount(parse_zil(\"0.1\")).call().await?;\n```\n\nOK, now if you get and print `welcome_msg` it should have the new value:\n```rust,ignore\n    println!(\"Welcome msg: {}\", contract.welcome_msg().await?);\n```\nThe final main:\n```rust\nuse std::error::Error;\n\nuse zilliqa_rs::{\n    contract::HelloWorld,\n    core::CreateTransactionResponse,\n    middlewares::Middleware,\n    providers::{Http, Provider},\n    signers::LocalWallet,\n    transaction::TransactionBuilder,\n    core::parse_zil,\n};\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn Error\u003e\u003e {\n    // Create the signer.\n    let wallet = \"0xe53d1c3edaffc7a7bab5418eb836cf75819a82872b4a1a0f1c7fcf5c3e020b89\"\n        .parse::\u003cLocalWallet\u003e()?;\n\n    // Create the provider with a signer.\n    let provider = Provider::\u003cHttp\u003e::try_from(\"http://127.0.0.1:5555\")?\n        .with_chain_id(222)\n        .with_signer(wallet.clone());\n\n    // Call a JSON-RPC endpoint.\n    let balance = provider\n        .get_balance(\"0x381f4008505e940ad7681ec3468a719060caf796\")\n        .await;\n\n    println!(\"{balance:?}\");\n\n    // Send a transaction\n    let receiver = LocalWallet::create_random()?;\n    let tx = TransactionBuilder::default()\n        .to_address(receiver.address.clone())\n        .amount(parse_zil(\"2.0\")?)\n        .gas_price(2000000000u128)\n        .gas_limit(50u64)\n        .build();\n\n    provider\n        .send_transaction_without_confirm::\u003cCreateTransactionResponse\u003e(tx)\n        .await?;\n\n    let balance = provider.get_balance(\u0026receiver.address).await;\n    println!(\"{balance:?}\");\n\n    // Deploy a contract\n    let contract = HelloWorld::deploy(provider.into(), wallet.address).await?;\n    println!(\"Contract address: {:?}\", contract.address());\n\n    println!(\"Contract owner: {:?}\", contract.owner().await?);\n    println!(\"Welcome msg: {}\", contract.welcome_msg().await?);\n\n    contract.set_hello(\"Salaam\".to_string()).call().await?;\n    println!(\"Welcome msg: {}\", contract.welcome_msg().await?);\n    Ok(())\n}\n```\n\nLet's run the code:\n\n```bash\ncargo run\n\nOk(BalanceResponse { nonce: 138, balance: 899999994124734000000000 })\nContract address: ZilAddress(\"0xB84De4A67E1640D9259c502AAb6751678B593185\")\nContract owner: ZilAddress(\"0xd90f2e538CE0Df89c8273CAd3b63ec44a3c4ed82\")\nWelcome msg: Hello world!\nWelcome msg: Salaam\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzilliqa%2Fzilliqa-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzilliqa%2Fzilliqa-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzilliqa%2Fzilliqa-rs/lists"}