starknet智能合约编写、部署和调用-基于cairo2.3.0

  • Dec-15th
  • 更新于 2023-10-28 15:38
  • 阅读 1006

starknet智能合约编写、部署和调用

前言

OpenZeppelin、Hadhat 和 Foundry都在支持和更新starknet,这是积极信号,尽快学起来 starknet智能合约使用cairo语言编写,最近刚刚更新2.3.0 cairo编程语言类rust,建议搭配学,或者先学rust更好理解 rust编程语言会在未来几年快速流行(仅个人理解)

本教程环境

windows 10 mac和linux请自行配置 vscode 下载cairo1插件(可省略)

cairo 2.3.0 https://github.com/starkware-libs/cairo/tree/main https://book.cairo-lang.org/zh-cn/title-page.html scarb 2.3.0 https://github.com/software-mansion/scarb foundry-rs 0.9.0 https://github.com/foundry-rs/starknet-foundry https://foundry-rs.github.io/starknet-foundry/index.html OpenZeppelin v0.8.0-beta.0 https://github.com/OpenZeppelin/cairo-contracts/tree/main 目前oz稳定版本是v0.7.0,难用且不支持cairo2.3.0 v0.8.0-beta.0主要支持了Components components提供了一种乐高组合合约代码的方式 教程https://book.cairo-lang.org/zh-cn/ch99-01-05-00-components.html

区块链浏览器 https://testnet.starkscan.co/

配置环境

下载scarb 2.3 下载foundry-rs 0.9.0 bin加入环境变量,并验证

scarb --version
snforge --version

创建项目

snforge init hello_starknet

1698466995981.png

项目配置

Scarb.toml配置如下:

url替换为测试网络rpc

name = "hello_starknet"
version = "0.1.0"

# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html

[dependencies]
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.9.0" }
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.8.0-beta.0" }
starknet = "2.3.0"

[[target.starknet-contract]]
casm = true
HelloStarknet = { path = "src/lib" }
# foo = { path = "vendor/foo" }

[tool.sncast]
account = "test_user_0"
accounts-file = "accounts.json"
# url = "http://127.0.0.1:5050/rpc"
url = "https://starknet-goerli.g.alchemy.com/v2/66iTEsBmPgN-------"

初始化账户

创建两个账号

sncast account create -n test_user_0 

sncast account create -n test_user_1

根目录下会创建accounts.json文件,打开可以看到两个密钥信息(这是我的,你的肯定不一样)

test_user_0:0x3180b441f524c2de2515094fc85ffef278d9764f6ebbb87db68928c094177ff test_user_1:0xdc64f74f50383703de669eb9dd4b7eb7f6ecbc792f34232112193c6ed86d9a

starknet网络转测试eth到这两个账户地址上(否则不能部署账户合约)

eth到账后可部署两个账户合约到starknet网络 test_user_0和test_user_1为accounts.json中账户名

sncast account deploy --name test_user_0 --max-fee 8646000000000
sncast account deploy --name test_user_1 --max-fee 8646000000000

编写合约

拷贝如下代码到lib.cairo

trait IHelloStarknet<TContractState> {
    fn increase_balance(ref self: TContractState, amount: felt252);
    fn get_balance(self: @TContractState) -> felt252;
}

#[starknet::contract]
mod HelloStarknet {
    use starknet::ContractAddress;
    use openzeppelin::access::ownable::Ownable;

    component!(path: Ownable, storage: Ownable_owner, event: OwnershipTransferred);

    #[abi(embed_v0)]
    impl OwnableImpl = Ownable::OwnableImpl<ContractState>;

    impl OwnableInternalImpl = Ownable::InternalImpl<ContractState>;

    #[storage]
    struct Storage {
        balance: felt252, 
        #[substorage(v0)]
        Ownable_owner: Ownable::Storage
    }

    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        OwnershipTransferred: Ownable::Event
    }

    #[constructor]
    fn constructor(ref self: ContractState, owner: ContractAddress) {
        self.Ownable_owner.initializer(owner);
    }

    #[external(v0)]
    impl HelloStarknetImpl of super::IHelloStarknet<ContractState> {
        fn increase_balance(ref self: ContractState, amount: felt252) {
            assert(amount != 0, 'Amount cannot be 0');
            self.Ownable_owner.assert_only_owner();
            self.balance.write(self.balance.read() + amount);
        }

        fn get_balance(self: @ContractState) -> felt252 {
            self.balance.read()
        }
    }
}

简单解释: foundry示例代码基础上,配合OZ中Ownerable实现简单权限控制 increase_balance方法只有owner地址可调用 constructor构造中初始化owner

部署合约

declare合约,如正确会输出class-hash HelloStarknet为Scarb.toml中定义

sncast declare -c HelloStarknet

command: declare class_hash: 0x689fe8545ecf92cc86ffea0350c9093e0c7e4c215cda2ee156b0202ba344c40 transaction_hash: 0x3a67707e712033bdbd32a24f8167bd37eea2224e3fcde41b89142f64de87a6f

deploy合约 --constructor-calldata 为构造参数,配置test_user_0为合约owner

sncast deploy --class-hash 0x689fe8545ecf92cc86ffea0350c9093e0c7e4c215cda2ee156b0202ba344c40 --constructor-calldata 0x3180b441f524c2de2515094fc85ffef278d9764f6ebbb87db68928c094177ff

command: deploy contract_address: 0x454bf4e91e12423c7c279f44c0b1c6f569c2c2635584cb554a62a4c0b2a24e2 transaction_hash: 0x5575459f0905b4f7c0915cee21632a850d018051c392af51116f029ccedde50

稍后可以在区块链浏览器查看合约地址

调用合约

查询 call

查询合约owner

sncast call -a 0x454bf4e91e12423c7c279f44c0b1c6f569c2c2635584cb554a62a4c0b2a24e2 -f "owner"

command: call response: [0x3180b441f524c2de2515094fc85ffef278d9764f6ebbb87db68928c094177ff]

查询balance值,初始值应为0

sncast call -a 0x454bf4e91e12423c7c279f44c0b1c6f569c2c2635584cb554a62a4c0b2a24e2 -f "get_balance"

command: call response: [0x0]

交易 invoke

test_user_0调用increase_balance方法

sncast -a test_user_0 invoke -a 0x454bf4e91e12423c7c279f44c0b1c6f569c2c2635584cb554a62a4c0b2a24e2 -f "increase_balance" -c 2

command: invoke transaction_hash: 0x2f79663fcc0eb7792c09377087b0cdbc5f069ef911232b62f51e0b1007b9668

再次调用查询get_balance方法,值应为2

sncast call -a 0x454bf4e91e12423c7c279f44c0b1c6f569c2c2635584cb554a62a4c0b2a24e2 -f "get_balance" command: call response: [0x2]

test_user_1调用increase_balance方法

sncast -a test_user_1 invoke -a 0x454bf4e91e12423c7c279f44c0b1c6f569c2c2635584cb554a62a4c0b2a24e2 -f "increase_balance" -c 2

command: invoke error: Transaction reverted: Error in the called contract (0x00dc64f74f50383703de669eb9dd4b7eb7f6ecbc792f34232112193c6ed86d9a): Error at pc=0:81: Got an exception while executing a hint: Hint Error: Execution failed. Failure reason: "Caller is not the owner". Cairo traceback (most recent call last): Unknown location (pc=0:731) Unknown location (pc=0:677) Unknown location (pc=0:291) Unknown location (pc=0:314)

非owner,调用失败

到目前,本教程代码在remix starknet插件中不能编译和运行,期待remix插件升级

点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Dec-15th
Dec-15th
轻舟已过万重山