From 28adea22bcf85ba2fd36a0cecf6f98e22ae5ee88 Mon Sep 17 00:00:00 2001 From: SatoshiQaziMuhammed Date: Tue, 11 Aug 2026 02:24:36 -0700 Subject: [PATCH] fix(pezkuwi-asset-hub): declare PEZ and USDT as sufficient, matching Polkadot AH (#66) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(pezkuwi-asset-hub): declare PEZ and USDT as sufficient assets The wallet refused USDT.p transfers to any account holding no HEZ: Your transfer will fail since the destination account does not have enough HEZ to accept other token transfers It is a false positive, and the chain disagrees with this config. DeadRecipientValidation skips the whole check when the destination asset is self-sufficient: skipIf = { assetSourceRegistry.isAssetSelfSufficient(destinationChainAsset) } and StatemineAssetBalance reads that flag from HERE, not from the chain: chainAsset.requireStatemine().isSufficient → runCatching { … }.getOrDefault(false) `isSufficient` was absent from typeExtras in every version of this config, so it resolved to false, the validation ran, and every transfer to a fresh account was warned against. Measured on chain (asset-hub-rpc.pezkuwichain.io): asset 1 PEZ sufficient=true minBalance=1 18 accounts asset 1000 wUSDT sufficient=true minBalance=10000 21 accounts Both are sufficient, so neither needs the recipient to hold native balance. Proof it works in practice rather than only in theory: account 5E2yqgUVVNjU… holds 1750.00 USDT with free=0, providers=0, sufficients=1 and nonce=0. Zero native balance, no provider reference, and it has never signed a transaction — so it was brought into existence by the incoming USDT transfer itself, which is exactly what the wallet was saying could not happen. Applied to v22 (the version the app fetches, runtime/build.gradle CHAINS_URL) and to the top-level chains.json. Noted, not changed here: this config also declares assets 1001/1002/1003 on Pezkuwi Asset Hub as DOT, ETH and BTC. None of the three exists on chain — assets.asset() returns None for all of them. They are shown to users and any transfer would fail. * Revert "fix(pezkuwi-asset-hub): declare PEZ and USDT as sufficient assets" This reverts commit af1a8a546873490f031fb5f018d3c2c0f855404d. * fix(pezkuwi-asset-hub): declare PEZ and USDT as sufficient, matching Polkadot AH Pezkuwi Asset Hub's two statemine assets carried only `assetId` in typeExtras. The equivalent entries on Polkadot Asset Hub — USDT (1984) and USDC (1337) — carry `isSufficient: true`. Same kind of asset, same file, two different declarations. The omission is not inert. `LocalToDomainChainMapper` reads typeExtras["isSufficient"] as Boolean? ?: STATEMINE_IS_SUFFICIENT_DEFAULT // false so an absent field resolves to false, `StatemineAssetBalance.isSelfSufficient` returns false, `DeadRecipientValidation`'s skipIf does not fire, and the validation runs — at `validOrError`, which is DefaultFailureLevel.ERROR, so the transfer is blocked rather than warned about. The chain says otherwise. Measured on asset-hub-rpc.pezkuwichain.io, 2026-08-10: asset 1 PEZ sufficient=true minBalance=1 18 accounts asset 1000 wUSDT sufficient=true minBalance=10000 21 accounts Neither needs the recipient to hold native HEZ, and one account demonstrates it: 5E2yqgUVVNjU… holds 1750.00 USDT with free=0, providers=0, sufficients=1 and nonce=0 — no native balance, no provider reference, never signed a transaction. It exists because the incoming USDT transfer created it, which is exactly what the wallet was reporting could not happen. 43 of the 67 statemine assets in this config declare the field. The 24 that omit it are genuinely non-sufficient on chain — the Polkadot AH meme tokens. Pezkuwi Asset Hub was the only case where the declaration disagreed with the chain. Applied to v22 (the version runtime/build.gradle CHAINS_URL fetches) and the top-level chains.json, in the same shape as the Polkadot entries. --- chains/chains.json | 8 +++++--- chains/v22/android/chains.json | 6 ++++-- chains/v22/android/chains_minimal.json | 8 +++++--- chains/v22/chains.json | 6 ++++-- chains/v22/chains_dev.json | 6 ++++-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/chains/chains.json b/chains/chains.json index 3c27ee9..727f855 100644 --- a/chains/chains.json +++ b/chains/chains.json @@ -116,7 +116,8 @@ "buyProviders": {}, "sellProviders": {}, "typeExtras": { - "assetId": "1" + "assetId": "1", + "isSufficient": true } }, { @@ -131,7 +132,8 @@ "buyProviders": {}, "sellProviders": {}, "typeExtras": { - "assetId": "1000" + "assetId": "1000", + "isSufficient": true } }, { @@ -8301,4 +8303,4 @@ "icon": "https://raw.githubusercontent.com/novasamatech/nova-utils/master/icons/chains/gradient/Acurast.svg", "addressPrefix": 42 } -] \ No newline at end of file +] diff --git a/chains/v22/android/chains.json b/chains/v22/android/chains.json index 41ce9d1..bded182 100644 --- a/chains/v22/android/chains.json +++ b/chains/v22/android/chains.json @@ -148,7 +148,8 @@ "buyProviders": {}, "sellProviders": {}, "typeExtras": { - "assetId": "1" + "assetId": "1", + "isSufficient": true } }, { @@ -163,7 +164,8 @@ "buyProviders": {}, "sellProviders": {}, "typeExtras": { - "assetId": "1000" + "assetId": "1000", + "isSufficient": true } } ], diff --git a/chains/v22/android/chains_minimal.json b/chains/v22/android/chains_minimal.json index 79745d2..a07ba3a 100644 --- a/chains/v22/android/chains_minimal.json +++ b/chains/v22/android/chains_minimal.json @@ -116,7 +116,8 @@ "buyProviders": {}, "sellProviders": {}, "typeExtras": { - "assetId": "1" + "assetId": "1", + "isSufficient": true } }, { @@ -131,7 +132,8 @@ "buyProviders": {}, "sellProviders": {}, "typeExtras": { - "assetId": "1000" + "assetId": "1000", + "isSufficient": true } }, { @@ -832,4 +834,4 @@ "defaultBlockTime": 2000 } } -] \ No newline at end of file +] diff --git a/chains/v22/chains.json b/chains/v22/chains.json index 41ce9d1..bded182 100644 --- a/chains/v22/chains.json +++ b/chains/v22/chains.json @@ -148,7 +148,8 @@ "buyProviders": {}, "sellProviders": {}, "typeExtras": { - "assetId": "1" + "assetId": "1", + "isSufficient": true } }, { @@ -163,7 +164,8 @@ "buyProviders": {}, "sellProviders": {}, "typeExtras": { - "assetId": "1000" + "assetId": "1000", + "isSufficient": true } } ], diff --git a/chains/v22/chains_dev.json b/chains/v22/chains_dev.json index fb8777f..750112b 100644 --- a/chains/v22/chains_dev.json +++ b/chains/v22/chains_dev.json @@ -148,7 +148,8 @@ "buyProviders": {}, "sellProviders": {}, "typeExtras": { - "assetId": "1" + "assetId": "1", + "isSufficient": true } }, { @@ -163,7 +164,8 @@ "buyProviders": {}, "sellProviders": {}, "typeExtras": { - "assetId": "1000" + "assetId": "1000", + "isSufficient": true } } ],