Skip to content

Fixed an issue where offer preview dialog incorrectly identified CATs as NFTs #2655

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/api/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export { default as english } from './english';
export { default as optionsForPlotter } from './optionsForPlotter';
export { default as toCamelCase } from './toCamelCase';
export { default as toSnakeCase } from './toSnakeCase';
export { default as toBech32m, fromBech32m, decodeBech32m } from './toBech32m';
export { default as toBech32m, fromBech32m, decodeBech32m, removePrefix } from './toBech32m';
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ export default function WalletConnectCreateOfferPreview(props: WalletConnectOffe
const openDialog = useOpenDialog();

const fee = parseFee(values.fee);
const driverDict = values.driverDict as Record<string, any> | undefined;

const offerBuilderData: OfferBuilderData | undefined = useMemo(() => {
if (isLoadingAssetIdNames) {
return undefined;
}

return createOfferForIdsToOfferBuilderData(value, lookupByWalletId, fee);
}, [value, lookupByWalletId, isLoadingAssetIdNames, fee]);
return createOfferForIdsToOfferBuilderData(value, lookupByWalletId, fee, driverDict);
}, [value, lookupByWalletId, isLoadingAssetIdNames, fee, driverDict]);

async function handleShowPreview() {
const offerBuilderDataResult = await openDialog(<OfferBuilderViewerDialog offerBuilderData={offerBuilderData} />);
Expand Down
5 changes: 3 additions & 2 deletions packages/gui/src/constants/WalletConnectCommands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -394,15 +394,16 @@ const walletConnectCommands: WalletConnectCommand[] = [
name: WalletConnectCommandParamName.OFFER,
label: <Trans>Wallet Ids and Amounts</Trans>,
type: 'object',
displayComponent: (value, params, values, onChange) => (
<WalletConnectCreateOfferPreview value={value} params={params} values={values} onChange={onChange} />
displayComponent: (value, _params, values, onChange) => (
<WalletConnectCreateOfferPreview value={value} values={values} onChange={onChange} />
),
},
{
name: WalletConnectCommandParamName.DRIVER_DICT,
label: <Trans>Driver Dict</Trans>,
type: 'object',
displayComponent: (value) => <>{JSON.stringify(value)}</>,
isOptional: true,
},
{
name: WalletConnectCommandParamName.VALIDATE_ONLY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ describe('createOfferForIdsToOfferBuilderData', () => {
});
});
});
describe('when offering XCH for an NFT', () => {

describe('when requesting an unknown CAT for XCH', () => {
it('should return a valid offer builder data object', () => {
const calledLookupByWalletIdWithIds: string[] = [];
const assetIdMapEntriesByWalletId: Record<string, AssetIdMapEntry> = {
Expand All @@ -165,22 +166,93 @@ describe('createOfferForIdsToOfferBuilderData', () => {
};

const walletIdsAndAmounts = {
1: -3_000_000_000_000,
'8d3ed4c44a1ad053907044f12c8ba0f6a4fdad4eeff585ec76580b50a8de3d2d': 1,
1: -2_000_000_000_000,
f17f88130c63522821f1a75466849354eee69c414c774bd9f3873ab643e9574d: 1234,
};

chiaCore.mojoToChia.mockReturnValue(new BigNumber(3));
chiaCore.mojoToChia.mockReturnValue(new BigNumber(2));
chiaCore.mojoToCAT.mockReturnValue(new BigNumber(1.234));

const result = createOfferForIdsToOfferBuilderData(walletIdsAndAmounts, lookupByWalletId);

expect(calledLookupByWalletIdWithIds).toEqual([
'1',
'8d3ed4c44a1ad053907044f12c8ba0f6a4fdad4eeff585ec76580b50a8de3d2d',
'f17f88130c63522821f1a75466849354eee69c414c774bd9f3873ab643e9574d',
]);

expect(result).toEqual({
offered: {
xch: [
{
amount: '2',
},
],
tokens: [],
nfts: [],
fee: [],
},
requested: {
xch: [],
tokens: [
{
amount: '1.234',
assetId: 'f17f88130c63522821f1a75466849354eee69c414c774bd9f3873ab643e9574d',
},
],
nfts: [],
fee: [],
},
});
});
});

describe('when requesting an unknown NFT for XCH with a DriverDict', () => {
it('should return a valid offer builder data object', () => {
const calledLookupByWalletIdWithIds: string[] = [];
const assetIdMapEntriesByWalletId: Record<string, AssetIdMapEntry> = {
1: {
walletId: 1,
walletType: 0, // STANDARD_WALLET
isVerified: true,
name: 'Chia',
symbol: 'XCH',
displayName: 'XCH',
assetId: 'xch',
},
};

const lookupByWalletId = (walletId: string) => {
calledLookupByWalletIdWithIds.push(walletId);
return assetIdMapEntriesByWalletId[walletId];
};

const walletIdsAndAmounts = {
1: -2_000_000_000_000,
f17f88130c63522821f1a75466849354eee69c414c774bd9f3873ab643e9574d: 1,
};
const driverDict = {
f17f88130c63522821f1a75466849354eee69c414c774bd9f3873ab643e9574d: {
type: 'singleton' as const,
launcherId: '8d3ed4c44a1ad053907044f12c8ba0f6a4fdad4eeff585ec76580b50a8de3d2d',
},
};

chiaCore.mojoToChia.mockReturnValue(new BigNumber(2));

const result = createOfferForIdsToOfferBuilderData(walletIdsAndAmounts, lookupByWalletId, undefined, driverDict);

expect(calledLookupByWalletIdWithIds).toEqual([
'1',
'f17f88130c63522821f1a75466849354eee69c414c774bd9f3873ab643e9574d',
]);

expect(result).toEqual({
offered: {
xch: [{ amount: '3' }],
xch: [
{
amount: '2',
},
],
tokens: [],
nfts: [],
fee: [],
Expand All @@ -198,6 +270,7 @@ describe('createOfferForIdsToOfferBuilderData', () => {
});
});
});

describe('when the amount is NaN', () => {
it('should throw an error', () => {
const walletIdsAndAmounts = {
Expand Down
32 changes: 31 additions & 1 deletion packages/gui/src/util/createOfferForIdsToOfferBuilderData.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { toBech32m, WalletType } from '@chia-network/api';
import { WalletType, removePrefix } from '@chia-network/api';
import { mojoToChia, mojoToCAT } from '@chia-network/core';
import BigNumber from 'bignumber.js';

import OfferBuilderData from '../@types/OfferBuilderData';
import createDefaultValues from '../components/offers2/utils/createDefaultValues';
import { AssetIdMapEntry } from '../hooks/useAssetIdName';

import { launcherIdToNFTId } from './nfts';

export default function createOfferForIdsToOfferBuilderData(
walletIdsAndAmounts: Record<string, number>,
lookupByWalletId: (walletId: string) => AssetIdMapEntry | undefined,
fee?: string,
driverDict?: Record<string, { type: 'CAT'; tail: string } | { type: 'singleton'; launcherId: string }>,
): OfferBuilderData {
const offerBuilderData: OfferBuilderData = createDefaultValues();
Object.entries(walletIdsAndAmounts).forEach(([walletOrAssetId, amount]) => {
Expand Down Expand Up @@ -39,8 +42,35 @@ export default function createOfferForIdsToOfferBuilderData(
break;
}
} else {
if (driverDict) {
const driver = driverDict[walletOrAssetId];
if (driver) {
switch (driver.type) {
case 'CAT':
section.tokens.push({
amount: mojoToCAT(numericValue.abs()).toFixed(),
assetId: removePrefix(driver.tail, '0x'),
});
return;
case 'singleton': {
const nftId = launcherIdToNFTId(driver.launcherId);
section.nfts.push({ nftId });
return;
}
default:
break;
}
}
}
// If the asset is still unknown, treat it as a CAT
section.tokens.push({
amount: mojoToCAT(numericValue.abs()).toFixed(),
assetId: removePrefix(walletOrAssetId, '0x'),
});
/*
const nftId = toBech32m(walletOrAssetId, 'nft');
section.nfts.push({ nftId });
*/
}
} catch (e) {
console.error(e);
Expand Down