Skip to content

Commit 26475e3

Browse files
authored
handle non-transferable currency (#1894)
* feat: Add nonTransferable field to Currency type and validator schema Support non-transferable currencies (e.g., Akash ACT token) by adding an optional nonTransferable boolean to the Currency interface and corresponding Joi validation in chain-validator. * feat: Hide non-transferable currencies from send/swap UI - Token detail: disable Send, Receive, Swap buttons for nonTransferable - Send asset selection: filter out nonTransferable tokens - Swap destination: filter out nonTransferable tokens from owned list * feat: Add nonTransferable property to Currency interface - Introduced an optional nonTransferable boolean field to the Currency interface, indicating whether a currency can be transferred on-chain. This enhances the currency type definition to support non-transferable assets.
1 parent bdc41fb commit 26475e3

File tree

6 files changed

+48
-6
lines changed

6 files changed

+48
-6
lines changed

apps/extension/src/pages/ibc-swap/select-asset/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,11 @@ class IBCSwapDestinationState {
227227
return false;
228228
}
229229

230+
const c = token.token.currency;
231+
if (c.nonTransferable) {
232+
return false;
233+
}
234+
230235
return this.swapHelper.isSwapDestinationOrAlternatives(
231236
sourceChainId,
232237
sourceDenom,

apps/extension/src/pages/main/token-detail/modal.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ export const TokenDetailModal: FunctionComponent<{
113113
})();
114114

115115
const isIBCCurrency = "paths" in currency;
116+
const isNonTransferable = !!currency.nonTransferable;
116117

117118
const [isReceiveOpen, setIsReceiveOpen] = React.useState(false);
118119
const [isOpenBuy, setIsOpenBuy] = React.useState(false);
@@ -257,7 +258,7 @@ export const TokenDetailModal: FunctionComponent<{
257258
onClick: () => {
258259
setIsReceiveOpen(true);
259260
},
260-
disabled: isIBCCurrency,
261+
disabled: isIBCCurrency || isNonTransferable,
261262
},
262263
{
263264
icon: (
@@ -285,10 +286,12 @@ export const TokenDetailModal: FunctionComponent<{
285286
}&outCoinMinimalDenom=uusdc&entryPoint=token_detail`
286287
);
287288
},
288-
disabled: !swapQueriesStore.querySwapHelper.isSwappableCurrency(
289-
chainId,
290-
currency
291-
),
289+
disabled:
290+
isNonTransferable ||
291+
!swapQueriesStore.querySwapHelper.isSwappableCurrency(
292+
chainId,
293+
currency
294+
),
292295
},
293296
{
294297
icon: (
@@ -329,6 +332,7 @@ export const TokenDetailModal: FunctionComponent<{
329332
);
330333
}
331334
},
335+
disabled: isNonTransferable,
332336
},
333337
];
334338

apps/extension/src/pages/send/select-asset/index.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,14 @@ export const SendSelectAssetPage: FunctionComponent = observer(() => {
9494
});
9595
}, [tokens]);
9696

97-
const searchedTokens = useSearch(nonZeroTokens, search, searchFields);
97+
const transferableTokens = useMemo(() => {
98+
return nonZeroTokens.filter((token) => {
99+
const c = token.token.currency;
100+
return !c.nonTransferable;
101+
});
102+
}, [nonZeroTokens]);
103+
104+
const searchedTokens = useSearch(transferableTokens, search, searchFields);
98105

99106
const _filteredTokens = useMemo(() => {
100107
if (paramIsIBCTransfer) {

packages/chain-validator/src/schema.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,27 @@ describe("Test chain info schema", () => {
105105
await CurrencySchema.validateAsync(currency);
106106
}, "Should throw error if coin image url is not url");
107107

108+
await assert.doesNotReject(async () => {
109+
const currency: Currency = {
110+
coinDenom: "TEST",
111+
coinMinimalDenom: "utest",
112+
coinDecimals: 6,
113+
nonTransferable: true,
114+
};
115+
116+
await CurrencySchema.validateAsync(currency);
117+
});
118+
119+
await assert.doesNotReject(async () => {
120+
const currency: Currency = {
121+
coinDenom: "TEST",
122+
coinMinimalDenom: "utest",
123+
coinDecimals: 6,
124+
};
125+
126+
await CurrencySchema.validateAsync(currency);
127+
});
128+
108129
await assert.rejects(async () => {
109130
// @ts-ignore
110131
const currency: Currency = {

packages/chain-validator/src/schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const CurrencySchema = Joi.object<
2525
coinDecimals: Joi.number().strict().integer().min(0).max(18).required(),
2626
coinGeckoId: Joi.string(),
2727
coinImageUrl: Joi.string().uri(),
28+
nonTransferable: Joi.boolean(),
2829
}).keys({
2930
type: Joi.forbidden(),
3031
});

packages/types/src/currency.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ export interface Currency {
1111
*/
1212
readonly coinGeckoId?: string;
1313
readonly coinImageUrl?: string;
14+
/**
15+
* If true, this currency cannot be transferred on-chain.
16+
*/
17+
readonly nonTransferable?: boolean;
1418
}
1519

1620
/**

0 commit comments

Comments
 (0)