尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

如何用 fuels-rs 调用流动性池合约的存款与取款方法并接收铸造的资产

如何用 fuels-rs 调用流动性池合约的存款与取款方法并接收铸造的资产 如何用 fuels-rs 调用流动性池合约的存款与取款方法并接收铸造的资产【免费下载链接】fuels-rsFuel Network Rust SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-rs这篇文章以 fuels-rsFuel Network Rust SDK自带的liquidity_pool示例合约为目标演示一个完整的操作路径部署一个流动性池合约通过CallParameters向payable方法转发资产来调用deposit()依靠可变输出variable output接收合约铸造的流动性LP资产再用全部 LP 资产调用withdraw()取回基础资产并核对余额。示例代码来自仓库中的 cookbook 示例docs/src/cookbook/deposit-and-withdraw.md 对应的 examples/cookbook/src/lib.rs 中的liquidity测试代码中的合约路径相对于 fuels-rs 工作区根目录解析因此需要在仓库工作区内运行。示例合约的资产流先看合约本身e2e/sway/contracts/liquidity_pool/src/main.sw它是一个简化版流动性池contract; use std::{asset::{mint_to, transfer}, call_frames::msg_asset_id, context::msg_amount}; abi LiquidityPool { #[payable] fn deposit(recipient: Identity); #[payable] fn withdraw(recipient: Identity); } const BASE_TOKEN: AssetId AssetId::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c); impl LiquidityPool for Contract { #[payable] fn deposit(recipient: Identity) { assert(BASE_TOKEN msg_asset_id()); assert(0 msg_amount()); // Mint two times the amount. let amount_to_mint msg_amount() * 2; // Mint some LP token based upon the amount of the base token. mint_to(recipient, b256::zero(), amount_to_mint); } #[payable] fn withdraw(recipient: Identity) { assert(0 msg_amount()); // Amount to withdraw. let amount_to_transfer msg_amount() / 2; // Transfer base token to recipient. transfer(recipient, BASE_TOKEN, amount_to_transfer); } }合约约束和资产流由源码直接给出deposit()只接受BASE_TOKEN常量0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c且要求金额大于 0它会向调用地址铸造两倍于所转 BASE_TOKEN 数量的 LP 资产。withdraw()要求收到金额大于 0然后把收到数量的一半以BASE_TOKEN转回给recipient。LP 资产是合约的子资产其 AssetId 由合约 ID 派生示例代码里用contract_id.asset_id(SubAssetId::zeroed())得到。也就是说存入 1,000,000 个 BASE_TOKEN 会铸造 2,000,000 个 LP 资产用全部 2,000,000 个 LP 资产取款合约会转回 1,000,000 个 BASE_TOKEN。这个往返关系就是后面的验证依据。准备环境与构建示例合约仓库的 CI 检查脚本 ci_checks.sh 给出了工具链要求与安装命令需要 forc、forc-fmt、fuel-core 三个工具cargo install fuel-core-bin --git https://github.com/FuelLabs/fuel-core --tag v0.18.1 --locked cargo install forc --git https://github.com/FuelLabs/sway --tag v0.38.0 --locked cargo install forc-fmt --git https://github.com/FuelLabs/sway --tag v0.38.0 --locked安装完成后在仓库根目录用 release 模式构建全部 Sway 示例合约liquidity_pool是 e2e/Forc.toml 工作区的成员之一forc build --release --terse --path e2e构建成功后e2e/sway/contracts/liquidity_pool/out/release/目录下会产出后面要用的 ABI 文件liquidity_pool-abi.json和字节码文件liquidity_pool.bin。生成绑定并部署合约用abigen!宏从合约 ABI 生成类型安全的 Rust 绑定这是用 fuels-rs 交互任何合约的第一步参见 docs/src/abigen/the-abigen-macro.mdabigen!(Contract( name MyContract, abi e2e/sway/contracts/liquidity_pool/out/release/liquidity_pool-abi.json ));abi参数是合约的 JSON ABI 文件路径name是生成绑定的名字。注意路径相对于 fuels-rs 工作区根目录这段代码只能放在仓库工作区内编译。接下来准备一个持有自定义资产的钱包。钱包需要两类资产默认基础资产部署合约的 gas 费用需要它和合约的BASE_TOKEN用于后续存款。示例给每种资产配置了 1 枚、每枚 1,000,000 的币use fuels::prelude::*; use fuels::test_helpers::{AssetConfig, WalletsConfig}; let base_asset_id: AssetId 0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c.parse()?; let asset_ids [AssetId::zeroed(), base_asset_id]; let asset_configs asset_ids .map(|id| AssetConfig { id, num_coins: 1, coin_amount: 1_000_000, }) .into(); let wallet_config WalletsConfig::new_multiple_assets(1, asset_configs); let wallets launch_custom_provider_and_get_wallets(wallet_config, None, None).await?; let wallet wallets[0];launch_custom_provider_and_get_wallets会启动一个本地测试 provider 并按配置向钱包注币示例不需要外部节点。部署合约并创建方法绑定实例let contract_id Contract::load_from( ../../e2e/sway/contracts/liquidity_pool/out/release/liquidity_pool.bin, LoadConfiguration::default(), )? .deploy(wallet, TxPolicies::default()) .await? .contract_id; let contract_methods MyContract::new(contract_id, wallet.clone()).methods();注意两处路径写法不同abigen!用e2e/...Contract::load_from用../../e2e/...两者都是从仓库示例代码原样保留的相对路径离开仓库工作区都无法解析。部署成功后contract_id会被记录下来后面的 LP 资产 ID 和取款验证都依赖它。调用 deposit 并接收铸造的 LP 资产合约方法要收到资产需要通过CallParameters转发。调用参数包括 Amount、Asset ID 和 Gas forwarded 三项创建CallParameters实例后链到方法调用的call_params上参见 docs/src/calling-contracts/call-params.md。此外deposit()会通过mint_to向调用地址铸造资产底层会产生一笔转账输出交易必须带有相应数量的可变输出才能成功所以调用链上要追加with_variable_output_policy参见 docs/src/calling-contracts/variable-outputs.md。该策略有两种取值VariableOutputPolicy::Exactly(n)手动指定数量VariableOutputPolicy::EstimateMinimum让 SDK 估算最小值。本示例中每次调用只会产生一笔输出用Exactly(1)let deposit_amount 1_000_000; let call_params CallParameters::default() .with_amount(deposit_amount) .with_asset_id(base_asset_id); contract_methods .deposit(wallet.address().into()) .call_params(call_params)? .with_variable_output_policy(VariableOutputPolicy::Exactly(1)) .call() .await?;这里with_asset_id必须填BASE_TOKEN的 AssetId因为合约里deposit()断言BASE_TOKEN msg_asset_id()recipient传wallet.address()铸造出来的 LP 资产就落在钱包地址上。调用 withdraw 取回资产并核对余额取款时先用合约 ID 派生出 LP 资产 ID再查询钱包的 LP 余额把它作为withdraw()的转发金额。取款同样会产生一笔转账输出因此也要声明可变输出策略let lp_asset_id contract_id.asset_id(SubAssetId::zeroed()); let lp_token_balance wallet.get_asset_balance(lp_asset_id).await?; let call_params CallParameters::default() .with_amount(lp_token_balance.try_into().unwrap()) .with_asset_id(lp_asset_id); contract_methods .withdraw(wallet.address().into()) .call_params(call_params)? .with_variable_output_policy(VariableOutputPolicy::Exactly(1)) .call() .await?; let base_balance wallet.get_asset_balance(base_asset_id).await?; assert_eq!(base_balance, deposit_amount as u128);验证逻辑与合约的资产流对应钱包初始有 1,000,000 个 BASE_TOKEN全部存入后余额归 0合约铸造 2,000,000 个 LP 资产用全部 LP 资产取款合约转回 2,000,000 的一半即 1,000,000 个 BASE_TOKEN。因此assert_eq!(base_balance, deposit_amount as u128)成立即说明存款与取款两条路径都按预期走通铸造出的资产确实被钱包接收到了。运行与验证方式上述代码对应 examples/cookbook/src/lib.rs 中#[tokio::test] async fn liquidity()测试函数整个调用序列abigen、钱包、部署、deposit、withdraw、断言都在这一个测试里。在仓库根目录可以运行仓库 CI 使用的测试命令见 ci_checks.shcargo test --all-targets --all-features其中liquidity测试通过断言base_balance 1_000_000即为该操作路径的验证结果。也可以只跑这个包fuels-example-cookbook是 examples/cookbook/Cargo.toml 定义的包名。限制与容易踩的坑转发资产 ID 错了会触发合约断言deposit()断言BASE_TOKEN msg_asset_id()且0 msg_amount()CallParameters里的资产 ID 或金额不满足时交易失败。向非 payable 方法转发资产会直接报错call_params返回 Result就是为了确保你不会向未标注#[payable]的方法转发资产参见 docs/src/calling-contracts/call-params.md。本合约的deposit和withdraw都标注了#[payable]可以正常转发。可变输出数量必须正确合约执行中会向地址转账/铸造时交易必须带有足够数量的可变输出否则无法成功Sway 标准库的mint_to_address底层调用transfer_to_address同样需要按转移输出处理参见 docs/src/calling-contracts/variable-outputs.md。默认不转发资产如果不设置调用参数或使用CallParameters::default()转发的是交易 gas 限额而不是资产金额资产金额与 ID 需要显式通过with_amount和with_asset_id指定。示例代码路径绑定仓库结构abigen!的 ABI 路径与Contract::load_from的字节码路径都指向e2e/sway/contracts/liquidity_pool/out/release/需要先完成forc build --release --terse --path e2e并保持在 fuels-rs 工作区内运行替换为自己的合约时两处路径都要改。【免费下载链接】fuels-rsFuel Network Rust SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-rs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表