{"record":{"id":"7e8d4c7850d54b73","repo":"datahaven-xyz/datahaven","slug":"invalidtokentransferfees","errorCode":"InvalidTokenTransferFees","errorMessage":"InvalidTokenTransferFees","messagePattern":"InvalidTokenTransferFees","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"operator/pallets/system/src/lib.rs","lineNumber":374,"sourceCode":"        /// - `origin`: Must be root\n        /// - `create_asset_xcm`: The XCM execution cost for creating a new asset class on AssetHub,\n        ///   in DOT\n        /// - `transfer_asset_xcm`: The XCM execution cost for performing a reserve transfer on\n        ///   AssetHub, in DOT\n        /// - `register_token`: The Ether fee for registering a new token, to discourage spamming\n        #[pallet::call_index(9)]\n        #[pallet::weight((T::WeightInfo::set_token_transfer_fees(), DispatchClass::Operational))]\n        pub fn set_token_transfer_fees(\n            origin: OriginFor<T>,\n            create_asset_xcm: u128,\n            transfer_asset_xcm: u128,\n            register_token: U256,\n        ) -> DispatchResult {\n            ensure_root(origin)?;\n\n            // Basic validation of new costs. Particularly for token registration, we want to ensure\n            // its relatively expensive to discourage spamming. Like at least 100 USD.\n            ensure!(\n                create_asset_xcm > 0 && transfer_asset_xcm > 0 && register_token > meth(100),\n                Error::<T>::InvalidTokenTransferFees\n            );\n\n            let command = Command::SetTokenTransferFees {\n                create_asset_xcm,\n                transfer_asset_xcm,\n                register_token,\n            };\n            Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::<T>::No)?;\n\n            Self::deposit_event(Event::<T>::SetTokenTransferFees {\n                create_asset_xcm,\n                transfer_asset_xcm,\n                register_token,\n            });\n            Ok(())\n        }","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/datahaven-xyz/datahaven/blob/edcb13dbbcd3c29489eaa2480a6f60ee4cb1f3ec/operator/pallets/system/src/lib.rs#L356-L392","documentation":"The system pallet's `set_token_transfer_fees` extrinsic throws `Error::InvalidTokenTransferFees` when fee validation fails: `create_asset_xcm` and `transfer_asset_xcm` must be non-zero, and `register_token` must be greater than `meth(100)` (100 units, intentionally expensive to deter token-registration spam). Fees that are zero or too cheap are rejected before dispatching the SetTokenTransferFees command to Ethereum.","triggerScenarios":"Calling `set_token_transfer_fees(origin, create_asset_xcm, transfer_asset_xcm, register_token)` with root origin where either XCM fee is 0, or `register_token <= meth(100)` (i.e. at most 100 ETH-equivalent in the configured unit).","commonSituations":"Governance proposals setting fees in the wrong denomination (e.g. wei vs whole units) making register_token far below the 100-unit floor; typos passing 0 for an XCM fee; scripts copying fees from another chain with different units.","solutions":["Pass non-zero values for create_asset_xcm and transfer_asset_xcm.","Ensure register_token is denominated correctly and exceeds meth(100); recompute from the fee policy before dispatching.","Convert units explicitly (e.g. multiply decimals) in the proposal script to avoid denomination mistakes."],"exampleFix":"// before\nlet register_token = U256::from(100); // way below meth(100) minimum\nSystem::set_token_transfer_fees(origin, U256::one(), U256::one(), register_token)?;\n\n// after\nlet one_hundred = meth(100); // e.g. 100 * 10^18\nassert!(create_asset_xcm > 0 && transfer_asset_xcm > 0 && register_token > one_hundred);\nSystem::set_token_transfer_fees(origin, create_asset_xcm, transfer_asset_xcm, register_token)?;","handlingStrategy":"validation","validationCode":"if (createAssetXcm === 0n || transferAssetXcm === 0n || registerToken <= meth(100)) throw new Error('fees fail policy');","typeGuard":"function feesSatisfyPolicy(c, t, r) { return c > 0n && t > 0n && r > meth(100); }","tryCatchPattern":"try { await api.tx.system.setTokenTransferFees(c, t, r).signAndSend(root); } catch (e) { if (String(e).includes('InvalidTokenTransferFees')) { recalcFees(); } else { throw e; } }","preventionTips":["Centralize fee computation in one denomination-aware helper","Never hardcode 0 for XCM fees","Recompute register_token floor whenever unit conventions change","Simulate the extrinsic before on-chain dispatch"],"tags":["substrate","governance","fees","validation","token-transfer"],"backgroundTag":"invalid-argument-value","analyzedSha":"edcb13dbbcd3c29489eaa2480a6f60ee4cb1f3ec","analyzedAt":"2026-09-13T19:19:32.206Z","contentChangedAt":"2026-09-13T19:19:32.206Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}