Skip to content

Commit

Permalink
lfix
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonioVentilii committed Feb 3, 2025
1 parent 8af9598 commit 959c2fb
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 65 deletions.
26 changes: 18 additions & 8 deletions src/frontend/src/lib/components/manage/ManageTokensModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@
import type { Network } from '$lib/types/network';
import type { TokenMetadata } from '$lib/types/token';
import { isNullishOrEmpty } from '$lib/utils/input.utils';
import { isNetworkIdEthereum, isNetworkIdICP, isNetworkIdSolana } from '$lib/utils/network.utils';
import {
isNetworkIdEthereum,
isNetworkIdICP,
isNetworkIdSolana,
isNetworkIdSOLDevnet
} from '$lib/utils/network.utils';
import SolAddTokenReview from '$sol/components/tokens/SolAddTokenReview.svelte';
import { saveSplUserTokens } from '$sol/services/manage-tokens.services';
import type { SolanaNetwork } from '$sol/types/network';
import type { SplTokenToggleable } from '$sol/types/spl-token-toggleable';
import type { SaveSplUserToken } from '$sol/types/spl-user-token';
const steps: WizardSteps = [
{
Expand Down Expand Up @@ -79,7 +82,16 @@
await Promise.allSettled([
...(icrc.length > 0 ? [saveIcrc(icrc.map((t) => ({ ...t, networkKey: 'Icrc' })))] : []),
...(erc20.length > 0 ? [saveErc20(erc20)] : []),
...(spl.length > 0 ? [saveSpl(spl)] : [])
...(spl.length > 0
? [
saveSpl(
spl.map((t) => ({
...t,
networkKey: isNetworkIdSOLDevnet(t.network.id) ? 'SplDevnet' : 'SplMainnet'
}))
)
]
: [])
]);
};
Expand Down Expand Up @@ -145,7 +157,7 @@
{
address: splTokenAddress,
...splMetadata,
network: network as SolanaNetwork,
networkKey: isNetworkIdSOLDevnet(network?.id) ? 'SplDevnet' : 'SplMainnet',
enabled: true
}
]);
Expand Down Expand Up @@ -173,8 +185,7 @@
identity: $authIdentity
});
// TODO: implement this function in the backend
const saveSpl = (tokens: SaveCustomTokenWithKey[]): void => {
const saveSpl = (tokens: SaveCustomTokenWithKey[]): Promise<void> =>
saveSplUserTokens({
tokens,
progress,
Expand All @@ -183,7 +194,6 @@
onError: () => modal.set(0),
identity: $authIdentity
});
};
const close = () => {
modalStore.close();
Expand Down
138 changes: 87 additions & 51 deletions src/frontend/src/sol/services/spl.services.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { SOLANA_MAINNET_NETWORK } from '$env/networks/networks.sol.env';
import type { CustomToken } from '$declarations/backend/backend.did';
import { SOLANA_DEVNET_NETWORK, SOLANA_MAINNET_NETWORK } from '$env/networks/networks.sol.env';
import { SOLANA_DEFAULT_DECIMALS } from '$env/tokens/tokens.sol.env';
import { SPL_TOKENS } from '$env/tokens/tokens.spl.env';
import { queryAndUpdate } from '$lib/actors/query.ic';
import { listCustomTokens, setManyCustomTokens } from '$lib/api/backend.api';
Expand Down Expand Up @@ -26,7 +28,7 @@ import type { SplTokenAddress } from '$sol/types/spl';
import type { SplUserToken } from '$sol/types/spl-user-token';
import { mapNetworkIdToNetwork } from '$sol/utils/network.utils';
import type { Identity } from '@dfinity/agent';
import { assertNonNullish, isNullish, nonNullish } from '@dfinity/utils';
import { assertNonNullish, fromNullable, isNullish, nonNullish } from '@dfinity/utils';
import { get } from 'svelte/store';

export const loadSplTokens = async ({ identity }: { identity: OptionIdentity }): Promise<void> => {
Expand Down Expand Up @@ -75,36 +77,49 @@ export const loadSplUserTokens = ({ identity }: { identity: OptionIdentity }): P
// The release before this change was v0.22.0, as reference.
// TODO: remove this function and its usage starting from the 1st of March 2025
const saveCachedUserTokensToBackend = async ({
identity
identity,
savedTokens
}: {
identity: Identity;
savedTokens: CustomToken[];
}): Promise<void> => {
const savedTokenAddresses = savedTokens.reduce<SplTokenAddress[]>(
(acc, { token }) => [
...acc,
...('SplMainnet' in token ? [token.SplMainnet.token_address] : [])
],
[]
);

const contractsMap: SplAddressMap = getStorage<SplAddressMap>({ key: SPL_USER_TOKENS_KEY }) ?? {};
const principal = identity.getPrincipal().toString();
const contracts = nonNullish(principal) ? (contractsMap[principal] ?? []) : [];

const tokens = await Promise.all(
contracts.map(async (address) => {
const network = SOLANA_MAINNET_NETWORK;
const tokens = [];

const solNetwork = mapNetworkIdToNetwork(network.id);
// We are using a for loop instead of a functional approach to avoid the async/await issue due to the limit of the Quicknode API calls.
// This is acceptable since this is just a temporary solution that shall be removed soon.
for (const address of contracts.filter((address) => !savedTokenAddresses.includes(address))) {
const network = SOLANA_MAINNET_NETWORK;
const solNetwork = mapNetworkIdToNetwork(network.id);

assertNonNullish(
solNetwork,
replacePlaceholders(get(i18n).init.error.no_solana_network, {
$network: network.id.description ?? ''
})
);
assertNonNullish(
solNetwork,
replacePlaceholders(get(i18n).init.error.no_solana_network, {
$network: network.id.description ?? ''
})
);

const metadata = await getSplMetadata({ address, network: solNetwork });
const metadata = await getSplMetadata({ address, network: solNetwork });

return {
address,
enabled: true,
...metadata
};
})
);
await new Promise((resolve) => setTimeout(resolve, 1000));

tokens.push({
address,
enabled: true,
...metadata
});
}

await setManyCustomTokens({
identity,
Expand All @@ -116,17 +131,14 @@ const saveCachedUserTokensToBackend = async ({
const loadSplCustomTokens = async (params: {
identity: OptionIdentity;
certified: boolean;
}): Promise<SplTokenAddress[]> => {
}): Promise<CustomToken[]> => {
const tokens = await listCustomTokens({
...params,
nullishIdentityErrorMessage: get(i18n).auth.error.no_internet_identity
});

// We filter the custom tokens that are Spl (the backend "Custom Token" potentially supports other types).
return tokens.reduce<SplTokenAddress[]>(
(acc, { token }) => ('SplMainnet' in token ? [...acc, token.SplMainnet.token_address] : acc),
[]
);
return tokens.filter(({ token }) => 'SplMainnet' in token);
};

export const loadUserTokens = async ({
Expand All @@ -140,33 +152,63 @@ export const loadUserTokens = async ({
return [];
}

await saveCachedUserTokensToBackend({ identity });
const splCustomTokens = await loadSplCustomTokens({ identity, certified: true });

const splCustomTokenAddresses = await loadSplCustomTokens({ identity, certified: true });
await saveCachedUserTokensToBackend({ identity, savedTokens: splCustomTokens });

const [existingTokens, userTokenAddresses] = splCustomTokenAddresses.reduce<
[SplUserToken[], SplTokenAddress[]]
const [existingTokens, nonExistingTokens] = splCustomTokens.reduce<
[SplUserToken[], SplUserToken[]]
>(
([accExisting, accUser], address) => {
const existingTokens = SPL_TOKENS.reduce<SplUserToken[]>(
(acc, token) =>
splCustomTokenAddresses.includes(token.address)
? [...acc, { ...token, enabled: true }]
: acc,
[]
([accExisting, accNonExisting], { token, enabled, version: versionNullable }) => {
if (!('SplMainnet' in token || 'SplDevnet' in token)) {
return [accExisting, accNonExisting];
}

const version = fromNullable(versionNullable);

const {
network: tokenNetwork,
symbol,
decimals,
token_address: tokenAddress
} = 'SplDevnet' in token
? { ...token.SplDevnet, network: SOLANA_DEVNET_NETWORK }
: { ...token.SplMainnet, network: SOLANA_MAINNET_NETWORK };

const existingToken = SPL_TOKENS.find(
({ address, network: { id: networkId } }) =>
address === tokenAddress && networkId === tokenNetwork.id
);

return existingTokens.length > 0
? [[...accExisting, ...existingTokens], accUser]
: [accExisting, [...accUser, address]];
if (nonNullish(existingToken)) {
return [[...accExisting, { ...existingToken, enabled, version }], accNonExisting];
}

return [
accExisting,
[
...accNonExisting,
{
id: parseTokenId(`custom-token#${fromNullable(symbol)}#${tokenNetwork.chainId}`),
name: tokenAddress,
address: tokenAddress,
network: tokenNetwork,
symbol: fromNullable(symbol) ?? '',
decimals: fromNullable(decimals) ?? SOLANA_DEFAULT_DECIMALS,
standard: 'spl' as const,
category: 'custom' as const,
enabled,
version
}
]
];
},
[[], []]
);

const userTokens = await Promise.all(
userTokenAddresses.map(async (address) => {
// TODO: add checks for the network, when we have the backend
const network = SOLANA_MAINNET_NETWORK;
const userTokens: SplUserToken[] = await Promise.all(
nonExistingTokens.map(async (token) => {
const { network, address } = token;

const solNetwork = mapNetworkIdToNetwork(network.id);

Expand All @@ -180,17 +222,11 @@ export const loadUserTokens = async ({
const metadata = await getSplMetadata({ address, network: solNetwork });

return {
id: parseTokenId(`user-token#${metadata.symbol}#${network.chainId}`),
network,
address,
standard: 'spl' as const,
category: 'custom' as const,
enabled: true,
...token,
...metadata
};
})
);

return [...existingTokens, ...userTokens];
};

Expand Down
6 changes: 0 additions & 6 deletions src/frontend/src/sol/types/spl-user-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,3 @@ import type { UserToken } from '$lib/types/user-token';
import type { SplToken } from '$sol/types/spl';

export type SplUserToken = UserToken<SplToken>;

export type SaveSplUserToken = Pick<
SplUserToken,
'enabled' | 'version' | 'symbol' | 'decimals' | 'address' | 'network'
> &
Partial<Pick<SplUserToken, 'id'>>;

0 comments on commit 959c2fb

Please sign in to comment.