brc20-prog 0.14.0

BRC20 programmable module - Smart contract execution engine compatible with BRC20 standard
Documentation
use std::str::FromStr;

use alloy::primitives::{Address, Bytes, U256};
use alloy_sol_types::{sol, SolCall};
use revm::primitives::TxKind;
use rust_embed::Embed;

use crate::engine::TxInfo;
use crate::global::INDEXER_ADDRESS;

lazy_static::lazy_static! {
    pub static ref BRC20_CONTROLLER_PATH: String = "BRC20_Controller".to_string();
    pub static ref BRC20_CONTROLLER_ADDRESS: Address = "0xc54dd4581af2dbf18e4d90840226756e9d2b3cdb".parse().unwrap();
}

#[derive(Embed)]
#[folder = "src/brc20_controller/contract/output"]
struct ContractAssets;

sol! {
    function mint(bytes, address, uint256) returns (bool);
    function burn(bytes, address, uint256) returns (bool);
    function balanceOf(bytes, address) returns (uint256);
}

pub fn load_brc20_mint_tx(ticker: Bytes, address: Address, amount: U256) -> TxInfo {
    TxInfo::from_inscription(
        *INDEXER_ADDRESS,
        TxKind::Call(*BRC20_CONTROLLER_ADDRESS),
        mintCall::new((ticker, address, amount)).abi_encode().into(),
    )
}

pub fn load_brc20_burn_tx(ticker: Bytes, address: Address, amount: U256) -> TxInfo {
    TxInfo::from_inscription(
        *INDEXER_ADDRESS,
        TxKind::Call(*BRC20_CONTROLLER_ADDRESS),
        burnCall::new((ticker, address, amount)).abi_encode().into(),
    )
}

pub fn load_brc20_balance_tx(ticker: Bytes, address: Address) -> TxInfo {
    TxInfo::from_inscription(
        *INDEXER_ADDRESS,
        TxKind::Call(*BRC20_CONTROLLER_ADDRESS),
        balanceOfCall::new((ticker, address)).abi_encode().into(),
    )
}

pub fn decode_brc20_balance_result(data: Option<&Bytes>) -> U256 {
    let Some(data) = data else {
        return U256::ZERO;
    };
    let returns = balanceOfCall::abi_decode_returns(data);
    return returns.ok().unwrap_or(U256::ZERO);
}

pub fn load_brc20_deploy_tx() -> TxInfo {
    let file_content = ContractAssets::get(&format!("{}_deploy.bytecode", *BRC20_CONTROLLER_PATH))
        .expect("Failed to load contract binary");
    let data = String::from_utf8(file_content.data.to_vec())
        .expect("Failed to convert binary data to string");

    TxInfo::from_inscription(
        *INDEXER_ADDRESS,
        TxKind::Create,
        Bytes::from_str(&data).expect("Failed to convert string to bytes"),
    )
}

pub fn verify_brc20_contract_address(address: &str) -> Result<(), String> {
    let address: Address = address.parse().unwrap_or_default();
    if address == *BRC20_CONTROLLER_ADDRESS {
        return Ok(());
    }
    Err("Invalid BRC20_Controller contract address".to_string())
}