Scrypto测试:如何将账户Bucket作为函数参数传递?
Scrypto中正确传递Bucket参数到合约方法的问题
问题背景
我在Scrypto蓝图中编写了一个供管理员将代币存入合约Token Vault的deposit函数:
pub fn deposit(&mut self, amount: Decimal, mut bucket: Bucket) { assert!(amount <= bucket.amount(), "not enough amount in your bucket"); self.token_vault.put(bucket.take(amount)) }
测试时,我已掌握生成新账户、调用带徽章保护方法的操作,参考Scrypto示例项目编写的测试代码如下:
let (public_key, private_key, account_component) = test_runner.new_allocated_account(); ... let manifest = ManifestBuilder::new(&NetworkDefinition::simulator()) .create_proof_from_account_by_amount(account_component, badge_amount, badge_addr) .withdraw_from_account_by_amount(account_component, amount, token_addr) .take_from_worktop(token_addr, |builder, bucket_id| { builder.call_method(component, func_name, args!(amount, Bucket(bucket_id))) }) .call_method( account_component, "deposit_batch", args!(Expression::entire_worktop()), ) .build(); let receipt = test_runner.execute_manifest_ignoring_fee( manifest, vec![NonFungibleAddress::from_public_key(&public_key)], ); println!("{} receipt: {:?}\n", func_name, receipt); receipt.expect_commit_success();
执行时出现如下错误:
COMMITTED FAILURE: KernelError(InvalidDropNodeVisibility { mode: Application, actor: Method(Scrypto { package_address: NormalPackage[011784f2e3c4b3dc9d14c850484fc4962f59ea68271e917d2f075c], blueprint_name: "StableCoin", ident: "deposit" }, ResolvedReceiver { derefed_from: Some((Global(Component(NormalComponent[02fd2e738e08b33e7d19001684043cd24fe35fda1ddc9429f7051e])), 36)), receiver: Component([252, 13, 40, 104, 140, 209, 211, 110, 141, 213, 197, 200, 172, 195, 190, 178, 219, 47, 174, 17, 52, 209, 75, 207, 106, 97, 105, 21, 213, 159, 52, 25, 15, 4, 0, 0]) }), node_id: Bucket(1027) })
请问如何正确将账户中的Bucket作为函数参数传递?
解决方法
这个错误的核心原因是传递给deposit方法的Bucket在执行后未被完全处理,Scrypto要求所有从工作区取出的Bucket必须被明确消费(存入Vault、销毁或返回给调用者),不能遗留未处理的Bucket节点。
修正步骤
调整蓝图的
deposit函数
原函数仅将指定数量代币存入Vault,但剩余的Bucket未返回给调用者,导致Bucket节点悬空。修改为返回剩余Bucket:pub fn deposit(&mut self, amount: Decimal, mut bucket: Bucket) -> Bucket { assert!(amount <= bucket.amount(), "not enough amount in your bucket"); self.token_vault.put(bucket.take(amount)); bucket // 返回剩余的Bucket }修正测试中的Manifest逻辑
调用deposit方法后,需要将返回的Bucket放回工作区,再存入账户,完成资源流转闭环:let manifest = ManifestBuilder::new(&NetworkDefinition::simulator()) .create_proof_from_account_by_amount(account_component, badge_amount, badge_addr) .withdraw_from_account_by_amount(account_component, amount, token_addr) .take_from_worktop(token_addr, |builder, bucket_id| { // 调用deposit方法并接收返回的剩余Bucket builder.call_method(component, func_name, args!(amount, Bucket(bucket_id))) .then(|builder, returned_bucket_id| { // 将返回的Bucket放回工作区 builder.return_to_worktop(Bucket(returned_bucket_id)) }) }) .call_method( account_component, "deposit_batch", args!(Expression::entire_worktop()), ) .build();
关键说明
- Scrypto的Manifest执行过程中,所有被取出的Bucket必须有明确的归宿:要么存入合约Vault,要么返回工作区最终回到账户,要么被销毁。
- 原代码中
deposit方法未返回剩余Bucket,导致Bucket节点处于未处理状态,触发InvalidDropNodeVisibility错误。 - 修正后,剩余Bucket被返回并放回工作区,最终通过
deposit_batch存入账户,完成了完整的资源流转流程。
内容的提问来源于stack exchange,提问作者Russo
相关产品推荐
相关产品推荐

