git.delta.rocks / unique-network / refs/commits / 17e188aac633

difftreelog

Merge pull request #577 from UniqueNetwork/fix/fee-multiplier-update

Yaroslav Bolyukin2022-12-19parents: #49182bd #bea7716.patch.diff
in: master

16 files changed

modifiedpallets/configuration/src/lib.rsdiffbeforeafterboth
--- a/pallets/configuration/src/lib.rs
+++ b/pallets/configuration/src/lib.rs
@@ -25,12 +25,14 @@
 };
 use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
 use scale_info::TypeInfo;
-use sp_arithmetic::traits::{BaseArithmetic, Unsigned};
+use sp_arithmetic::{
+	per_things::{Perbill, PerThing},
+	traits::{BaseArithmetic, Unsigned},
+};
 use smallvec::smallvec;
 
 pub use pallet::*;
 use sp_core::U256;
-use sp_runtime::Perbill;
 
 #[pallet]
 mod pallet {
@@ -46,8 +48,7 @@
 	#[pallet::config]
 	pub trait Config: frame_system::Config {
 		#[pallet::constant]
-		type DefaultWeightToFeeCoefficient: Get<u32>;
-
+		type DefaultWeightToFeeCoefficient: Get<u64>;
 		#[pallet::constant]
 		type DefaultMinGasPrice: Get<u64>;
 
@@ -66,7 +67,7 @@
 
 	#[pallet::storage]
 	pub type WeightToFeeCoefficientOverride<T: Config> = StorageValue<
-		Value = u32,
+		Value = u64,
 		QueryKind = ValueQuery,
 		OnEmpty = T::DefaultWeightToFeeCoefficient,
 	>;
@@ -90,7 +91,7 @@
 		#[pallet::weight(T::DbWeight::get().writes(1))]
 		pub fn set_weight_to_fee_coefficient_override(
 			origin: OriginFor<T>,
-			coeff: Option<u32>,
+			coeff: Option<u64>,
 		) -> DispatchResult {
 			ensure_root(origin)?;
 			if let Some(coeff) = coeff {
@@ -156,14 +157,17 @@
 impl<T, B> WeightToFeePolynomial for WeightToFee<T, B>
 where
 	T: Config,
-	B: BaseArithmetic + From<u32> + Copy + Unsigned,
+	B: BaseArithmetic + From<u32> + From<u64> + Copy + Unsigned,
 {
 	type Balance = B;
 
 	fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
 		smallvec!(WeightToFeeCoefficient {
-			coeff_integer: <WeightToFeeCoefficientOverride<T>>::get().into(),
-			coeff_frac: Perbill::zero(),
+			coeff_integer: (<WeightToFeeCoefficientOverride<T>>::get() / Perbill::ACCURACY as u64)
+				.into(),
+			coeff_frac: Perbill::from_parts(
+				(<WeightToFeeCoefficientOverride<T>>::get() % Perbill::ACCURACY as u64) as u32
+			),
 			negative: false,
 			degree: 1,
 		})
modifiedprimitives/common/src/constants.rsdiffbeforeafterboth
43pub const UNIQUE: Balance = 100 * CENTIUNIQUE;43pub const UNIQUE: Balance = 100 * CENTIUNIQUE;
4444
45// Targeting 0.1 UNQ per transfer45// Targeting 0.1 UNQ per transfer
46pub const WEIGHT_TO_FEE_COEFF: u32 = /*<weight2fee>*/175_199_920/*</weight2fee>*/;46pub const WEIGHT_TO_FEE_COEFF: u64 = /*<weight2fee>*/77_083_524_944_487_510/*</weight2fee>*/;
4747
48// Targeting 0.15 UNQ per transfer via ETH48// Targeting 0.15 UNQ per transfer via ETH
49pub const MIN_GAS_PRICE: u64 = /*<mingasprice>*/1_014_919_410_810/*</mingasprice>*/;49pub const MIN_GAS_PRICE: u64 = /*<mingasprice>*/1_014_919_313_914/*</mingasprice>*/;
5050
51/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers.51/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers.
52/// This is used to limit the maximal weight of a single extrinsic.52/// This is used to limit the maximal weight of a single extrinsic.
60 .set_proof_size(MAX_POV_SIZE as u64);60 .set_proof_size(MAX_POV_SIZE as u64);
6161
62parameter_types! {62parameter_types! {
63 pub const TransactionByteFee: Balance = 501 * MICROUNIQUE;63 pub const TransactionByteFee: Balance = 501 * MICROUNIQUE / 2;
64}64}
6565
modifiedruntime/common/config/pallets/mod.rsdiffbeforeafterboth
--- a/runtime/common/config/pallets/mod.rs
+++ b/runtime/common/config/pallets/mod.rs
@@ -104,7 +104,7 @@
 	pub const DayRelayBlocks: BlockNumber = RELAY_DAYS;
 }
 impl pallet_configuration::Config for Runtime {
-	type DefaultWeightToFeeCoefficient = ConstU32<{ up_common::constants::WEIGHT_TO_FEE_COEFF }>;
+	type DefaultWeightToFeeCoefficient = ConstU64<{ up_common::constants::WEIGHT_TO_FEE_COEFF }>;
 	type DefaultMinGasPrice = ConstU64<{ up_common::constants::MIN_GAS_PRICE }>;
 	type MaxXcmAllowedLocations = ConstU32<16>;
 	type AppPromotionDailyRate = AppPromotionDailyRate;
modifiedruntime/common/config/substrate.rsdiffbeforeafterboth
--- a/runtime/common/config/substrate.rs
+++ b/runtime/common/config/substrate.rs
@@ -28,10 +28,12 @@
 	traits::{BlakeTwo256, AccountIdLookup},
 	Perbill, Permill, Percent,
 };
+use sp_arithmetic::traits::One;
 use frame_system::{
 	limits::{BlockLength, BlockWeights},
 	EnsureRoot,
 };
+use pallet_transaction_payment::{Multiplier, ConstFeeMultiplier};
 use crate::{
 	runtime_common::DealWithFees, Runtime, RuntimeEvent, RuntimeCall, RuntimeOrigin, PalletInfo,
 	System, Balances, Treasury, SS58Prefix, Version,
@@ -152,6 +154,8 @@
 	/// This value increases the priority of `Operational` transactions by adding
 	/// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
 	pub const OperationalFeeMultiplier: u8 = 5;
+
+	pub FeeMultiplier: Multiplier = Multiplier::one();
 }
 
 impl pallet_transaction_payment::Config for Runtime {
@@ -160,7 +164,7 @@
 	type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
 	type OperationalFeeMultiplier = OperationalFeeMultiplier;
 	type WeightToFee = pallet_configuration::WeightToFee<Self, Balance>;
-	type FeeMultiplierUpdate = ();
+	type FeeMultiplierUpdate = ConstFeeMultiplier<FeeMultiplier>;
 }
 
 parameter_types! {
modifiedtests/src/calibrate.tsdiffbeforeafterboth
--- a/tests/src/calibrate.ts
+++ b/tests/src/calibrate.ts
@@ -1,59 +1,186 @@
 import {IKeyringPair} from '@polkadot/types/types';
-
 import {usingEthPlaygrounds, EthUniqueHelper} from './eth/util';
 
+class Fract {
+  static ZERO = new Fract(0n);
+  constructor(public readonly a: bigint, public readonly b: bigint = 1n) {
+    if (b === 0n) throw new Error('division by zero');
+    if (b < 0n) throw new Error('missing normalization');
+  }
 
-function linearRegression(points: { x: bigint, y: bigint }[]) {
-  let sumxy = 0n;
-  let sumx = 0n;
-  let sumy = 0n;
-  let sumx2 = 0n;
-  const n = points.length;
-  for (let i = 0; i < n; i++) {
-    const p = points[i];
-    sumxy += p.x * p.y;
-    sumx += p.x;
-    sumy += p.y;
-    sumx2 += p.x * p.x;
+  mul(other: Fract) {
+    return new Fract(this.a * other.a, this.b * other.b).optimize();
   }
 
-  const nb = BigInt(n);
+  div(other: Fract) {
+    return this.mul(other.inv());
+  }
 
-  const a = (nb * sumxy - sumx * sumy) / (nb * sumx2 - sumx * sumx);
-  const b = (sumy - a * sumx) / nb;
+  plus(other: Fract) {
+    if (this.b === other.b) {
+      return new Fract(this.a + other.a, this.b);
+    }
+    return new Fract(this.a * other.b + other.a * this.b, this.b * other.b).optimize();
+  }
 
-  return {a, b};
-}
+  minus(other: Fract) {
+    return this.plus(other.neg());
+  }
 
-// JS has no builtin function to calculate sqrt of bigint
-// https://stackoverflow.com/a/53684036/6190169
-function sqrt(value: bigint) {
-  if (value < 0n) {
-    throw 'square root of negative numbers is not supported';
+  neg() {
+    return new Fract(-this.a, this.b);
+  }
+  inv() {
+    if (this.a < 0) {
+      return new Fract(-this.b, -this.a);
+    } else {
+      return new Fract(this.b, this.a);
+    }
   }
 
-  if (value < 2n) {
-    return value;
+  optimize() {
+    function gcd(x: bigint, y: bigint) {
+      if (x < 0n)
+        x = -x;
+      if (y < 0n)
+        y = -y;
+      while(y) {
+        const t = y;
+        y = x % y;
+        x = t;
+      }
+      return x;
+    }
+    const v = gcd(this.a, this.b);
+    return new Fract(this.a / v, this.b / v);
+  }
+
+  toBigInt() {
+    return this.a / this.b;
+  }
+  toNumber() {
+    const v = this.optimize();
+    return Number(v.a) / Number(v.b);
+  }
+  toString() {
+    const v = this.optimize();
+    return `${v.a} / ${v.b}`;
   }
 
-  function newtonIteration(n: bigint, x0: bigint): bigint {
-    const x1 = ((n / x0) + x0) >> 1n;
-    if (x0 === x1 || x0 === (x1 - 1n)) {
-      return x0;
+  lt(other: Fract) {
+    return this.a * other.b < other.a * this.b;
+  }
+  eq(other: Fract) {
+    return this.a * other.b === other.a * this.b;
+  }
+
+  sqrt() {
+    if (this.a < 0n) {
+      throw 'square root of negative numbers is not supported';
+    }
+
+    if (this.lt(new Fract(2n))) {
+      return this;
+    }
+
+    function newtonIteration(n: Fract, x0: Fract): Fract {
+      const x1 = rpn(n, x0, '/', x0, '+', new Fract(2n), '/');
+      if (x0.eq(x1) || x0.eq(x1.minus(new Fract(1n)))) {
+        return x0;
+      }
+      return newtonIteration(n, x1);
     }
-    return newtonIteration(n, x1);
+
+    return newtonIteration(this, new Fract(1n));
   }
+}
 
-  return newtonIteration(value, 1n);
+type Op = Fract | '+' | '-' | '*' | '/' | 'dup' | Op[];
+function rpn(...ops: (Op)[]) {
+  const stack: Fract[] = [];
+  for (const op of ops) {
+    if (op instanceof Fract) {
+      stack.push(op);
+    } else if (op === '+') {
+      if (stack.length < 2)
+        throw new Error('stack underflow');
+      const b = stack.pop()!;
+      const a = stack.pop()!;
+      stack.push(a.plus(b));
+    } else if (op === '*') {
+      if (stack.length < 2)
+        throw new Error('stack underflow');
+      const b = stack.pop()!;
+      const a = stack.pop()!;
+      stack.push(a.mul(b));
+    } else if (op === '-') {
+      if (stack.length < 2)
+        throw new Error('stack underflow');
+      const b = stack.pop()!;
+      const a = stack.pop()!;
+      stack.push(a.minus(b));
+    } else if (op === '/') {
+      if (stack.length < 2)
+        throw new Error('stack underflow');
+      const b = stack.pop()!;
+      const a = stack.pop()!;
+      stack.push(a.div(b));
+    } else if (op === 'dup') {
+      if (stack.length < 1)
+        throw new Error('stack underflow');
+      const a = stack.pop()!;
+      stack.push(a);
+      stack.push(a);
+    } else if (Array.isArray(op)) {
+      stack.push(rpn(...op));
+    } else {
+      throw new Error(`unknown operand: ${op}`);
+    }
+  }
+  if (stack.length != 1)
+    throw new Error('one element should be left on stack');
+  return stack[0]!;
+}
+
+function linearRegression(points: { x: Fract, y: Fract }[]) {
+  let sumxy = Fract.ZERO;
+  let sumx = Fract.ZERO;
+  let sumy = Fract.ZERO;
+  let sumx2 = Fract.ZERO;
+  const n = points.length;
+  for (let i = 0; i < n; i++) {
+    const p = points[i];
+    sumxy = rpn(p.x, p.y, '*', sumxy, '+');
+    sumx = sumx.plus(p.x);
+    sumy = sumy.plus(p.y);
+    sumx2 = rpn(p.x, p.x, '*', sumx2, '+');
+  }
+
+  const nb = new Fract(BigInt(n));
+
+  const a = rpn(
+    [nb, sumxy, '*', sumx, sumy, '*', '-'],
+    [nb, sumx2, '*', sumx, sumx, '*', '-'],
+    '/',
+  );
+  const b = rpn(
+    [sumy, a, sumx, '*', '-'],
+    nb,
+    '/',
+  );
+
+  return {a, b};
 }
 
-function _error(points: { x: bigint, y: bigint }[], hypothesis: (a: bigint) => bigint) {
-  return sqrt(points.map(p => {
+const hypothesisLinear = (a: Fract, b: Fract) => (x: Fract) => rpn(x, a, '*', b, '+');
+
+function _error(points: { x: Fract, y: Fract }[], hypothesis: (a: Fract) => Fract) {
+  return points.map(p => {
     const v = hypothesis(p.x);
     const vv = p.y;
 
-    return (v - vv) ** 2n;
-  }).reduce((a, b) => a + b, 0n) / BigInt(points.length));
+    return rpn(v, vv, '-', 'dup', '*');
+  }).reduce((a, b) => a.plus(b), Fract.ZERO).sqrt().div(new Fract(BigInt(points.length)));
 }
 
 async function calibrateWeightToFee(helper: EthUniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>) {
@@ -68,15 +195,15 @@
     await token.transfer(alice, {Substrate: bob.address});
     const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
 
-    console.log(`Original price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`);
+    console.log(`\t[NFT transfer] Original price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`);
   }
 
   const api = helper.getApi();
-  const defaultCoeff = (api.consts.configuration.defaultWeightToFeeCoefficient as any).toBigInt();
+  const base = (await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt();
   for (let i = -5; i < 5; i++) {
-    await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(defaultCoeff + defaultCoeff / 1000n * BigInt(i))));
+    await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(base + base / 1000n * BigInt(i))));
 
-    const coefficient = (await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt();
+    const coefficient = new Fract((await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt());
     const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
     const token = await collection.mintToken(alice, {Substrate: alice.address});
 
@@ -84,16 +211,18 @@
     await token.transfer(alice, {Substrate: bob.address});
     const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
 
-    const transferPrice = aliceBalanceBefore - aliceBalanceAfter;
+    const transferPrice = new Fract(aliceBalanceBefore - aliceBalanceAfter);
 
     dataPoints.push({x: transferPrice, y: coefficient});
   }
   const {a, b} = linearRegression(dataPoints);
 
-  // console.log(`Error: ${error(dataPoints, x => a*x+b)}`);
+  const hyp = hypothesisLinear(a, b);
+  // console.log(`\t[NFT transfer] Error: ${_error(dataPoints, hyp).toNumber()}`);
 
-  const perfectValue = a * helper.balance.getOneTokenNominal() / 10n + b;
-  await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(perfectValue.toString())));
+  // 0.1 UNQ
+  const perfectValue = hyp(rpn(new Fract(helper.balance.getOneTokenNominal()), new Fract(1n, 10n), '*'));
+  await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(perfectValue.toBigInt())));
 
   {
     const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
@@ -102,7 +231,7 @@
     await token.transfer(alice, {Substrate: bob.address});
     const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
 
-    console.log(`Calibrated price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`);
+    console.log(`\t[NFT transfer] Calibrated price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`);
   }
 }
 
@@ -121,35 +250,37 @@
 
     const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS}));
 
-    console.log(`Original price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`);
+    console.log(`\t[ETH NFT transfer] Original price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`);
   }
 
   const api = helper.getApi();
-  const defaultCoeff = (api.consts.configuration.defaultMinGasPrice as any).toBigInt();
+  // const defaultCoeff = (api.consts.configuration.defaultMinGasPrice as any).toBigInt();
+  const base = (await api.query.configuration.minGasPriceOverride() as any).toBigInt();
   for (let i = -8; i < 8; i++) {
-    const gasPrice = defaultCoeff + defaultCoeff / 100000n * BigInt(i);
+    const gasPrice = base + base / 100000n * BigInt(i);
     const gasPriceStr = '0x' + gasPrice.toString(16);
     await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(gasPrice)));
 
-    const coefficient = (await api.query.configuration.minGasPriceOverride() as any).toBigInt();
+    const coefficient = new Fract((await api.query.configuration.minGasPriceOverride() as any).toBigInt());
     const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
     const token = await collection.mintToken(alice, {Ethereum: caller});
 
     const address = helper.ethAddress.fromCollectionId(collection.collectionId);
     const contract = helper.ethNativeContract.collection(address, 'nft', caller);
 
-    const transferPrice = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gasPrice: gasPriceStr, gas: helper.eth.DEFAULT_GAS}));
+    const transferPrice = new Fract(await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gasPrice: gasPriceStr, gas: helper.eth.DEFAULT_GAS})));
 
     dataPoints.push({x: transferPrice, y: coefficient});
   }
 
   const {a, b} = linearRegression(dataPoints);
 
-  // console.log(`Error: ${error(dataPoints, x => a*x+b)}`);
+  const hyp = hypothesisLinear(a, b);
+  // console.log(`\t[ETH NFT transfer] Error: ${_error(dataPoints, hyp).toNumber()}`);
 
-  // * 0.15 = * 10000 / 66666
-  const perfectValue = a * helper.balance.getOneTokenNominal() * 1000000n / 6666666n + b;
-  await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(perfectValue.toString())));
+  // 0.15 UNQ
+  const perfectValue = hyp(rpn(new Fract(helper.balance.getOneTokenNominal()), new Fract(15n, 100n), '*'));
+  await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(perfectValue.toBigInt())));
 
   {
     const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'});
@@ -160,18 +291,26 @@
 
     const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS}));
 
-    console.log(`Calibrated price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`);
+    console.log(`\t[ETH NFT transfer] Calibrated price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`);
   }
 }
 
 (async () => {
   await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {
-    // Second run slightly reduces error sometimes, as price line is not actually straight, this is a curve
+    // Subsequent runs reduce error, as price line is not actually straight, this is a curve
+
+    const iterations = 3;
+
+    console.log('[Calibrate WeightToFee]');
+    for (let i = 0; i < iterations; i++) {
+      await calibrateWeightToFee(helper, privateKey);
+    }
 
-    await calibrateWeightToFee(helper, privateKey);
-    await calibrateWeightToFee(helper, privateKey);
+    console.log();
 
-    await calibrateMinGasPrice(helper, privateKey);
-    await calibrateMinGasPrice(helper, privateKey);
+    console.log('[Calibrate MinGasPrice]');
+    for (let i = 0; i < iterations; i++) {
+      await calibrateMinGasPrice(helper, privateKey);
+    }
   });
 })();
addedtests/src/eth/ethFeesAreCorrect.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/ethFeesAreCorrect.test.ts
@@ -0,0 +1,66 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network 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.
+
+// Unique Network 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 Unique Network. If not, see <http://witww.gnu.org/licenses/>.
+
+import {IKeyringPair} from '@polkadot/types/types';
+import {itEth, usingEthPlaygrounds, expect} from './util';
+
+describe('Eth fees are correct', () => {
+  let donor: IKeyringPair;
+  let minter: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async () => {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = await privateKey({filename: __filename});
+      [minter, alice] = await helper.arrange.createAccounts([100n, 200n], donor);
+    });
+  });
+
+
+  itEth('web3 fees are the same as evm.call fees', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(minter, {});
+    
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const receiver = await helper.eth.createAccountWithBalance(donor);
+    const aliceEth = helper.address.substrateToEth(alice.address);
+
+    const {tokenId: tokenA} = await collection.mintToken(minter, {Ethereum: owner});
+    const {tokenId: tokenB} = await collection.mintToken(minter, {Ethereum: aliceEth});
+
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+
+    const balanceBeforeWeb3Transfer = await helper.balance.getEthereum(owner);
+    await contract.methods.transfer(receiver, tokenA).send({from: owner});
+    const balanceAfterWeb3Transfer = await helper.balance.getEthereum(owner);
+    const web3Diff = balanceBeforeWeb3Transfer - balanceAfterWeb3Transfer;
+
+    const encodedCall = contract.methods.transfer(receiver, tokenB)
+      .encodeABI();
+    
+    const balanceBeforeEvmCall = await helper.balance.getSubstrate(alice.address);
+    await helper.eth.sendEVM(
+      alice,
+      collectionAddress,
+      encodedCall,
+      '0',
+    );
+    const balanceAfterEvmCall = await helper.balance.getSubstrate(alice.address);
+    const evmCallDiff = balanceBeforeEvmCall - balanceAfterEvmCall;
+
+    expect(web3Diff).to.be.equal(evmCallDiff);
+  });
+});
modifiedtests/src/interfaces/augment-api-consts.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-consts.ts
+++ b/tests/src/interfaces/augment-api-consts.ts
@@ -82,7 +82,7 @@
       appPromotionDailyRate: Perbill & AugmentedConst<ApiType>;
       dayRelayBlocks: u32 & AugmentedConst<ApiType>;
       defaultMinGasPrice: u64 & AugmentedConst<ApiType>;
-      defaultWeightToFeeCoefficient: u32 & AugmentedConst<ApiType>;
+      defaultWeightToFeeCoefficient: u64 & AugmentedConst<ApiType>;
       maxXcmAllowedLocations: u32 & AugmentedConst<ApiType>;
       /**
        * Generic const
modifiedtests/src/interfaces/augment-api-query.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-query.ts
+++ b/tests/src/interfaces/augment-api-query.ts
@@ -162,7 +162,7 @@
     configuration: {
       appPromomotionConfigurationOverride: AugmentedQuery<ApiType, () => Observable<PalletConfigurationAppPromotionConfiguration>, []> & QueryableStorageEntry<ApiType, []>;
       minGasPriceOverride: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
-      weightToFeeCoefficientOverride: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+      weightToFeeCoefficientOverride: AugmentedQuery<ApiType, () => Observable<u64>, []> & QueryableStorageEntry<ApiType, []>;
       xcmAllowedLocationsOverride: AugmentedQuery<ApiType, () => Observable<Option<Vec<XcmV1MultiLocation>>>, []> & QueryableStorageEntry<ApiType, []>;
       /**
        * Generic query
modifiedtests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-rpc.ts
+++ b/tests/src/interfaces/augment-api-rpc.ts
@@ -16,7 +16,7 @@
 import type { BlockHash } from '@polkadot/types/interfaces/chain';
 import type { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate';
 import type { AuthorityId } from '@polkadot/types/interfaces/consensus';
-import type { CodeUploadRequest, CodeUploadResult, ContractCallRequest, ContractExecResult, ContractInstantiateResult, InstantiateRequest } from '@polkadot/types/interfaces/contracts';
+import type { CodeUploadRequest, CodeUploadResult, ContractCallRequest, ContractExecResult, ContractInstantiateResult, InstantiateRequestV1 } from '@polkadot/types/interfaces/contracts';
 import type { BlockStats } from '@polkadot/types/interfaces/dev';
 import type { CreatedBlock } from '@polkadot/types/interfaces/engine';
 import type { EthAccount, EthCallRequest, EthFeeHistory, EthFilter, EthFilterChanges, EthLog, EthReceipt, EthRichBlock, EthSubKind, EthSubParams, EthSyncStatus, EthTransaction, EthTransactionRequest, EthWork } from '@polkadot/types/interfaces/eth';
@@ -24,7 +24,7 @@
 import type { EncodedFinalityProofs, JustificationNotification, ReportedRoundStates } from '@polkadot/types/interfaces/grandpa';
 import type { MmrLeafBatchProof, MmrLeafProof } from '@polkadot/types/interfaces/mmr';
 import type { StorageKind } from '@polkadot/types/interfaces/offchain';
-import type { FeeDetails, RuntimeDispatchInfo } from '@polkadot/types/interfaces/payment';
+import type { FeeDetails, RuntimeDispatchInfoV1 } from '@polkadot/types/interfaces/payment';
 import type { RpcMethods } from '@polkadot/types/interfaces/rpc';
 import type { AccountId, AccountId32, BlockNumber, H160, H256, H64, Hash, Header, Index, Justification, KeyValue, SignedBlock, StorageData } from '@polkadot/types/interfaces/runtime';
 import type { MigrationStatusResult, ReadProof, RuntimeVersion, TraceBlockResponse } from '@polkadot/types/interfaces/state';
@@ -174,7 +174,7 @@
        * @deprecated Use the runtime interface `api.call.contractsApi.instantiate` instead
        * Instantiate a new contract
        **/
-      instantiate: AugmentedRpc<(request: InstantiateRequest | { origin?: any; value?: any; gasLimit?: any; storageDepositLimit?: any; code?: any; data?: any; salt?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractInstantiateResult>>;
+      instantiate: AugmentedRpc<(request: InstantiateRequestV1 | { origin?: any; value?: any; gasLimit?: any; code?: any; data?: any; salt?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractInstantiateResult>>;
       /**
        * @deprecated Not available in newer versions of the contracts interfaces
        * Returns the projected time a given contract will be able to sustain paying its rent
@@ -426,13 +426,15 @@
     };
     payment: {
       /**
+       * @deprecated Use `api.call.transactionPaymentApi.queryFeeDetails` instead
        * Query the detailed fee of a given encoded extrinsic
        **/
       queryFeeDetails: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<FeeDetails>>;
       /**
+       * @deprecated Use `api.call.transactionPaymentApi.queryInfo` instead
        * Retrieves the fee information for an encoded extrinsic
        **/
-      queryInfo: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<RuntimeDispatchInfo>>;
+      queryInfo: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<RuntimeDispatchInfoV1>>;
     };
     rmrk: {
       /**
modifiedtests/src/interfaces/augment-api-runtime.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-runtime.ts
+++ b/tests/src/interfaces/augment-api-runtime.ts
@@ -6,7 +6,7 @@
 import '@polkadot/api-base/types/calls';
 
 import type { ApiTypes, AugmentedCall, DecoratedCallBase } from '@polkadot/api-base/types';
-import type { Bytes, Null, Option, Result, U256, Vec, bool, u256, u64 } from '@polkadot/types-codec';
+import type { Bytes, Null, Option, Result, U256, Vec, bool, u256, u32, u64 } from '@polkadot/types-codec';
 import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';
 import type { CheckInherentsResult, InherentData } from '@polkadot/types/interfaces/blockbuilder';
 import type { BlockHash } from '@polkadot/types/interfaces/chain';
@@ -16,6 +16,7 @@
 import type { EvmAccount, EvmCallInfo, EvmCreateInfo } from '@polkadot/types/interfaces/evm';
 import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';
 import type { OpaqueMetadata } from '@polkadot/types/interfaces/metadata';
+import type { FeeDetails, RuntimeDispatchInfo } from '@polkadot/types/interfaces/payment';
 import type { AccountId, Block, H160, H256, Header, Index, KeyTypeId, Permill, SlotDuration } from '@polkadot/types/interfaces/runtime';
 import type { RuntimeVersion } from '@polkadot/types/interfaces/state';
 import type { ApplyExtrinsicResult, DispatchError } from '@polkadot/types/interfaces/system';
@@ -228,5 +229,20 @@
        **/
       [key: string]: DecoratedCallBase<ApiType>;
     };
+    /** 0x37c8bb1350a9a2a8/2 */
+    transactionPaymentApi: {
+      /**
+       * The transaction fee details
+       **/
+      queryFeeDetails: AugmentedCall<ApiType, (uxt: Extrinsic | IExtrinsic | string | Uint8Array, len: u32 | AnyNumber | Uint8Array) => Observable<FeeDetails>>;
+      /**
+       * The transaction info
+       **/
+      queryInfo: AugmentedCall<ApiType, (uxt: Extrinsic | IExtrinsic | string | Uint8Array, len: u32 | AnyNumber | Uint8Array) => Observable<RuntimeDispatchInfo>>;
+      /**
+       * Generic call
+       **/
+      [key: string]: DecoratedCallBase<ApiType>;
+    };
   } // AugmentedCalls
 } // declare module
modifiedtests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-tx.ts
+++ b/tests/src/interfaces/augment-api-tx.ts
@@ -217,7 +217,7 @@
     configuration: {
       setAppPromotionConfigurationOverride: AugmentedSubmittable<(configuration: PalletConfigurationAppPromotionConfiguration | { recalculationInterval?: any; pendingInterval?: any; intervalIncome?: any; maxStakersPerCalculation?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletConfigurationAppPromotionConfiguration]>;
       setMinGasPriceOverride: AugmentedSubmittable<(coeff: Option<u64> | null | Uint8Array | u64 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u64>]>;
-      setWeightToFeeCoefficientOverride: AugmentedSubmittable<(coeff: Option<u32> | null | Uint8Array | u32 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u32>]>;
+      setWeightToFeeCoefficientOverride: AugmentedSubmittable<(coeff: Option<u64> | null | Uint8Array | u64 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u64>]>;
       setXcmAllowedLocations: AugmentedSubmittable<(locations: Option<Vec<XcmV1MultiLocation>> | null | Uint8Array | Vec<XcmV1MultiLocation> | (XcmV1MultiLocation | { parents?: any; interior?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Option<Vec<XcmV1MultiLocation>>]>;
       /**
        * Generic tx
@@ -1432,6 +1432,23 @@
        **/
       destroyCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
       /**
+       * Repairs a collection if the data was somehow corrupted.
+       * 
+       * # Arguments
+       * 
+       * * `collection_id`: ID of the collection to repair.
+       **/
+      forceRepairCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+      /**
+       * Repairs a token if the data was somehow corrupted.
+       * 
+       * # Arguments
+       * 
+       * * `collection_id`: ID of the collection the item belongs to.
+       * * `item_id`: ID of the item.
+       **/
+      forceRepairItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32]>;
+      /**
        * Remove admin of a collection.
        * 
        * An admin address can remove itself. List of admins may become empty,
@@ -1474,15 +1491,6 @@
        * * `address`: ID of the address to be removed from the allowlist.
        **/
       removeFromAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-      /**
-       * Repairs a broken item
-       * 
-       * # Arguments
-       * 
-       * * `collection_id`: ID of the collection the item belongs to.
-       * * `item_id`: ID of the item.
-       **/
-      repairItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32]>;
       /**
        * Re-partition a refungible token, while owning all of its parts/pieces.
        * 
modifiedtests/src/interfaces/augment-types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-types.ts
+++ b/tests/src/interfaces/augment-types.ts
@@ -24,7 +24,7 @@
 import type { StatementKind } from '@polkadot/types/interfaces/claims';
 import type { CollectiveOrigin, MemberCount, ProposalIndex, Votes, VotesTo230 } from '@polkadot/types/interfaces/collective';
 import type { AuthorityId, RawVRFOutput } from '@polkadot/types/interfaces/consensus';
-import type { AliveContractInfo, CodeHash, CodeSource, CodeUploadRequest, CodeUploadResult, CodeUploadResultValue, ContractCallFlags, ContractCallRequest, ContractExecResult, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractExecResultTo267, ContractInfo, ContractInstantiateResult, ContractInstantiateResultTo267, ContractInstantiateResultTo299, ContractReturnFlags, ContractStorageKey, DeletedContract, ExecReturnValue, Gas, HostFnWeights, HostFnWeightsTo264, InstantiateRequest, InstantiateRequestV1, InstantiateRequestV2, InstantiateReturnValue, InstantiateReturnValueOk, InstantiateReturnValueTo267, InstructionWeights, Limits, LimitsTo264, PrefabWasmModule, RentProjection, Schedule, ScheduleTo212, ScheduleTo258, ScheduleTo264, SeedOf, StorageDeposit, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts';
+import type { AliveContractInfo, CodeHash, CodeSource, CodeUploadRequest, CodeUploadResult, CodeUploadResultValue, ContractCallFlags, ContractCallRequest, ContractExecResult, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractExecResultTo267, ContractExecResultU64, ContractInfo, ContractInstantiateResult, ContractInstantiateResultTo267, ContractInstantiateResultTo299, ContractInstantiateResultU64, ContractReturnFlags, ContractStorageKey, DeletedContract, ExecReturnValue, Gas, HostFnWeights, HostFnWeightsTo264, InstantiateRequest, InstantiateRequestV1, InstantiateRequestV2, InstantiateReturnValue, InstantiateReturnValueOk, InstantiateReturnValueTo267, InstructionWeights, Limits, LimitsTo264, PrefabWasmModule, RentProjection, Schedule, ScheduleTo212, ScheduleTo258, ScheduleTo264, SeedOf, StorageDeposit, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts';
 import type { ContractConstructorSpecLatest, ContractConstructorSpecV0, ContractConstructorSpecV1, ContractConstructorSpecV2, ContractConstructorSpecV3, ContractContractSpecV0, ContractContractSpecV1, ContractContractSpecV2, ContractContractSpecV3, ContractContractSpecV4, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEventParamSpecLatest, ContractEventParamSpecV0, ContractEventParamSpecV2, ContractEventSpecLatest, ContractEventSpecV0, ContractEventSpecV1, ContractEventSpecV2, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpecLatest, ContractMessageParamSpecV0, ContractMessageParamSpecV2, ContractMessageSpecLatest, ContractMessageSpecV0, ContractMessageSpecV1, ContractMessageSpecV2, ContractMetadata, ContractMetadataLatest, ContractMetadataV0, ContractMetadataV1, ContractMetadataV2, ContractMetadataV3, ContractMetadataV4, ContractProject, ContractProjectContract, ContractProjectInfo, ContractProjectSource, ContractProjectV0, ContractSelector, ContractStorageLayout, ContractTypeSpec } from '@polkadot/types/interfaces/contractsAbi';
 import type { FundIndex, FundInfo, LastContribution, TrieIndex } from '@polkadot/types/interfaces/crowdloan';
 import type { CollationInfo, CollationInfoV1, ConfigData, MessageId, OverweightIndex, PageCounter, PageIndexData } from '@polkadot/types/interfaces/cumulus';
@@ -47,7 +47,7 @@
 import type { StorageKind } from '@polkadot/types/interfaces/offchain';
 import type { DeferredOffenceOf, Kind, OffenceDetails, Offender, OpaqueTimeSlot, ReportIdOf, Reporter } from '@polkadot/types/interfaces/offences';
 import type { AbridgedCandidateReceipt, AbridgedHostConfiguration, AbridgedHrmpChannel, AssignmentId, AssignmentKind, AttestedCandidate, AuctionIndex, AuthorityDiscoveryId, AvailabilityBitfield, AvailabilityBitfieldRecord, BackedCandidate, Bidder, BufferedSessionChange, CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, CandidateInfo, CandidatePendingAvailability, CandidateReceipt, CollatorId, CollatorSignature, CommittedCandidateReceipt, CoreAssignment, CoreIndex, CoreOccupied, CoreState, DisputeLocation, DisputeResult, DisputeState, DisputeStatement, DisputeStatementSet, DoubleVoteReport, DownwardMessage, ExplicitDisputeStatement, GlobalValidationData, GlobalValidationSchedule, GroupIndex, GroupRotationInfo, HeadData, HostConfiguration, HrmpChannel, HrmpChannelId, HrmpOpenChannelRequest, InboundDownwardMessage, InboundHrmpMessage, InboundHrmpMessages, IncomingParachain, IncomingParachainDeploy, IncomingParachainFixed, InvalidDisputeStatementKind, LeasePeriod, LeasePeriodOf, LocalValidationData, MessageIngestionType, MessageQueueChain, MessagingStateSnapshot, MessagingStateSnapshotEgressEntry, MultiDisputeStatementSet, NewBidder, OccupiedCore, OccupiedCoreAssumption, OldV1SessionInfo, OutboundHrmpMessage, ParaGenesisArgs, ParaId, ParaInfo, ParaLifecycle, ParaPastCodeMeta, ParaScheduling, ParaValidatorIndex, ParachainDispatchOrigin, ParachainInherentData, ParachainProposal, ParachainsInherentData, ParathreadClaim, ParathreadClaimQueue, ParathreadEntry, PersistedValidationData, PvfCheckStatement, QueuedParathread, RegisteredParachainInfo, RelayBlockNumber, RelayChainBlockNumber, RelayChainHash, RelayHash, Remark, ReplacementTimes, Retriable, ScheduledCore, Scheduling, ScrapedOnChainVotes, ServiceQuality, SessionInfo, SessionInfoValidatorGroup, SignedAvailabilityBitfield, SignedAvailabilityBitfields, SigningContext, SlotRange, SlotRange10, Statement, SubId, SystemInherentData, TransientValidationData, UpgradeGoAhead, UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidationData, ValidationDataType, ValidationFunctionParams, ValidatorSignature, ValidityAttestation, VecInboundHrmpMessage, WinnersData, WinnersData10, WinnersDataTuple, WinnersDataTuple10, WinningData, WinningData10, WinningDataEntry } from '@polkadot/types/interfaces/parachains';
-import type { FeeDetails, InclusionFee, RuntimeDispatchInfo } from '@polkadot/types/interfaces/payment';
+import type { FeeDetails, InclusionFee, RuntimeDispatchInfo, RuntimeDispatchInfoV1, RuntimeDispatchInfoV2 } from '@polkadot/types/interfaces/payment';
 import type { Approvals } from '@polkadot/types/interfaces/poll';
 import type { ProxyAnnouncement, ProxyDefinition, ProxyType } from '@polkadot/types/interfaces/proxy';
 import type { AccountStatus, AccountValidity } from '@polkadot/types/interfaces/purchase';
@@ -273,10 +273,12 @@
     ContractExecResultTo255: ContractExecResultTo255;
     ContractExecResultTo260: ContractExecResultTo260;
     ContractExecResultTo267: ContractExecResultTo267;
+    ContractExecResultU64: ContractExecResultU64;
     ContractInfo: ContractInfo;
     ContractInstantiateResult: ContractInstantiateResult;
     ContractInstantiateResultTo267: ContractInstantiateResultTo267;
     ContractInstantiateResultTo299: ContractInstantiateResultTo299;
+    ContractInstantiateResultU64: ContractInstantiateResultU64;
     ContractLayoutArray: ContractLayoutArray;
     ContractLayoutCell: ContractLayoutCell;
     ContractLayoutEnum: ContractLayoutEnum;
@@ -1057,6 +1059,8 @@
     RpcMethods: RpcMethods;
     RuntimeDbWeight: RuntimeDbWeight;
     RuntimeDispatchInfo: RuntimeDispatchInfo;
+    RuntimeDispatchInfoV1: RuntimeDispatchInfoV1;
+    RuntimeDispatchInfoV2: RuntimeDispatchInfoV2;
     RuntimeVersion: RuntimeVersion;
     RuntimeVersionApi: RuntimeVersionApi;
     RuntimeVersionPartial: RuntimeVersionPartial;
modifiedtests/src/interfaces/default/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -1303,7 +1303,7 @@
 export interface PalletConfigurationCall extends Enum {
   readonly isSetWeightToFeeCoefficientOverride: boolean;
   readonly asSetWeightToFeeCoefficientOverride: {
-    readonly coeff: Option<u32>;
+    readonly coeff: Option<u64>;
   } & Struct;
   readonly isSetMinGasPriceOverride: boolean;
   readonly asSetMinGasPriceOverride: {
@@ -2319,12 +2319,16 @@
     readonly operator: PalletEvmAccountBasicCrossAccountIdRepr;
     readonly approve: bool;
   } & Struct;
-  readonly isRepairItem: boolean;
-  readonly asRepairItem: {
+  readonly isForceRepairCollection: boolean;
+  readonly asForceRepairCollection: {
+    readonly collectionId: u32;
+  } & Struct;
+  readonly isForceRepairItem: boolean;
+  readonly asForceRepairItem: {
     readonly collectionId: u32;
     readonly itemId: u32;
   } & Struct;
-  readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll' | 'RepairItem';
+  readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll' | 'ForceRepairCollection' | 'ForceRepairItem';
 }
 
 /** @name PalletUniqueError */
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -2282,8 +2282,11 @@
         operator: 'PalletEvmAccountBasicCrossAccountIdRepr',
         approve: 'bool',
       },
-      repair_item: {
+      force_repair_collection: {
         collectionId: 'u32',
+      },
+      force_repair_item: {
+        collectionId: 'u32',
         itemId: 'u32'
       }
     }
@@ -2452,7 +2455,7 @@
   PalletConfigurationCall: {
     _enum: {
       set_weight_to_fee_coefficient_override: {
-        coeff: 'Option<u32>',
+        coeff: 'Option<u64>',
       },
       set_min_gas_price_override: {
         coeff: 'Option<u64>',
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -2517,12 +2517,16 @@
       readonly operator: PalletEvmAccountBasicCrossAccountIdRepr;
       readonly approve: bool;
     } & Struct;
-    readonly isRepairItem: boolean;
-    readonly asRepairItem: {
+    readonly isForceRepairCollection: boolean;
+    readonly asForceRepairCollection: {
+      readonly collectionId: u32;
+    } & Struct;
+    readonly isForceRepairItem: boolean;
+    readonly asForceRepairItem: {
       readonly collectionId: u32;
       readonly itemId: u32;
     } & Struct;
-    readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll' | 'RepairItem';
+    readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll' | 'ForceRepairCollection' | 'ForceRepairItem';
   }
 
   /** @name UpDataStructsCollectionMode (237) */
@@ -2675,7 +2679,7 @@
   interface PalletConfigurationCall extends Enum {
     readonly isSetWeightToFeeCoefficientOverride: boolean;
     readonly asSetWeightToFeeCoefficientOverride: {
-      readonly coeff: Option<u32>;
+      readonly coeff: Option<u64>;
     } & Struct;
     readonly isSetMinGasPriceOverride: boolean;
     readonly asSetMinGasPriceOverride: {
modifiedtests/src/nesting/collectionProperties.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/collectionProperties.test.ts
+++ b/tests/src/nesting/collectionProperties.test.ts
@@ -209,7 +209,7 @@
   before(async () => {
     await usingPlaygrounds(async (helper, privateKey) => {
       const donor = await privateKey({filename: __filename});
-      [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
+      [alice, bob] = await helper.arrange.createAccounts([1000n, 100n], donor);
     });
   });