I have a function for the admin to burn tokens in a bucket.
pub fn burn_in_bucket(&mut self, mut bucket: Bucket) {
assert!(bucket.resource_address() == self.token_vault.resource_address(), "input token invalid");
let amount = bucket.amount();
bucket.take(amount).burn();
}
I know how to make a method call with badge protected access... And I have learned from Scrypto-example/nft/magic-card: https://github.com/radixdlt/scrypto-examples
let manifest = ManifestBuilder::new(&NetworkDefinition::simulator())
.create_proof_from_account_by_amount(user.compo_addr, badge_amount, badge_addr)
.withdraw_from_account_by_amount(user.compo_addr, amount, token_addr)
.take_from_worktop_by_amount(amount, token_addr, |builder, bucket_id| {
builder.call_method(component, func_name, args!(Bucket(bucket_id)))
})
.call_method(
user.compo_addr,
"deposit_batch",
args!(Expression::entire_worktop()),
)
.build();
let receipt = test_runner.execute_manifest_ignoring_fee(
manifest,
vec![NonFungibleAddress::from_public_key(&user.public_key)],
);
receipt.expect_commit_success();
The instructions:
Instructions:
├─ CALL_METHOD ComponentAddress("NormalComponent[0257...]") "lock_fee" Decimal("100");
├─ CALL_METHOD ComponentAddress("AccountComponent[03d8...]") "create_proof_by_amount" Decimal("3") ResourceAddress("NormalResource[00f1...]");
├─ CALL_METHOD ComponentAddress("AccountComponent[03d8...]") "withdraw_by_amount" Decimal("12") ResourceAddress("NormalResource[004a...]");
├─ TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("12") ResourceAddress("NormalResource[004a...]") Bucket("bucket1");
├─ CALL_METHOD ComponentAddress("NormalComponent[028f...]") "burn_in_bucket" Bucket("bucket1");
└─ CALL_METHOD ComponentAddress("AccountComponent[03d8...]") "deposit_batch" Expression("ENTIRE_WORKTOP");
Then I got this error:
COMMITTED FAILURE: KernelError(InvalidDropNodeVisibility { mode: Application, actor: Method(
Scrypto { package_address: NormalPackage[0165...], blueprint_name: "StableCoin", ident: "burn_in_bucket" },
ResolvedReceiver { derefed_from: Some((Global(Component(NormalComponent[028f...])), 36)), receiver: Component([143, 123, 111, 139, 198, 156, 205, 139, 18, 0, 234, 91, 33, 85, 171, 28, 89, 180, 217, 77, 183, 128, 169, 59, 111, 177, 96, 148, 55, 190, 141, 232, 15, 4, 0, 0]) }),
node_id: Bucket(1027) })
I suspect the "deposit_batch" is not correct, but don't know what is wrong...
The possible problem would be you didn't return the bucket after you burned it. The code would be like this:
pub fn burn_in_bucket(&mut self, mut bucket: Bucket) -> Bucket {
assert!(bucket.resource_address() == self.token_vault.resource_address(), "input token invalid");
let amount = bucket.amount();
bucket.take(amount).burn();
return bucket
}
Notice: I have rechecked the problem and actually it's not a good design to burn token like that. It would be a better design if you use a burn flag to protect token and burn the whole bucket at once, like this:
pub fn burn_in_bucket(&mut self, mut bucket: Bucket) {
assert!(bucket.resource_address() == self.token_vault.resource_address(), "input token invalid");
self.token_badge.authorize(|| {
bucket.burn()
});
}