diff --git a/Cargo.toml b/Cargo.toml
index 3eb8697f..112896e6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -97,6 +97,7 @@ sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39", default-features = false }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39", default-features = false }
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39", default-features = false }
+sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39", default-features = false }
# (native)
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" }
diff --git a/chain-extensions/pallet-assets/Cargo.toml b/chain-extensions/pallet-assets/Cargo.toml
index 94319eef..6456d8f6 100644
--- a/chain-extensions/pallet-assets/Cargo.toml
+++ b/chain-extensions/pallet-assets/Cargo.toml
@@ -23,6 +23,13 @@ sp-core = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
+[dev-dependencies]
+env_logger = "0.9"
+pallet-balances = { workspace = true }
+pallet-timestamp = { workspace = true }
+sp-io = { workspace = true }
+sp-keystore = { workspace = true }
+
[features]
default = ["std"]
std = [
@@ -38,4 +45,5 @@ std = [
"sp-runtime/std",
"pallet-assets/std",
"assets-chain-extension-types/std",
+ "pallet-balances/std",
]
diff --git a/chain-extensions/pallet-assets/src/lib.rs b/chain-extensions/pallet-assets/src/lib.rs
index f4ff4695..7f15a272 100644
--- a/chain-extensions/pallet-assets/src/lib.rs
+++ b/chain-extensions/pallet-assets/src/lib.rs
@@ -18,6 +18,10 @@
#![cfg_attr(not(feature = "std"), no_std)]
+#[cfg(test)]
+mod mock;
+#[cfg(test)]
+pub mod tests;
pub mod weights;
use assets_chain_extension_types::{select_origin, Origin, Outcome};
diff --git a/chain-extensions/pallet-assets/src/mock.rs b/chain-extensions/pallet-assets/src/mock.rs
new file mode 100644
index 00000000..2bdf6ac1
--- /dev/null
+++ b/chain-extensions/pallet-assets/src/mock.rs
@@ -0,0 +1,241 @@
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Astar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Astar. If not, see .
+
+use crate::weights::SubstrateWeight;
+use crate::{weights, AssetsExtension};
+use frame_support::traits::{AsEnsureOriginWithArg, ConstU128, Currency, Randomness};
+use frame_support::{
+ parameter_types, sp_io,
+ traits::{ConstU32, ConstU64, Nothing},
+ weights::Weight,
+};
+use pallet_assets::AssetsCallback;
+use pallet_contracts::chain_extension::RegisteredChainExtension;
+use pallet_contracts::{Config, DefaultAddressGenerator, Frame};
+use parity_scale_codec::Encode;
+use sp_core::crypto::AccountId32;
+use sp_io::storage;
+use sp_keystore::{testing::KeyStore, KeystoreExt};
+use sp_runtime::generic;
+use sp_runtime::testing::H256;
+use sp_runtime::traits::{BlakeTwo256, Convert, IdentityLookup, Zero};
+use std::sync::Arc;
+
+pub type BlockNumber = u32;
+pub type Balance = u128;
+pub type AssetId = u128;
+
+type BalanceOf =
+ <::Currency as Currency<::AccountId>>::Balance;
+
+parameter_types! {
+ pub const BlockHashCount: BlockNumber = 250;
+ pub BlockWeights: frame_system::limits::BlockWeights =
+ frame_system::limits::BlockWeights::simple_max(
+ Weight::from_ref_time(2_000_000_000_000).set_proof_size(u64::MAX),
+ );
+}
+impl frame_system::Config for Test {
+ type BaseCallFilter = frame_support::traits::Everything;
+ type BlockWeights = BlockWeights;
+ type BlockLength = ();
+ type DbWeight = ();
+ type RuntimeOrigin = RuntimeOrigin;
+ type Index = u32;
+ type BlockNumber = BlockNumber;
+ type Hash = H256;
+ type RuntimeCall = RuntimeCall;
+ type Hashing = BlakeTwo256;
+ type AccountId = AccountId32;
+ type Lookup = IdentityLookup;
+ type Header = generic::Header;
+ type RuntimeEvent = RuntimeEvent;
+ type BlockHashCount = BlockHashCount;
+ type Version = ();
+ type PalletInfo = PalletInfo;
+ type AccountData = pallet_balances::AccountData;
+ type OnNewAccount = ();
+ type OnKilledAccount = ();
+ type SystemWeightInfo = ();
+ type SS58Prefix = ();
+ type OnSetCode = ();
+ type MaxConsumers = frame_support::traits::ConstU32<16>;
+}
+
+parameter_types! {
+ pub const DeletionWeightLimit: Weight = Weight::from_ref_time(500_000_000_000);
+ pub static UnstableInterface: bool = true;
+ pub Schedule: pallet_contracts::Schedule = Default::default();
+ pub static DepositPerByte: BalanceOf = 1;
+ pub const DepositPerItem: BalanceOf = 1;
+}
+
+pub struct DummyDeprecatedRandomness;
+impl Randomness for DummyDeprecatedRandomness {
+ fn random(_: &[u8]) -> (H256, BlockNumber) {
+ (Default::default(), Zero::zero())
+ }
+}
+
+impl pallet_contracts::Config for Test {
+ type Time = Timestamp;
+ type Randomness = DummyDeprecatedRandomness;
+ type Currency = Balances;
+ type RuntimeEvent = RuntimeEvent;
+ type RuntimeCall = RuntimeCall;
+ type CallFilter = Nothing;
+ type CallStack = [Frame; 5];
+ type WeightPrice = Self;
+ type WeightInfo = ();
+ type ChainExtension = AssetsExtension>;
+ type DeletionQueueDepth = ConstU32<128>;
+ type DeletionWeightLimit = DeletionWeightLimit;
+ type Schedule = Schedule;
+ type DepositPerByte = DepositPerByte;
+ type DepositPerItem = DepositPerItem;
+ type AddressGenerator = DefaultAddressGenerator;
+ type MaxCodeLen = ConstU32<{ 123 * 1024 }>;
+ type MaxStorageKeyLen = ConstU32<128>;
+ type UnsafeUnstableInterface = UnstableInterface;
+ type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>;
+}
+
+impl RegisteredChainExtension for AssetsExtension {
+ const ID: u16 = 02;
+}
+
+parameter_types! {
+ pub static ExistentialDeposit: u64 = 1;
+}
+
+impl pallet_balances::Config for Test {
+ type MaxLocks = ();
+ type MaxReserves = ();
+ type ReserveIdentifier = [u8; 8];
+ type Balance = Balance;
+ type RuntimeEvent = RuntimeEvent;
+ type DustRemoval = ();
+ type ExistentialDeposit = ExistentialDeposit;
+ type AccountStore = System;
+ type WeightInfo = ();
+}
+
+impl pallet_timestamp::Config for Test {
+ type Moment = u64;
+ type OnTimestampSet = ();
+ type MinimumPeriod = ConstU64<1>;
+ type WeightInfo = ();
+}
+
+pub struct AssetsCallbackHandle;
+impl AssetsCallback for AssetsCallbackHandle {
+ fn created(_id: &AssetId, _owner: &AccountId32) {
+ storage::set(b"asset_created", &().encode());
+ }
+
+ fn destroyed(_id: &AssetId) {
+ storage::set(b"asset_destroyed", &().encode());
+ }
+}
+
+impl pallet_assets::Config for Test {
+ type RuntimeEvent = RuntimeEvent;
+ type Balance = Balance;
+ type AssetId = AssetId;
+ type AssetIdParameter = u128;
+ type Currency = Balances;
+ type CreateOrigin = AsEnsureOriginWithArg>;
+ type ForceOrigin = frame_system::EnsureRoot;
+ type AssetDeposit = ConstU128<1>;
+ type AssetAccountDeposit = ConstU128<10>;
+ type MetadataDepositBase = ConstU128<1>;
+ type MetadataDepositPerByte = ConstU128<1>;
+ type ApprovalDeposit = ConstU128<1>;
+ type StringLimit = ConstU32<50>;
+ type Freezer = ();
+ type WeightInfo = ();
+ type CallbackHandle = AssetsCallbackHandle;
+ type Extra = ();
+ type RemoveItemsLimit = ConstU32<5>;
+}
+
+type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic;
+type Block = frame_system::mocking::MockBlock;
+
+frame_support::construct_runtime!(
+ pub enum Test where
+ Block = Block,
+ NodeBlock = Block,
+ UncheckedExtrinsic = UncheckedExtrinsic,
+ {
+ System: frame_system::{Pallet, Call, Config, Storage, Event},
+ Balances: pallet_balances::{Pallet, Call, Storage, Config, Event},
+ Assets: pallet_assets::{Pallet, Call, Storage, Event},
+ Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
+ Contracts: pallet_contracts::{Pallet, Call, Storage, Event},
+ }
+);
+
+pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]);
+pub const BOB: AccountId32 = AccountId32::new([2u8; 32]);
+pub const GAS_LIMIT: Weight = Weight::from_ref_time(100_000_000_000).set_proof_size(700000u64);
+pub const ONE: u128 = 1_000_000_000_000_000_000;
+
+impl Convert> for Test {
+ fn convert(w: Weight) -> BalanceOf {
+ w.ref_time().into()
+ }
+}
+
+pub struct ExtBuilder {
+ existential_deposit: u64,
+}
+
+impl Default for ExtBuilder {
+ fn default() -> Self {
+ Self {
+ existential_deposit: ExistentialDeposit::get(),
+ }
+ }
+}
+
+impl ExtBuilder {
+ pub fn existential_deposit(mut self, existential_deposit: u64) -> Self {
+ self.existential_deposit = existential_deposit;
+ self
+ }
+ pub fn set_associated_consts(&self) {
+ EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit);
+ }
+ pub fn build(self) -> sp_io::TestExternalities {
+ use env_logger::{Builder, Env};
+ let env = Env::new().default_filter_or("runtime=debug");
+ let _ = Builder::from_env(env).is_test(true).try_init();
+ self.set_associated_consts();
+ let mut t = frame_system::GenesisConfig::default()
+ .build_storage::()
+ .unwrap();
+ pallet_balances::GenesisConfig:: { balances: vec![] }
+ .assimilate_storage(&mut t)
+ .unwrap();
+ let mut ext = sp_io::TestExternalities::new(t);
+ ext.register_extension(KeystoreExt(Arc::new(KeyStore::new())));
+ ext.execute_with(|| System::set_block_number(1));
+ ext
+ }
+}
diff --git a/chain-extensions/pallet-assets/src/tests.rs b/chain-extensions/pallet-assets/src/tests.rs
new file mode 100644
index 00000000..255e64e2
--- /dev/null
+++ b/chain-extensions/pallet-assets/src/tests.rs
@@ -0,0 +1,499 @@
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Astar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Astar. If not, see .
+
+use crate::mock::*;
+use frame_support::assert_ok;
+use frame_support::traits::fungibles::roles::Inspect;
+use frame_support::traits::Currency;
+use pallet_contracts::Determinism;
+use pallet_contracts_primitives::{Code, ExecReturnValue, ReturnFlags};
+use parity_scale_codec::Encode;
+use sp_core::crypto::AccountId32;
+use sp_runtime::DispatchError;
+use std::fs;
+
+// Those tests use the contract scheduler_example avilable here:
+// https://github.com/AstarNetwork/chain-extension-contracts/blob/main/examples/assets
+// It maps chain extension functions to ink! callable messages
+// ex:
+// #[ink(message)]
+// pub fn burn(&mut self, asset_id: u128, who: AccountId, amount: Balance) -> Result<(), AssetsError> {
+// AssetsExtension::burn(Origin::Caller, asset_id, who, amount)?;
+// Ok(())
+// }
+
+#[test]
+fn create_works() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Act - Create asset
+ assert_ok!(create(addr.clone(), 1, 1));
+
+ // Assert - Contract is the owner
+ assert_eq!(Assets::owner(1), Some(addr.into()));
+ });
+}
+
+#[test]
+fn mint_works() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Arrange - create asset
+ assert_ok!(create(addr.clone(), 1, 1));
+
+ // Act - Mint 1000 assets to Alice
+ assert_ok!(mint(addr.clone(), 1, ALICE, 1000));
+
+ // Assert - Alice balance is 1000
+ assert_eq!(Assets::balance(1, ALICE), 1000);
+ });
+}
+
+#[test]
+fn burn_works() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Arrange - Create & mint 1000 to Alice
+ assert_ok!(create(addr.clone(), 1, 1));
+ assert_ok!(mint(addr.clone(), 1, ALICE, 1000));
+
+ // Act - Burn 1000 of Alice tokens
+ assert_ok!(burn(addr.clone(), 1, ALICE, 1000));
+
+ // Assert - Balance of Alice is then 0
+ assert_eq!(Assets::balance(1, ALICE), 0);
+ });
+}
+
+#[test]
+fn transfer_works() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Assert - Create & mint 1000 to contract
+ assert_ok!(create(addr.clone(), 1, 1));
+ assert_ok!(mint(addr.clone(), 1, addr.clone(), 1000));
+
+ // Act - Tranfer 1000 from contract to Alice
+ assert_ok!(transfer(addr.clone(), 1, ALICE, 1000));
+
+ // Assert - Alice balance is 1000 and contract is zero
+ assert_eq!(Assets::balance(1, ALICE), 1000);
+ assert_eq!(Assets::balance(1, addr.clone()), 0);
+ });
+}
+
+#[test]
+fn balance_of_and_total_supply() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Arrange - create & mint 1000 to Alice
+ assert_ok!(create(addr.clone(), 1, 1));
+ assert_ok!(mint(addr.clone(), 1, ALICE, 1000));
+
+ // Assert - Balance and total supply is 1000
+ assert_eq!(
+ balance_of(addr.clone(), 1, ALICE).data[1..],
+ 1000u128.encode()
+ );
+ assert_eq!(total_supply(addr.clone(), 1).data[1..], 1000u128.encode());
+ });
+}
+
+#[test]
+fn approve_transfer_and_check_allowance() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Arrange - Create and mint 1000 to contract
+ assert_ok!(create(addr.clone(), 1, 1));
+ assert_ok!(mint(addr.clone(), 1, addr.clone(), 1000));
+
+ // Act - approve transfer To BOB for 100
+ assert_ok!(approve_transfer(addr.clone(), 1, BOB, 100));
+
+ // Assert - Bob has 100 allowance
+ assert_eq!(
+ allowance(addr.clone(), 1, addr.clone(), BOB).data[1..],
+ 100u128.encode()
+ );
+ });
+}
+
+#[test]
+fn approve_transfer_and_transfer_balance() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Arrange
+ // As transfer_approved() can only be called on behalf of the contract
+ // Bob creates & mint token to himself
+ // and approve the contract to spend his assets
+ assert_ok!(Assets::create(RuntimeOrigin::signed(BOB), 1, BOB, 1));
+ assert_ok!(Assets::mint(RuntimeOrigin::signed(BOB), 1, BOB, 1000));
+ assert_ok!(Assets::approve_transfer(
+ RuntimeOrigin::signed(BOB),
+ 1,
+ addr.clone(),
+ 100
+ ));
+
+ // Act - The contract transfer 100 from Alice to Bob
+ assert_ok!(transfer_approved(addr.clone(), 1, BOB, ALICE, 100));
+
+ // Assert - Bob has 900 and Alice 100
+ assert_eq!(balance_of(addr.clone(), 1, BOB).data[1..], 900u128.encode());
+ assert_eq!(
+ balance_of(addr.clone(), 1, ALICE).data[1..],
+ 100u128.encode()
+ );
+ });
+}
+
+#[test]
+fn cancel_approval_works() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Arrange - Create and mint 1000 to contract
+ // and approve Bob to spend 100
+ assert_ok!(create(addr.clone(), 1, 1));
+ assert_ok!(mint(addr.clone(), 1, addr.clone(), 1000));
+ assert_ok!(approve_transfer(addr.clone(), 1, BOB, 100));
+
+ // Act - cancel approval
+ assert_ok!(cancel_approval(addr.clone(), 1, BOB));
+
+ // Assert - Bob allowance is 0
+ assert_eq!(
+ allowance(addr.clone(), 1, addr.clone(), BOB).data[1..],
+ 0u128.encode()
+ );
+ });
+}
+
+#[test]
+fn set_metadata_and_checks() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Arrange - create
+ assert_ok!(create(addr.clone(), 1, 1));
+
+ // Act - set metadata
+ assert_ok!(set_metadata(
+ addr.clone(),
+ 1,
+ "Name".as_bytes().to_vec(),
+ "SYMB".as_bytes().to_vec(),
+ 18
+ ));
+
+ // Assert - metadata Name, Symbol & decimal is correct
+ assert_eq!(metadata_name(addr.clone(), 1).data[1..], "Name".encode());
+ assert_eq!(metadata_symbol(addr.clone(), 1).data[1..], "SYMB".encode());
+ assert_eq!(metadata_decimals(addr.clone(), 1).data[1..], 18u8.encode());
+ });
+}
+
+#[test]
+fn transfer_ownership_works() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Arrange - create token - owner is contract
+ assert_ok!(create(addr.clone(), 1, 1));
+ assert_eq!(Assets::owner(1), Some(addr.clone()));
+
+ // Act - transfer ownership to Alice
+ assert_ok!(transfer_ownership(addr.clone(), 1, ALICE));
+
+ // Assert - Alice is the owner
+ assert_eq!(Assets::owner(1), Some(ALICE));
+ });
+}
+
+#[test]
+fn cannot_make_tx_on_behalf_of_caller() {
+ ExtBuilder::default()
+ .existential_deposit(50)
+ .build()
+ .execute_with(|| {
+ let addr = instantiate();
+
+ // Assert
+ // When calling chan extensio with Orgin::Caller
+ // it reverts
+ assert_eq!(
+ create_caller(addr.clone(), 1, 1).unwrap(),
+ ExecReturnValue {
+ flags: ReturnFlags::REVERT,
+ data: [0, 1, 98].into()
+ }
+ );
+ });
+}
+
+fn instantiate() -> AccountId32 {
+ let code = fs::read("./test-contract/asset_wrapper.wasm").expect("could not read .wasm file");
+ let _ = Balances::deposit_creating(&ALICE, ONE * 1000);
+ let _ = Balances::deposit_creating(&BOB, ONE * 1000);
+ let instance_selector: Vec = [0x9b, 0xae, 0x9d, 0x5e].to_vec();
+ Contracts::bare_instantiate(
+ ALICE,
+ 0,
+ GAS_LIMIT,
+ None,
+ Code::Upload(code),
+ instance_selector,
+ vec![],
+ false,
+ )
+ .result
+ .unwrap()
+ .account_id
+}
+
+fn create(
+ addr: AccountId32,
+ asset_id: u128,
+ min_balance: u128,
+) -> Result {
+ let data = [
+ [0xab, 0x70, 0x0a, 0x1b].to_vec(),
+ (asset_id, min_balance).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, ONE)
+}
+
+fn create_caller(
+ addr: AccountId32,
+ asset_id: u128,
+ min_balance: u128,
+) -> Result {
+ let data = [
+ [0x7f, 0xb0, 0xf9, 0xbb].to_vec(),
+ (asset_id, min_balance).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, ONE)
+}
+
+fn mint(
+ addr: AccountId32,
+ asset_id: u128,
+ beneficiary: AccountId32,
+ amount: u128,
+) -> Result {
+ let data = [
+ [0xcf, 0xdd, 0x9a, 0xa2].to_vec(),
+ (asset_id, beneficiary, amount).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, 0)
+}
+
+fn burn(
+ addr: AccountId32,
+ asset_id: u128,
+ who: AccountId32,
+ amount: u128,
+) -> Result {
+ let data = [
+ [0xb1, 0xef, 0xc1, 0x7b].to_vec(),
+ (asset_id, who, amount).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, 0)
+}
+
+fn transfer(
+ addr: AccountId32,
+ asset_id: u128,
+ target: AccountId32,
+ amount: u128,
+) -> Result {
+ let data = [
+ [0x84, 0xa1, 0x5d, 0xa1].to_vec(),
+ (asset_id, target, amount).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, 0)
+}
+
+fn transfer_approved(
+ addr: AccountId32,
+ asset_id: u128,
+ owner: AccountId32,
+ dest: AccountId32,
+ amount: u128,
+) -> Result {
+ let data = [
+ [0x31, 0x05, 0x59, 0x75].to_vec(),
+ (asset_id, owner, dest, amount).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, 0)
+}
+
+fn approve_transfer(
+ addr: AccountId32,
+ asset_id: u128,
+ delegate: AccountId32,
+ amount: u128,
+) -> Result {
+ let data = [
+ [0x8e, 0x7c, 0x3e, 0xe9].to_vec(),
+ (asset_id, delegate, amount).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, 0)
+}
+
+fn cancel_approval(
+ addr: AccountId32,
+ asset_id: u128,
+ delegate: AccountId32,
+) -> Result {
+ let data = [
+ [0x31, 0x7c, 0x8e, 0x29].to_vec(),
+ (asset_id, delegate).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, 0)
+}
+
+fn transfer_ownership(
+ addr: AccountId32,
+ asset_id: u128,
+ owner: AccountId32,
+) -> Result {
+ let data = [
+ [0x10, 0x7e, 0x33, 0xea].to_vec(),
+ (asset_id, owner).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, 0)
+}
+
+fn set_metadata(
+ addr: AccountId32,
+ asset_id: u128,
+ name: Vec,
+ symbol: Vec,
+ decimals: u8,
+) -> Result {
+ let data = [
+ [0x0b, 0x78, 0x7b, 0xb5].to_vec(),
+ (asset_id, name, symbol, decimals).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, 0)
+}
+
+fn balance_of(addr: AccountId32, asset_id: u128, who: AccountId32) -> ExecReturnValue {
+ let data = [[0x0f, 0x75, 0x5a, 0x56].to_vec(), (asset_id, who).encode()].concat();
+ do_bare_call(addr, data, 0).unwrap()
+}
+
+fn total_supply(addr: AccountId32, asset_id: u128) -> ExecReturnValue {
+ let data = [[0xdb, 0x63, 0x75, 0xa8].to_vec(), asset_id.encode()].concat();
+ do_bare_call(addr, data, 0).unwrap()
+}
+
+fn allowance(
+ addr: AccountId32,
+ asset_id: u128,
+ owner: AccountId32,
+ delegate: AccountId32,
+) -> ExecReturnValue {
+ let data = [
+ [0x6a, 0x00, 0x16, 0x5e].to_vec(),
+ (asset_id, owner, delegate).encode(),
+ ]
+ .concat();
+ do_bare_call(addr, data, 0).unwrap()
+}
+
+fn metadata_name(addr: AccountId32, asset_id: u128) -> ExecReturnValue {
+ let data = [[0xf5, 0xcd, 0xdb, 0xc1].to_vec(), asset_id.encode()].concat();
+ do_bare_call(addr, data, 0).unwrap()
+}
+
+fn metadata_symbol(addr: AccountId32, asset_id: u128) -> ExecReturnValue {
+ let data = [[0x7c, 0xdc, 0xaf, 0xc1].to_vec(), asset_id.encode()].concat();
+ do_bare_call(addr, data, 0).unwrap()
+}
+
+fn metadata_decimals(addr: AccountId32, asset_id: u128) -> ExecReturnValue {
+ let data = [[0x25, 0x54, 0x47, 0x3b].to_vec(), asset_id.encode()].concat();
+ do_bare_call(addr, data, 0).unwrap()
+}
+
+fn do_bare_call(
+ addr: AccountId32,
+ input: Vec,
+ value: u128,
+) -> Result {
+ Contracts::bare_call(
+ ALICE,
+ addr.into(),
+ value.into(),
+ GAS_LIMIT,
+ None,
+ input,
+ false,
+ Determinism::Deterministic,
+ )
+ .result
+}
diff --git a/chain-extensions/pallet-assets/test-contract/asset_wrapper.json b/chain-extensions/pallet-assets/test-contract/asset_wrapper.json
new file mode 100644
index 00000000..f9a6f1b5
--- /dev/null
+++ b/chain-extensions/pallet-assets/test-contract/asset_wrapper.json
@@ -0,0 +1,1203 @@
+{
+ "source": {
+ "hash": "0xe355795885a65d3d6235679e5f71239c7404471d1573c86e60ee838701490ed1",
+ "language": "ink! 4.2.0",
+ "compiler": "rustc 1.69.0-nightly",
+ "build_info": {
+ "build_mode": "Debug",
+ "cargo_contract_version": "2.1.0",
+ "rust_toolchain": "nightly-x86_64-unknown-linux-gnu",
+ "wasm_opt_settings": {
+ "keep_debug_symbols": false,
+ "optimization_passes": "Z"
+ }
+ }
+ },
+ "contract": {
+ "name": "asset_wrapper",
+ "version": "0.1.0",
+ "authors": [
+ "Stake Technologies "
+ ]
+ },
+ "spec": {
+ "constructors": [
+ {
+ "args": [],
+ "default": false,
+ "docs": [],
+ "label": "new",
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink_primitives",
+ "ConstructorResult"
+ ],
+ "type": 0
+ },
+ "selector": "0x9bae9d5e"
+ }
+ ],
+ "docs": [],
+ "environment": {
+ "accountId": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ },
+ "balance": {
+ "displayName": [
+ "Balance"
+ ],
+ "type": 3
+ },
+ "blockNumber": {
+ "displayName": [
+ "BlockNumber"
+ ],
+ "type": 16
+ },
+ "chainExtension": {
+ "displayName": [
+ "ChainExtension"
+ ],
+ "type": 17
+ },
+ "hash": {
+ "displayName": [
+ "Hash"
+ ],
+ "type": 14
+ },
+ "maxEventTopics": 4,
+ "timestamp": {
+ "displayName": [
+ "Timestamp"
+ ],
+ "type": 15
+ }
+ },
+ "events": [],
+ "lang_error": {
+ "displayName": [
+ "ink",
+ "LangError"
+ ],
+ "type": 2
+ },
+ "messages": [
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "min_balance",
+ "type": {
+ "displayName": [
+ "Balance"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "create",
+ "mutates": true,
+ "payable": true,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 4
+ },
+ "selector": "0xab700a1b"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "beneficiary",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ },
+ {
+ "label": "amount",
+ "type": {
+ "displayName": [
+ "Balance"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "mint",
+ "mutates": true,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 4
+ },
+ "selector": "0xcfdd9aa2"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "who",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ },
+ {
+ "label": "amount",
+ "type": {
+ "displayName": [
+ "Balance"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "burn",
+ "mutates": true,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 4
+ },
+ "selector": "0xb1efc17b"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "target",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ },
+ {
+ "label": "amount",
+ "type": {
+ "displayName": [
+ "Balance"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "transfer",
+ "mutates": true,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 4
+ },
+ "selector": "0x84a15da1"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "who",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "balance_of",
+ "mutates": false,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 10
+ },
+ "selector": "0x0f755a56"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "total_supply",
+ "mutates": false,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 10
+ },
+ "selector": "0xdb6375a8"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "owner",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ },
+ {
+ "label": "delegate",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "allowance",
+ "mutates": false,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 10
+ },
+ "selector": "0x6a00165e"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "delegate",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ },
+ {
+ "label": "amount",
+ "type": {
+ "displayName": [
+ "Balance"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "approve_transfer",
+ "mutates": true,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 4
+ },
+ "selector": "0x8e7c3ee9"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "delegate",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "cancel_approval",
+ "mutates": true,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 4
+ },
+ "selector": "0x317c8e29"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "owner",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ },
+ {
+ "label": "destination",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ },
+ {
+ "label": "amount",
+ "type": {
+ "displayName": [
+ "Balance"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "transfer_approved",
+ "mutates": true,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 4
+ },
+ "selector": "0x31055975"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "name",
+ "type": {
+ "displayName": [
+ "Vec"
+ ],
+ "type": 11
+ }
+ },
+ {
+ "label": "symbol",
+ "type": {
+ "displayName": [
+ "Vec"
+ ],
+ "type": 11
+ }
+ },
+ {
+ "label": "decimals",
+ "type": {
+ "displayName": [
+ "u8"
+ ],
+ "type": 9
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "set_metadata",
+ "mutates": true,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 4
+ },
+ "selector": "0x0b787bb5"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "metadata_name",
+ "mutates": false,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 12
+ },
+ "selector": "0xf5cddbc1"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "metadata_symbol",
+ "mutates": false,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 12
+ },
+ "selector": "0x7cdcafc1"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "metadata_decimals",
+ "mutates": false,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 13
+ },
+ "selector": "0x2554473b"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "owner",
+ "type": {
+ "displayName": [
+ "AccountId"
+ ],
+ "type": 7
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "transfer_ownership",
+ "mutates": true,
+ "payable": false,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 4
+ },
+ "selector": "0x107e33ea"
+ },
+ {
+ "args": [
+ {
+ "label": "asset_id",
+ "type": {
+ "displayName": [
+ "u128"
+ ],
+ "type": 3
+ }
+ },
+ {
+ "label": "min_balance",
+ "type": {
+ "displayName": [
+ "Balance"
+ ],
+ "type": 3
+ }
+ }
+ ],
+ "default": false,
+ "docs": [],
+ "label": "create_caller",
+ "mutates": true,
+ "payable": true,
+ "returnType": {
+ "displayName": [
+ "ink",
+ "MessageResult"
+ ],
+ "type": 4
+ },
+ "selector": "0x7fb0f9bb"
+ }
+ ]
+ },
+ "storage": {
+ "root": {
+ "layout": {
+ "struct": {
+ "fields": [],
+ "name": "Mock"
+ }
+ },
+ "root_key": "0x00000000"
+ }
+ },
+ "types": [
+ {
+ "id": 0,
+ "type": {
+ "def": {
+ "variant": {
+ "variants": [
+ {
+ "fields": [
+ {
+ "type": 1
+ }
+ ],
+ "index": 0,
+ "name": "Ok"
+ },
+ {
+ "fields": [
+ {
+ "type": 2
+ }
+ ],
+ "index": 1,
+ "name": "Err"
+ }
+ ]
+ }
+ },
+ "params": [
+ {
+ "name": "T",
+ "type": 1
+ },
+ {
+ "name": "E",
+ "type": 2
+ }
+ ],
+ "path": [
+ "Result"
+ ]
+ }
+ },
+ {
+ "id": 1,
+ "type": {
+ "def": {
+ "tuple": []
+ }
+ }
+ },
+ {
+ "id": 2,
+ "type": {
+ "def": {
+ "variant": {
+ "variants": [
+ {
+ "index": 1,
+ "name": "CouldNotReadInput"
+ }
+ ]
+ }
+ },
+ "path": [
+ "ink_primitives",
+ "LangError"
+ ]
+ }
+ },
+ {
+ "id": 3,
+ "type": {
+ "def": {
+ "primitive": "u128"
+ }
+ }
+ },
+ {
+ "id": 4,
+ "type": {
+ "def": {
+ "variant": {
+ "variants": [
+ {
+ "fields": [
+ {
+ "type": 5
+ }
+ ],
+ "index": 0,
+ "name": "Ok"
+ },
+ {
+ "fields": [
+ {
+ "type": 2
+ }
+ ],
+ "index": 1,
+ "name": "Err"
+ }
+ ]
+ }
+ },
+ "params": [
+ {
+ "name": "T",
+ "type": 5
+ },
+ {
+ "name": "E",
+ "type": 2
+ }
+ ],
+ "path": [
+ "Result"
+ ]
+ }
+ },
+ {
+ "id": 5,
+ "type": {
+ "def": {
+ "variant": {
+ "variants": [
+ {
+ "fields": [
+ {
+ "type": 1
+ }
+ ],
+ "index": 0,
+ "name": "Ok"
+ },
+ {
+ "fields": [
+ {
+ "type": 6
+ }
+ ],
+ "index": 1,
+ "name": "Err"
+ }
+ ]
+ }
+ },
+ "params": [
+ {
+ "name": "T",
+ "type": 1
+ },
+ {
+ "name": "E",
+ "type": 6
+ }
+ ],
+ "path": [
+ "Result"
+ ]
+ }
+ },
+ {
+ "id": 6,
+ "type": {
+ "def": {
+ "variant": {
+ "variants": [
+ {
+ "index": 1,
+ "name": "BalanceLow"
+ },
+ {
+ "index": 2,
+ "name": "NoAccount"
+ },
+ {
+ "index": 3,
+ "name": "NoPermission"
+ },
+ {
+ "index": 4,
+ "name": "Unknown"
+ },
+ {
+ "index": 5,
+ "name": "Frozen"
+ },
+ {
+ "index": 6,
+ "name": "InUse"
+ },
+ {
+ "index": 7,
+ "name": "BadWitness"
+ },
+ {
+ "index": 8,
+ "name": "MinBalanceZero"
+ },
+ {
+ "index": 9,
+ "name": "NoProvider"
+ },
+ {
+ "index": 10,
+ "name": "BadMetadata"
+ },
+ {
+ "index": 11,
+ "name": "Unapproved"
+ },
+ {
+ "index": 12,
+ "name": "WouldDie"
+ },
+ {
+ "index": 13,
+ "name": "AlreadyExists"
+ },
+ {
+ "index": 14,
+ "name": "NoDeposit"
+ },
+ {
+ "index": 15,
+ "name": "WouldBurn"
+ },
+ {
+ "index": 16,
+ "name": "LiveAsset"
+ },
+ {
+ "index": 17,
+ "name": "AssetNotLive"
+ },
+ {
+ "index": 18,
+ "name": "IncorrectStatus"
+ },
+ {
+ "index": 19,
+ "name": "NotFrozen"
+ },
+ {
+ "index": 98,
+ "name": "OriginCannotBeCaller"
+ },
+ {
+ "index": 99,
+ "name": "RuntimeError"
+ },
+ {
+ "index": 21,
+ "name": "UnknownStatusCode"
+ },
+ {
+ "index": 22,
+ "name": "InvalidScaleEncoding"
+ }
+ ]
+ }
+ },
+ "path": [
+ "assets_extension",
+ "AssetsError"
+ ]
+ }
+ },
+ {
+ "id": 7,
+ "type": {
+ "def": {
+ "composite": {
+ "fields": [
+ {
+ "type": 8,
+ "typeName": "[u8; 32]"
+ }
+ ]
+ }
+ },
+ "path": [
+ "ink_primitives",
+ "types",
+ "AccountId"
+ ]
+ }
+ },
+ {
+ "id": 8,
+ "type": {
+ "def": {
+ "array": {
+ "len": 32,
+ "type": 9
+ }
+ }
+ }
+ },
+ {
+ "id": 9,
+ "type": {
+ "def": {
+ "primitive": "u8"
+ }
+ }
+ },
+ {
+ "id": 10,
+ "type": {
+ "def": {
+ "variant": {
+ "variants": [
+ {
+ "fields": [
+ {
+ "type": 3
+ }
+ ],
+ "index": 0,
+ "name": "Ok"
+ },
+ {
+ "fields": [
+ {
+ "type": 2
+ }
+ ],
+ "index": 1,
+ "name": "Err"
+ }
+ ]
+ }
+ },
+ "params": [
+ {
+ "name": "T",
+ "type": 3
+ },
+ {
+ "name": "E",
+ "type": 2
+ }
+ ],
+ "path": [
+ "Result"
+ ]
+ }
+ },
+ {
+ "id": 11,
+ "type": {
+ "def": {
+ "sequence": {
+ "type": 9
+ }
+ }
+ }
+ },
+ {
+ "id": 12,
+ "type": {
+ "def": {
+ "variant": {
+ "variants": [
+ {
+ "fields": [
+ {
+ "type": 11
+ }
+ ],
+ "index": 0,
+ "name": "Ok"
+ },
+ {
+ "fields": [
+ {
+ "type": 2
+ }
+ ],
+ "index": 1,
+ "name": "Err"
+ }
+ ]
+ }
+ },
+ "params": [
+ {
+ "name": "T",
+ "type": 11
+ },
+ {
+ "name": "E",
+ "type": 2
+ }
+ ],
+ "path": [
+ "Result"
+ ]
+ }
+ },
+ {
+ "id": 13,
+ "type": {
+ "def": {
+ "variant": {
+ "variants": [
+ {
+ "fields": [
+ {
+ "type": 9
+ }
+ ],
+ "index": 0,
+ "name": "Ok"
+ },
+ {
+ "fields": [
+ {
+ "type": 2
+ }
+ ],
+ "index": 1,
+ "name": "Err"
+ }
+ ]
+ }
+ },
+ "params": [
+ {
+ "name": "T",
+ "type": 9
+ },
+ {
+ "name": "E",
+ "type": 2
+ }
+ ],
+ "path": [
+ "Result"
+ ]
+ }
+ },
+ {
+ "id": 14,
+ "type": {
+ "def": {
+ "composite": {
+ "fields": [
+ {
+ "type": 8,
+ "typeName": "[u8; 32]"
+ }
+ ]
+ }
+ },
+ "path": [
+ "ink_primitives",
+ "types",
+ "Hash"
+ ]
+ }
+ },
+ {
+ "id": 15,
+ "type": {
+ "def": {
+ "primitive": "u64"
+ }
+ }
+ },
+ {
+ "id": 16,
+ "type": {
+ "def": {
+ "primitive": "u32"
+ }
+ }
+ },
+ {
+ "id": 17,
+ "type": {
+ "def": {
+ "variant": {}
+ },
+ "path": [
+ "ink_env",
+ "types",
+ "NoChainExtension"
+ ]
+ }
+ }
+ ],
+ "version": "4"
+}
\ No newline at end of file
diff --git a/chain-extensions/pallet-assets/test-contract/asset_wrapper.wasm b/chain-extensions/pallet-assets/test-contract/asset_wrapper.wasm
new file mode 100644
index 00000000..555f80d5
Binary files /dev/null and b/chain-extensions/pallet-assets/test-contract/asset_wrapper.wasm differ