freeradiantbunny.org

freeradiantbunny.org/blog

flare development using rust

This guide is for developers who want to interact with Flare using Rust. In this guide, using Rust, you will learn how to:

Query a contract on Flare using alloy-rs, an async library for interacting with Ethereum-like chains.

Compile a Solidity contract using the CLI interface of solc, the Solidity compiler.

Deploy your compiled contract on Flare.

TIP

All examples in this guide are available at developer-hub/examples.

Getting started

Install the Solidity compiler by following the instructions in the Solidity documentation. The main commands are provided here:

MacOS via Homebrew

Ubuntu via PPAs

brew tap ethereum/ethereum

brew install solidity

Install the following dependencies:

cargo add alloy eyre tokio --features alloy/full,tokio/rt,tokio/rt-multi-thread,tokio/macros

Usage

You need to connect to testnet or mainnet via an RPC, any RPC listed on the Network Configurationpage will work. For this guide, you can use the Public RPC.

Flare Testnet Coston2

Flare Mainnet

src/bin/chain_id.rs

  use alloy::providers::{Provider, ProviderBuilder};
  use eyre::Result;
  #[tokio::main]
  async fn main() -> Result<()> {
    let provider =
    ProviderBuilder::new().on_http("https://coston2-api.flare.network/ext/C/rpc".parse()?);
    let chain_id = provider.get_chain_id().await?;
    println!("Chain ID: {}", chain_id); // Chain ID: 114
    Ok(())
    }
    


  cargo run --bin chain_id

Querying a contract

To query a contract, two pieces of information are required:

Contract address

Contract ABI (Application Binary Interface)

For this example, you can use the FlareContractRegistry contract which has the same address 0xaD67FE66660Fb8dFE9d6b1b4240d8650e30F6019across both testnet and mainnet.

Fetch ABI

To fetch a contract's ABI, copy the FlareContractRegistry ABI, and paste it into a file named FlareContractRegistry.json, located in the root of your project, i.e. same level as Cargo.toml.

Make query

You can now query the FlareContractRegistrycontract to get the addresses of other Flare contracts.

For example, querying it for the address of the WNatcontract:

Flare Testnet Coston2

Flare Mainnet

src/bin/make_query.rs


      use alloy::{providers::ProviderBuilder, sol};
      use eyre::Result;
      sol!(
      #[sol(rpc)]
      FlareContractRegistry,
      "FlareContractRegistry.json"
      );
      #[tokio::main]
      async fn main() -> Result<()> {
      let provider =
      ProviderBuilder::new().on_http("https://coston2-api.flare.network/ext/C/rpc".parse()?);
      let registry = FlareContractRegistry::new(
      "0xaD67FE66660Fb8dFE9d6b1b4240d8650e30F6019".parse()?,
      provider,
      );
      let FlareContractRegistry::getContractAddressByNameReturn { _0 } = registry
      .getContractAddressByName("WNat".to_string())
      .call()
      .await?;
      println!("WNat address: {_0}"); // WNat address: 0xC67DCE33D7A8efA5FfEB961899C73fe01bCe9273
      Ok(())
      }
  

      cargo run --bin make_query
  
Compiling a contract>

For this example, you can use the FtsoV2FeedConsumer contract to query the FTSOv2 feeds. Copy the FtsoV2FeedConsumer sample contract code given below, and save the .sol file in the same folder as your Cargo.toml.

FtsoV2FeedConsumer sample contract

Compile with solc

To compile the contract using the Solidity CLI compiler, create a file named config.json:


    config.json
      {
      "language": "Solidity",
      "sources": {
      "FtsoV2FeedConsumer.sol": {
      "urls": [
      "./FtsoV2FeedConsumer.sol"
      ]
      }
      },
      "settings": {
      "outputSelection": {
      "FtsoV2FeedConsumer.sol": {
      "FtsoV2FeedConsumer": [
      "abi",
      "metadata",
      "evm.bytecode",
      "evm.bytecode.sourceMap"
      ]
      }
      },
      "optimizer": {
      "enabled": true,
      "runs": 200
      },
      "evmVersion": "london"
      }
    }

  solc --standard-json config.json > FtsoV2FeedConsumer.json

  

This will generate a FtsoV2FeedConsumer.json file with the contract7#39;s ABI and bytecode.

Modify format

Things get a bit annoying here, as the alloy-rs solc!() macro expects a specific format for the JSON, which is not the same as the output from the Solidity compiler. To fix this, in the generated FtsoV2FeedConsumer.json, remove the top-level JSON fields, after you are done, the JSON should look like:

FtsoV2FeedConsumer.json


    {
    "abi": [
    ...
    ],
    "evm": {
    ...
    }
    "metadata": "..."
    }
Create account

Before deploying a contract, you need to have an account with some testnet or mainnet gas tokens. You can create a new Flare account using create_account.rs:

src/bin/create_account.rs


    use alloy::signers::local::LocalSigner;
    use eyre::Result;
    #[tokio::main]
    async fn main() -> Result<()> {
let signer = LocalSigner::random();
println!(
"Account: {}, Private key: {}",
signer.address(),
signer.as_nonzero_scalar()
);
Ok(())
  }

    cargo run --bin create_account

This will output a new private key and an account pair.

DANGER

Never share your private keys.

Never put your private keys in source code.

Never commit private keys to a Git repository.

You can save the account and private key into environment variables ACCOUNT and ACCOUNT_PRIVATE_KEY respectively.

NOTE

You can also import the raw hex private key to MetaMask and any other wallet - the private key can be shared between your Rust code and any number of wallets.

For testnet, you can get free testnet C2FLR on the Coston2 Faucet.

For mainnet you will need to fund the account with FLR. You can buy FLR with regular currency in places like centralized exchanges, crypto on-ramps, or swap other tokens for FLR on decentralized exchanges.

Deploying with alloy-rs

With the account ready, you can now deploy the contract. In a deploy_contract.rs file, you can define the following code to deploy the contract:

Flare Testnet Coston2

Flare Mainnet

src/bin/deploy_contract.rs


	       // THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.
	use alloy::{
	network::EthereumWallet, providers::ProviderBuilder, signers::local::PrivateKeySigner, sol,
	};
	use eyre::Result;
	sol!(
	#[sol(rpc)]
	FtsoV2FeedConsumer,
	"./FtsoV2FeedConsumer.json"
	);
	#[tokio::main]
	async fn main() -> Result<()> {
	  let private_key = std::env::var("ACCOUNT_PRIVATE_KEY")?;
	  let signer: PrivateKeySigner = private_key.parse().unwrap();
	  let wallet = EthereumWallet::from(signer.clone());
	  let provider = ProviderBuilder::new()
	  .with_recommended_fillers()
	  .wallet(wallet)
	  .on_http("https://coston2-api.flare.network/ext/C/rpc".parse()?);
	  let contract = FtsoV2FeedConsumer::deploy(&provider).await?;
	  println!("Deployed contract at address: {}", contract.address());
	  Ok(())
	  }

You can now run the deploy_contract.rs script to deploy the contract. The contract address will be printed once the deployment is successful. You can check the contract address on a Flare Blockchain explorer, linked on the Network Configuration page.