diff --git a/packages/desktop/features/onboarding.features.ts b/packages/desktop/features/onboarding.features.ts index d7bc4104e2..41d31406ef 100644 --- a/packages/desktop/features/onboarding.features.ts +++ b/packages/desktop/features/onboarding.features.ts @@ -41,6 +41,9 @@ const onboardingFeaturesForIota: IOnboardingFeaturesForNetwork = { enabled: false, }, }, + defaultIscChains: { + enabled: false, + }, } const onboardingFeaturesForShimmer: IOnboardingFeaturesForNetwork = { @@ -82,6 +85,9 @@ const onboardingFeaturesForShimmer: IOnboardingFeaturesForNetwork = { enabled: true, }, }, + defaultIscChains: { + enabled: true, + }, } const onboardingFeaturesForTestnet: IOnboardingFeaturesForNetwork = { @@ -123,6 +129,9 @@ const onboardingFeaturesForTestnet: IOnboardingFeaturesForNetwork = { enabled: true, }, }, + defaultIscChains: { + enabled: true, + }, } const onboardingFeaturesForCustom: IOnboardingFeaturesForNetwork = { @@ -164,6 +173,9 @@ const onboardingFeaturesForCustom: IOnboardingFeaturesForNetwork = { enabled: true, }, }, + defaultIscChains: { + enabled: false, + }, } const onboardingFeatures: OnboardingFeatures = { diff --git a/packages/desktop/views/dashboard/send-flow/views/components/EvmTransactionSummary.svelte b/packages/desktop/views/dashboard/send-flow/views/components/EvmTransactionSummary.svelte index 2ba3cf3302..b15e9c1a0d 100644 --- a/packages/desktop/views/dashboard/send-flow/views/components/EvmTransactionSummary.svelte +++ b/packages/desktop/views/dashboard/send-flow/views/components/EvmTransactionSummary.svelte @@ -1,14 +1,16 @@ diff --git a/packages/shared/src/components/avatars/NetworkAvatar.svelte b/packages/shared/src/components/avatars/NetworkAvatar.svelte index c430402e4a..a490e99c9d 100644 --- a/packages/shared/src/components/avatars/NetworkAvatar.svelte +++ b/packages/shared/src/components/avatars/NetworkAvatar.svelte @@ -13,6 +13,7 @@ [SupportedNetworkId.Iota]: '#000000', [SupportedNetworkId.Shimmer]: 'shimmer-background', [SupportedNetworkId.Testnet]: 'shimmer-background', + [SupportedNetworkId.IotaEvm]: '#0A0FB0', [SupportedNetworkId.ShimmerEvm]: 'shimmer-background', [SupportedNetworkId.TestnetEvm]: 'text-secondary', } @@ -21,6 +22,7 @@ [SupportedNetworkId.Iota]: '#FFFFFF', [SupportedNetworkId.Shimmer]: 'shimmer', [SupportedNetworkId.Testnet]: 'text-secondary', + [SupportedNetworkId.IotaEvm]: '#FFFFFF', [SupportedNetworkId.ShimmerEvm]: 'text-invert', [SupportedNetworkId.TestnetEvm]: 'shimmer-background', } diff --git a/packages/shared/src/components/avatars/TokenAvatar.svelte b/packages/shared/src/components/avatars/TokenAvatar.svelte index 04739d2934..cc3a2f499a 100644 --- a/packages/shared/src/components/avatars/TokenAvatar.svelte +++ b/packages/shared/src/components/avatars/TokenAvatar.svelte @@ -23,6 +23,9 @@ [SupportedNetworkId.Testnet]: { [BASE_TOKEN_ID]: 'shimmer', }, + [SupportedNetworkId.IotaEvm]: { + [BASE_TOKEN_ID]: '#000000', + }, [SupportedNetworkId.ShimmerEvm]: { [BASE_TOKEN_ID]: 'shimmer', }, @@ -41,6 +44,9 @@ [SupportedNetworkId.Testnet]: { [BASE_TOKEN_ID]: 'shimmer-background', }, + [SupportedNetworkId.IotaEvm]: { + [BASE_TOKEN_ID]: '#FFFFFF', + }, [SupportedNetworkId.ShimmerEvm]: { [BASE_TOKEN_ID]: 'shimmer-background', }, diff --git a/packages/shared/src/lib/auxiliary/icon/constants/default-network-icon.ts b/packages/shared/src/lib/auxiliary/icon/constants/default-network-icon.ts index 7f60528247..f3fce1ede5 100644 --- a/packages/shared/src/lib/auxiliary/icon/constants/default-network-icon.ts +++ b/packages/shared/src/lib/auxiliary/icon/constants/default-network-icon.ts @@ -5,6 +5,7 @@ export const DEFAULT_NETWORK_ICON: { [id in NetworkId]?: IconName } = { [SupportedNetworkId.Iota]: IconName.Iota, [SupportedNetworkId.Shimmer]: IconName.Shimmer, [SupportedNetworkId.Testnet]: IconName.Shimmer, + [SupportedNetworkId.IotaEvm]: IconName.Iota, [SupportedNetworkId.ShimmerEvm]: IconName.Shimmer, [SupportedNetworkId.TestnetEvm]: IconName.Shimmer, } diff --git a/packages/shared/src/lib/auxiliary/icon/constants/default-token-icon.ts b/packages/shared/src/lib/auxiliary/icon/constants/default-token-icon.ts index b84e1edb10..36e1b0d718 100644 --- a/packages/shared/src/lib/auxiliary/icon/constants/default-token-icon.ts +++ b/packages/shared/src/lib/auxiliary/icon/constants/default-token-icon.ts @@ -12,6 +12,9 @@ export const DEFAULT_TOKEN_ICON: { [networkId in NetworkId]?: { [tokenId: string [SupportedNetworkId.Testnet]: { [BASE_TOKEN_ID]: IconName.Shimmer, }, + [SupportedNetworkId.IotaEvm]: { + [BASE_TOKEN_ID]: IconName.Iota, + }, [SupportedNetworkId.ShimmerEvm]: { [BASE_TOKEN_ID]: IconName.Shimmer, }, diff --git a/packages/shared/src/lib/core/layer-2/actions/checkForUntrackedTokens.ts b/packages/shared/src/lib/core/layer-2/actions/checkForUntrackedTokens.ts index 1ba2ca6416..f0568e27f1 100644 --- a/packages/shared/src/lib/core/layer-2/actions/checkForUntrackedTokens.ts +++ b/packages/shared/src/lib/core/layer-2/actions/checkForUntrackedTokens.ts @@ -9,7 +9,7 @@ export function checkForUntrackedTokens(account: IAccountState, addPreviouslyUnt const evmNetworks = getEvmNetworks() evmNetworks?.forEach(async (evmNetwork) => { const evmAddress = account.evmAddresses[evmNetwork.coinType] - if (!evmAddress) { + if (!evmAddress || !evmNetwork.explorerUrl) { return } const networkId = evmNetwork.id diff --git a/packages/shared/src/lib/core/layer-2/actions/getGasFeeForLayer1ToLayer2Transaction.ts b/packages/shared/src/lib/core/layer-2/actions/getGasFeeForLayer1ToLayer2Transaction.ts index 11f7130476..441ca4cb1f 100644 --- a/packages/shared/src/lib/core/layer-2/actions/getGasFeeForLayer1ToLayer2Transaction.ts +++ b/packages/shared/src/lib/core/layer-2/actions/getGasFeeForLayer1ToLayer2Transaction.ts @@ -19,15 +19,18 @@ export async function getGasFeeForLayer1ToLayer2Transaction(sendFlowParameters: } try { - const gasEstimate = await getGasEstimateForIscCall(destinationNetworkId, sendFlowParameters) - return gasEstimate + const gasFeeEstimate = await getGasFeeEstimateForIscCall(destinationNetworkId, sendFlowParameters) + return gasFeeEstimate } catch (err) { console.error(err) return BigInt(FALLBACK_ESTIMATED_GAS[sendFlowParameters.type]) } } -async function getGasEstimateForIscCall(networkId: NetworkId, sendFlowParameters: SendFlowParameters): Promise { +async function getGasFeeEstimateForIscCall( + networkId: NetworkId, + sendFlowParameters: SendFlowParameters +): Promise { const iscChain = getIscChain(networkId) if (!iscChain) { return Promise.reject('Invalid network') @@ -35,7 +38,7 @@ async function getGasEstimateForIscCall(networkId: NetworkId, sendFlowParameters const account = getSelectedAccount() const tempOutput = await createStardustOutputFromSendFlowParameters(sendFlowParameters, account) const outputBytes = await outputHexBytes(tempOutput) - return iscChain.getGasEstimate(outputBytes) + return iscChain.getGasFeeEstimate(outputBytes) } function getTransferredAsset(sendFlowParameters: SendFlowParameters): TransferredAsset | undefined { diff --git a/packages/shared/src/lib/core/layer-2/actions/getLayer2MetadataForTransfer.ts b/packages/shared/src/lib/core/layer-2/actions/getLayer2MetadataForTransfer.ts index 134686eb75..cc8965b83c 100644 --- a/packages/shared/src/lib/core/layer-2/actions/getLayer2MetadataForTransfer.ts +++ b/packages/shared/src/lib/core/layer-2/actions/getLayer2MetadataForTransfer.ts @@ -16,15 +16,22 @@ export function getLayer2MetadataForTransfer(sendFlowParameters: SendFlowParamet const address = sendFlowParameters.recipient?.address ?? '' const encodedAddress = encodeAddress(address.toLowerCase(), iscChain) - const estimatedGas = sendFlowParameters.gasFee ?? BigInt(0) - const gasLimit = Math.floor(Number(estimatedGas) * GAS_LIMIT_MULTIPLIER) + const gasFee = sendFlowParameters.gasFee ?? BigInt(0) + const gasPerToken = iscChain.getMetadata()?.gasFeePolicy.gasPerToken + let gasLimit: number + if (gasPerToken) { + // More information can be found here: https://wiki.iota.org/isc/reference/core-contracts/governance/#ratio32 + gasLimit = (Number(gasFee) * gasPerToken['a']) / gasPerToken['b'] + } else { + gasLimit = Number(gasFee) * GAS_LIMIT_MULTIPLIER + } metadataStream.writeUInt8('senderContract', EXTERNALLY_OWNED_ACCOUNT) metadataStream.writeUInt32('targetContract', ACCOUNTS_CONTRACT) metadataStream.writeUInt32('contractFunction', TRANSFER_ALLOWANCE) // Gas budget is the ISC equivalent of gas limit in ethereum and what we use throughout the code - metadataStream.writeUInt64SpecialEncoding('gasLimit', BigInt(gasLimit)) + metadataStream.writeUInt64SpecialEncoding('gasLimit', BigInt(Math.floor(gasLimit))) const smartContractParameters = Object.entries({ a: encodedAddress }) const parameters = encodeSmartContractParameters(smartContractParameters) diff --git a/packages/shared/src/lib/core/layer-2/constants/index.ts b/packages/shared/src/lib/core/layer-2/constants/index.ts index 473e152128..2a4cb396f1 100644 --- a/packages/shared/src/lib/core/layer-2/constants/index.ts +++ b/packages/shared/src/lib/core/layer-2/constants/index.ts @@ -10,7 +10,6 @@ export * from './externally-owned-account.constant' export * from './fallback-estimated-gas.constant' export * from './gas-limit-multiplier.constant' export * from './isc-magic-contract-address.constant' -export * from './l2-to-l1-storage-deposit-buffer.constant' export * from './layer2-tokens-poll-interval.constant' export * from './target-contracts.constant' export * from './transfer-allowance.constant' diff --git a/packages/shared/src/lib/core/layer-2/constants/l2-to-l1-storage-deposit-buffer.constant.ts b/packages/shared/src/lib/core/layer-2/constants/l2-to-l1-storage-deposit-buffer.constant.ts deleted file mode 100644 index 47d113c005..0000000000 --- a/packages/shared/src/lib/core/layer-2/constants/l2-to-l1-storage-deposit-buffer.constant.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { SendFlowType } from '@core/wallet/enums' - -export const L2_TO_L1_STORAGE_DEPOSIT_BUFFER: { [key in SendFlowType]?: bigint } = { - [SendFlowType.TokenUnwrap]: BigInt(56_500), - [SendFlowType.NftUnwrap]: BigInt(3_500), -} diff --git a/packages/shared/src/lib/core/layer-2/utils/calculateEstimatedGasFeeFromTransactionData.ts b/packages/shared/src/lib/core/layer-2/utils/calculateEstimatedGasFeeFromTransactionData.ts index 0f5a80e878..5e4942e86c 100644 --- a/packages/shared/src/lib/core/layer-2/utils/calculateEstimatedGasFeeFromTransactionData.ts +++ b/packages/shared/src/lib/core/layer-2/utils/calculateEstimatedGasFeeFromTransactionData.ts @@ -1,11 +1,11 @@ import { EvmTransactionData } from '../types' import { calculateGasFeeInGlow } from '../helpers' -export function calculateEstimatedGasFeeFromTransactionData(transactionData: EvmTransactionData): bigint | undefined { +export function calculateEstimatedGasFeeFromTransactionData(transactionData: EvmTransactionData): bigint { const { estimatedGas, gasPrice } = transactionData if (estimatedGas && gasPrice) { return calculateGasFeeInGlow(estimatedGas, gasPrice) } else { - return undefined + return BigInt(0) } } diff --git a/packages/shared/src/lib/core/layer-2/utils/calculateMaxGasFeeFromTransactionData.ts b/packages/shared/src/lib/core/layer-2/utils/calculateMaxGasFeeFromTransactionData.ts index 4a857f1879..252cea9a20 100644 --- a/packages/shared/src/lib/core/layer-2/utils/calculateMaxGasFeeFromTransactionData.ts +++ b/packages/shared/src/lib/core/layer-2/utils/calculateMaxGasFeeFromTransactionData.ts @@ -1,11 +1,11 @@ import { EvmTransactionData } from '../types' import { calculateGasFeeInGlow } from '../helpers' -export function calculateMaxGasFeeFromTransactionData(transactionData: EvmTransactionData): bigint | undefined { +export function calculateMaxGasFeeFromTransactionData(transactionData: EvmTransactionData): bigint { const { gasLimit, gasPrice } = transactionData if (gasLimit && gasPrice) { return calculateGasFeeInGlow(gasLimit, gasPrice) } else { - return undefined + return BigInt(0) } } diff --git a/packages/shared/src/lib/core/layer-2/utils/fetchIscAssetsForAccount.ts b/packages/shared/src/lib/core/layer-2/utils/fetchIscAssetsForAccount.ts index c1693198ef..ebdb03e40e 100644 --- a/packages/shared/src/lib/core/layer-2/utils/fetchIscAssetsForAccount.ts +++ b/packages/shared/src/lib/core/layer-2/utils/fetchIscAssetsForAccount.ts @@ -49,6 +49,7 @@ async function getL2NativeTokenBalancesForAddress(evmAddress: string, iscChain: nativeTokenResult.items?.forEach((item) => (nativeTokens[item.key] = Converter.bigIntLikeToBigInt(item.value))) return nativeTokens } catch (e) { + console.error(e) return {} } } diff --git a/packages/shared/src/lib/core/layer-2/utils/getL2ToL1StorageDepositBuffer.ts b/packages/shared/src/lib/core/layer-2/utils/getL2ToL1StorageDepositBuffer.ts new file mode 100644 index 0000000000..6da08e294c --- /dev/null +++ b/packages/shared/src/lib/core/layer-2/utils/getL2ToL1StorageDepositBuffer.ts @@ -0,0 +1,35 @@ +import { StardustNetworkId, getStardustNetwork } from '@core/network' +import { DEFAULT_PROTOCOL } from '@core/network/constants' +import { SendFlowType } from '@core/wallet/enums' + +const L2_TO_L1_STORAGE_DEPOSIT_BUFFER_BYTES: { [key in UnwrapSendFlow]: bigint } = { + [SendFlowType.TokenUnwrap]: BigInt(565), + [SendFlowType.NftUnwrap]: BigInt(35), +} + +type UnwrapSendFlow = SendFlowType.TokenUnwrap | SendFlowType.NftUnwrap + +export function getL2ToL1StorageDepositBuffer(type: UnwrapSendFlow, networkId: StardustNetworkId): bigint { + const network = getStardustNetwork(networkId) + if (!network) { + return BigInt(0) + } + + const actualVByteCost = network.protocol.rentStructure.vByteCost + let expectedVByteCost = DEFAULT_PROTOCOL[networkId]?.rentStructure.vByteCost + + // TODO: Validate byte cost returned by node + if (!expectedVByteCost && !actualVByteCost) { + throw new Error(`Virtual byte cost for ${networkId} is undefined!`) + // } else if (!actualVByteCost) { + // throw new Error('Node does not return virtual byte cost') + } else if (!expectedVByteCost) { + expectedVByteCost = actualVByteCost + } + + // if (expectedVByteCost !== actualVByteCost) { + // throw new Error('Virtual byte cost from the node differs from the expected values') + // } + + return BigInt(expectedVByteCost) * L2_TO_L1_STORAGE_DEPOSIT_BUFFER_BYTES[type] +} diff --git a/packages/shared/src/lib/core/layer-2/utils/index.ts b/packages/shared/src/lib/core/layer-2/utils/index.ts index 6452d3c848..49538b45bf 100644 --- a/packages/shared/src/lib/core/layer-2/utils/index.ts +++ b/packages/shared/src/lib/core/layer-2/utils/index.ts @@ -13,6 +13,7 @@ export * from './getErc721TransferSmartContractData' export * from './getEvmTransactionFromHexString' export * from './getHexEncodedTransaction' export * from './getMethodForEvmTransaction' +export * from './getL2ToL1StorageDepositBuffer' export * from './isErcAsset' export * from './lookupMethodSignature' export * from './parseLayer2Metadata' diff --git a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts index 41c5fa7c4f..dbf9d08553 100644 --- a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts +++ b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts @@ -3,7 +3,6 @@ import { fetchIscAssetsForAccount } from '@core/layer-2/utils' import { NetworkType } from '@core/network/enums' import { getActiveProfileId } from '@core/profile/stores' import { ITokenBalance } from '@core/token/interfaces' -import { Converter } from '@core/utils' import { IIscChain, IIscChainConfiguration, IIscChainMetadata } from '../interfaces' import { EvmNetwork } from './evm-network.class' @@ -27,15 +26,18 @@ export class IscChain extends EvmNetwork implements IIscChain { this._chainApi = new URL(`v1/chains/${aliasAddress}`, apiEndpoint).href } - getMetadata(): Promise { - if (this._metadata) { - return Promise.resolve(this._metadata) - } else { - this._metadata = {} // await this.fetchChainMetadata() - return Promise.resolve(this._metadata) + async setMetadata(): Promise { + try { + this._metadata = await this.fetchChainMetadata() + } catch (err) { + console.error(err) } } + getMetadata(): IIscChainMetadata | undefined { + return this._metadata + } + /** * CAUTION: The API endpoint used by this method is not available * with the public ShimmerEVM node URL (b/c it's actually just @@ -59,9 +61,9 @@ export class IscChain extends EvmNetwork implements IIscChain { return { ...tokenBalance, ...iscBalance } } - async getGasEstimate(hex: string): Promise { + async getGasFeeEstimate(outputBytes: string): Promise { const URL = `${this._chainApi}/estimategas-onledger` - const body = JSON.stringify({ outputBytes: hex }) + const body = JSON.stringify({ outputBytes }) const requestInit: RequestInit = { method: 'POST', @@ -76,12 +78,12 @@ export class IscChain extends EvmNetwork implements IIscChain { const data = await response.json() if (response.status === 200) { - const gasEstimate = Converter.bigIntLikeToBigInt(data.gasFeeCharged) - if (gasEstimate === BigInt(0)) { - throw new Error(`Gas fee has an invalid value: ${gasEstimate}!`) + const gasFee = BigInt(data.gasFeeCharged) + if (gasFee === BigInt(0)) { + throw new Error(`Gas fee has an invalid value: ${gasFee}!`) } - return gasEstimate + return gasFee } else { throw new Error(data) } diff --git a/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts b/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts index 535dcb5a26..b138e035ed 100644 --- a/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts +++ b/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts @@ -31,10 +31,11 @@ export const EVM_BASE_TOKEN: IBaseToken = { decimals: 18, } -export const DEFAULT_BASE_TOKEN: Readonly<{ [id in NetworkId]?: IBaseToken }> = { +export const DEFAULT_BASE_TOKEN: Readonly<{ [id in NetworkId]: IBaseToken }> = { [SupportedNetworkId.Iota]: IOTA_BASE_TOKEN, [SupportedNetworkId.Shimmer]: SHIMMER_BASE_TOKEN, [SupportedNetworkId.Testnet]: SHIMMER_BASE_TOKEN, + [SupportedNetworkId.IotaEvm]: IOTA_BASE_TOKEN, [SupportedNetworkId.ShimmerEvm]: SHIMMER_BASE_TOKEN, [SupportedNetworkId.TestnetEvm]: SHIMMER_BASE_TOKEN, [SupportedNetworkId.Ethereum]: EVM_BASE_TOKEN, diff --git a/packages/shared/src/lib/core/network/constants/default-coin-type.constant.ts b/packages/shared/src/lib/core/network/constants/default-coin-type.constant.ts index 9d1e70bb52..4e99839e71 100644 --- a/packages/shared/src/lib/core/network/constants/default-coin-type.constant.ts +++ b/packages/shared/src/lib/core/network/constants/default-coin-type.constant.ts @@ -6,12 +6,13 @@ export const SHIMMER_COIN_TYPE = 4219 export const TEST_COIN_TYPE = 1 export const ETHEREUM_COIN_TYPE = 60 -export const DEFAULT_COIN_TYPE: Readonly<{ [id in NetworkId]?: number }> = { +export const DEFAULT_COIN_TYPE: Readonly<{ [key in NetworkId]: number }> = { [SupportedNetworkId.Iota]: IOTA_COIN_TYPE, [SupportedNetworkId.Shimmer]: SHIMMER_COIN_TYPE, [SupportedNetworkId.Testnet]: TEST_COIN_TYPE, - [SupportedNetworkId.Ethereum]: ETHEREUM_COIN_TYPE, - [SupportedNetworkId.Sepolia]: ETHEREUM_COIN_TYPE, + [SupportedNetworkId.IotaEvm]: ETHEREUM_COIN_TYPE, [SupportedNetworkId.ShimmerEvm]: ETHEREUM_COIN_TYPE, [SupportedNetworkId.TestnetEvm]: ETHEREUM_COIN_TYPE, + [SupportedNetworkId.Ethereum]: ETHEREUM_COIN_TYPE, + [SupportedNetworkId.Sepolia]: ETHEREUM_COIN_TYPE, } diff --git a/packages/shared/src/lib/core/network/constants/default-explorer-urls.constant.ts b/packages/shared/src/lib/core/network/constants/default-explorer-urls.constant.ts index b37f493469..80089e9471 100644 --- a/packages/shared/src/lib/core/network/constants/default-explorer-urls.constant.ts +++ b/packages/shared/src/lib/core/network/constants/default-explorer-urls.constant.ts @@ -5,6 +5,7 @@ export const DEFAULT_EXPLORER_URLS: Readonly<{ [key in NetworkId]?: string }> = [SupportedNetworkId.Iota]: 'https://explorer.iota.org', [SupportedNetworkId.Shimmer]: 'https://explorer.shimmer.network', [SupportedNetworkId.Testnet]: 'https://explorer.shimmer.network', + [SupportedNetworkId.IotaEvm]: 'https://explorer.evm.iota.org', [SupportedNetworkId.Ethereum]: 'https://eth.blockscout.com', [SupportedNetworkId.ShimmerEvm]: 'https://explorer.evm.shimmer.network', [SupportedNetworkId.TestnetEvm]: 'https://explorer.evm.testnet.shimmer.network', diff --git a/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts b/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts index 50e933c32f..513b7f9d33 100644 --- a/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts +++ b/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts @@ -1,35 +1,66 @@ import { NetworkType, NetworkNamespace, ChainId } from '../enums' import { IIscChainConfiguration } from '../interfaces' import { StardustNetworkId } from '../types' -import { SHIMMER_BASE_TOKEN } from './default-base-token.constant' +import { DEFAULT_BASE_TOKEN } from './default-base-token.constant' import { DEFAULT_COIN_TYPE } from './default-coin-type.constant' import { SupportedIscNetworkId, SupportedNetworkId, SupportedStardustNetworkId } from './supported-network-id.constant' +import { isFeatureEnabled } from '@lib/features/utils' + +const IOTA_EVM_CHAIN_CONFIGURATION: IIscChainConfiguration = { + id: SupportedIscNetworkId.IotaEvm, + type: NetworkType.Isc, + name: 'IOTA EVM', + chainId: ChainId.IotaEvm, + namespace: NetworkNamespace.Evm, + baseToken: DEFAULT_BASE_TOKEN[SupportedNetworkId.IotaEvm], + coinType: DEFAULT_COIN_TYPE[SupportedNetworkId.IotaEvm], + aliasAddress: + 'https://github.com/bloomwalletio/bloom-private/pull/17/files#diff-2e95221dbfb375be5e97b45bad40479c2b3f9a70efa14e66caa1b7fe37df8296', + rpcEndpoint: + 'https://github.com/bloomwalletio/bloom-private/pull/17/files#diff-2e95221dbfb375be5e97b45bad40479c2b3f9a70efa14e66caa1b7fe37df8296', + apiEndpoint: + 'https://github.com/bloomwalletio/bloom-private/pull/17/files#diff-2e95221dbfb375be5e97b45bad40479c2b3f9a70efa14e66caa1b7fe37df8296', + explorerUrl: + 'https://github.com/bloomwalletio/bloom-private/pull/17/files#diff-2e95221dbfb375be5e97b45bad40479c2b3f9a70efa14e66caa1b7fe37df8296', +} + +const SHIMMER_EVM_CHAIN_CONFIGURATION: IIscChainConfiguration = { + id: SupportedIscNetworkId.ShimmerEvm, + type: NetworkType.Isc, + name: 'Shimmer EVM', + chainId: ChainId.ShimmerEvm, + namespace: NetworkNamespace.Evm, + baseToken: DEFAULT_BASE_TOKEN[SupportedNetworkId.ShimmerEVM], + coinType: DEFAULT_COIN_TYPE[SupportedNetworkId.ShimmerEvm] ?? 0, + aliasAddress: 'smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s', + rpcEndpoint: 'https://json-rpc.evm.shimmer.network/', + apiEndpoint: 'https://api.evm.shimmer.network/', + explorerUrl: 'https://explorer.evm.shimmer.network/', +} + +// exported as used in tests +export const TESTNET_EVM_CHAIN_CONFIGURATION: IIscChainConfiguration = { + id: SupportedIscNetworkId.TestnetEvm, + type: NetworkType.Isc, + name: 'Testnet EVM', + chainId: ChainId.TestnetEvm, + namespace: NetworkNamespace.Evm, + baseToken: DEFAULT_BASE_TOKEN[SupportedNetworkId.TestnetEvm], + coinType: DEFAULT_COIN_TYPE[SupportedNetworkId.TestnetEvm] ?? 0, + aliasAddress: 'rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex', + rpcEndpoint: 'https://json-rpc.evm.testnet.shimmer.network/', + apiEndpoint: 'https://api.evm.testnet.shimmer.network/', + explorerUrl: 'https://explorer.evm.testnet.shimmer.network/', +} export const DEFAULT_ISC_CHAINS_CONFIGURATIONS: Readonly<{ [id in StardustNetworkId]?: IIscChainConfiguration }> = { - [SupportedStardustNetworkId.Shimmer]: { - id: SupportedIscNetworkId.ShimmerEvm, - type: NetworkType.Isc, - name: 'Shimmer EVM', - chainId: ChainId.ShimmerEvm, - namespace: NetworkNamespace.Evm, - baseToken: SHIMMER_BASE_TOKEN, - coinType: DEFAULT_COIN_TYPE[SupportedNetworkId.ShimmerEvm] ?? 0, - aliasAddress: 'smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s', - rpcEndpoint: 'https://json-rpc.evm.shimmer.network/', - apiEndpoint: 'https://api.evm.shimmer.network/', - explorerUrl: 'https://explorer.evm.shimmer.network/', - }, - [SupportedStardustNetworkId.Testnet]: { - id: SupportedIscNetworkId.TestnetEvm, - type: NetworkType.Isc, - name: 'Testnet EVM', - chainId: ChainId.TestnetEvm, - namespace: NetworkNamespace.Evm, - baseToken: SHIMMER_BASE_TOKEN, - coinType: DEFAULT_COIN_TYPE[SupportedNetworkId.TestnetEvm] ?? 0, - aliasAddress: 'rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex', - rpcEndpoint: 'https://json-rpc.evm.testnet.shimmer.network/', - apiEndpoint: 'https://api.evm.testnet.shimmer.network/', - explorerUrl: 'https://explorer.evm.testnet.shimmer.network/', - }, + ...(isFeatureEnabled('onboarding.iota.defaultIscChains') && { + [SupportedStardustNetworkId.Iota]: IOTA_EVM_CHAIN_CONFIGURATION, + }), + ...(isFeatureEnabled('onboarding.shimmer.defaultIscChains') && { + [SupportedStardustNetworkId.Shimmer]: SHIMMER_EVM_CHAIN_CONFIGURATION, + }), + ...(isFeatureEnabled('onboarding.testnet.defaultIscChains') && { + [SupportedStardustNetworkId.Testnet]: TESTNET_EVM_CHAIN_CONFIGURATION, + }), } diff --git a/packages/shared/src/lib/core/network/constants/explorer-endpoints.constant.ts b/packages/shared/src/lib/core/network/constants/explorer-endpoints.constant.ts index 282df70e1c..8067074838 100644 --- a/packages/shared/src/lib/core/network/constants/explorer-endpoints.constant.ts +++ b/packages/shared/src/lib/core/network/constants/explorer-endpoints.constant.ts @@ -24,6 +24,11 @@ export const EXPLORER_ENDPOINTS: Readonly<{ [key in NetworkId]?: { [key in Explo [ExplorerEndpoint.Foundry]: `testnet/${ExplorerEndpoint.Foundry}`, [ExplorerEndpoint.Address]: 'testnet/addr', }, + [SupportedNetworkId.IotaEvm]: { + [ExplorerEndpoint.Transaction]: 'tx', + [ExplorerEndpoint.Token]: ExplorerEndpoint.Token, + [ExplorerEndpoint.Address]: ExplorerEndpoint.Address, + }, [SupportedNetworkId.ShimmerEvm]: { [ExplorerEndpoint.Transaction]: 'tx', [ExplorerEndpoint.Token]: ExplorerEndpoint.Token, diff --git a/packages/shared/src/lib/core/network/constants/supported-network-id.constant.ts b/packages/shared/src/lib/core/network/constants/supported-network-id.constant.ts index b8b865c9a4..60f69f58df 100644 --- a/packages/shared/src/lib/core/network/constants/supported-network-id.constant.ts +++ b/packages/shared/src/lib/core/network/constants/supported-network-id.constant.ts @@ -15,6 +15,7 @@ export const SupportedL1EvmNetworkId: Record = { } export const SupportedIscNetworkId: Record = { + IotaEvm: `${NetworkNamespace.Evm}:${ChainId.IotaEvm}`, ShimmerEvm: `${NetworkNamespace.Evm}:${ChainId.ShimmerEvm}`, TestnetEvm: `${NetworkNamespace.Evm}:${ChainId.TestnetEvm}`, } diff --git a/packages/shared/src/lib/core/network/enums/chain-id.enum.ts b/packages/shared/src/lib/core/network/enums/chain-id.enum.ts index df85db568d..9ba80d7efa 100644 --- a/packages/shared/src/lib/core/network/enums/chain-id.enum.ts +++ b/packages/shared/src/lib/core/network/enums/chain-id.enum.ts @@ -1,4 +1,5 @@ export enum ChainId { + IotaEvm = '8822', Ethereum = '1', ShimmerEvm = '148', TestnetEvm = '1073', diff --git a/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts b/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts index 97b8dd4820..c00df3dc5e 100644 --- a/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts @@ -13,8 +13,9 @@ export interface IIscChain extends IEvmNetwork { apiEndpoint: string aliasAddress: string - getGasEstimate(hex: string): Promise - getMetadata(): Promise + getGasFeeEstimate(hex: string): Promise + getMetadata(): IIscChainMetadata | undefined + setMetadata(): Promise } export interface IEvmNetwork extends IBaseNetwork, IBaseNetworkMetadata { diff --git a/packages/shared/src/lib/core/network/stores/networks.store.ts b/packages/shared/src/lib/core/network/stores/networks.store.ts index 0b9b0d925c..d9fe024537 100644 --- a/packages/shared/src/lib/core/network/stores/networks.store.ts +++ b/packages/shared/src/lib/core/network/stores/networks.store.ts @@ -5,7 +5,7 @@ import features from '@features/features' import { IscChain, EvmNetwork, StardustNetwork } from '../classes' import { IEvmNetwork, IIscChain, IStardustNetwork } from '../interfaces' -import { EvmNetworkId, Network, NetworkId } from '../types' +import { EvmNetworkId, Network, NetworkId, StardustNetworkId } from '../types' import { NetworkType, NetworkNamespace } from '../enums' export const networks: Writable = writable([]) @@ -66,6 +66,12 @@ export function getL1Network(): IStardustNetwork { return l1Network } +export function getStardustNetwork(networkId: StardustNetworkId): IStardustNetwork | undefined { + return get(networks)?.find( + (network) => network.namespace === NetworkNamespace.Stardust && network.id === networkId + ) as IStardustNetwork +} + export function getEvmNetworks(): IEvmNetwork[] { return (get(networks)?.filter((network) => network.namespace === NetworkNamespace.Evm) as IEvmNetwork[]) ?? [] } diff --git a/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts b/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts index 6e16d26464..f13575a7cd 100644 --- a/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts +++ b/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts @@ -23,7 +23,7 @@ export async function checkForUntrackedNfts(account: IAccountState): Promise { const networks = getEvmNetworks() for (const network of networks) { + if (!network.explorerUrl) { + continue + } + const networkId = network.id for (const account of accounts) { try { diff --git a/packages/shared/src/lib/core/wallet/actions/send/createEvmToStardustTransaction.ts b/packages/shared/src/lib/core/wallet/actions/send/createEvmToStardustTransaction.ts index 4738ac6339..a05bd5b842 100644 --- a/packages/shared/src/lib/core/wallet/actions/send/createEvmToStardustTransaction.ts +++ b/packages/shared/src/lib/core/wallet/actions/send/createEvmToStardustTransaction.ts @@ -1,10 +1,10 @@ import { IAccountState } from '@core/account/interfaces' import { localize } from '@core/i18n' import { buildUnwrapAssetParameters } from '@core/layer-2/actions' -import { ISC_MAGIC_CONTRACT_ADDRESS, L2_TO_L1_STORAGE_DEPOSIT_BUFFER } from '@core/layer-2/constants' +import { ISC_MAGIC_CONTRACT_ADDRESS } from '@core/layer-2/constants' import { AssetType, ContractType, EvmErrorMessage } from '@core/layer-2/enums' import { EvmTransactionData, TransferredAsset } from '@core/layer-2/types' -import { buildAssetAllowance, buildEvmTransactionData } from '@core/layer-2/utils' +import { buildAssetAllowance, buildEvmTransactionData, getL2ToL1StorageDepositBuffer } from '@core/layer-2/utils' import { ETHEREUM_COIN_TYPE } from '@core/network/constants' import { IEvmNetwork } from '@core/network/interfaces' @@ -15,6 +15,7 @@ import { TokenStandard } from '@core/token/enums' import { IIrc27Nft } from '@core/nfts' import { getTokenBalance } from '@core/token/actions' import { IError } from '@core/error' +import { StardustNetworkId } from '@core/network' export async function createEvmToStardustTransaction( sendFlowParameters: SendFlowParameters, @@ -30,17 +31,18 @@ export async function createEvmToStardustTransaction( const { targetAddress, adjustMinimumStorageDeposit, sendMetadata, sendOptions } = buildUnwrapAssetParameters(recipientAddress) - let transferredAsset: TransferredAsset | undefined let storageDepositRequired = BigInt(0) - if ( - sendFlowParameters.type === SendFlowType.TokenTransfer || - sendFlowParameters.type === SendFlowType.BaseCoinTransfer - ) { + + const { type, destinationNetworkId } = sendFlowParameters + if (type === SendFlowType.TokenTransfer || type === SendFlowType.BaseCoinTransfer) { const { token, amount } = getAmountAndTokenFromSendFlowParameters(sendFlowParameters) const isBaseCoin = token?.standard === TokenStandard.BaseToken const assetType = isBaseCoin ? AssetType.BaseCoin : AssetType.Token - storageDepositRequired = L2_TO_L1_STORAGE_DEPOSIT_BUFFER[SendFlowType.TokenUnwrap] ?? BigInt(0) + storageDepositRequired = getL2ToL1StorageDepositBuffer( + SendFlowType.TokenUnwrap, + destinationNetworkId as StardustNetworkId + ) transferredAsset = token && amount ? { type: assetType, token, amount } : undefined if (token?.standard === TokenStandard.BaseToken && amount) { const availableBalance = getTokenBalance(token.id, evmNetwork.id)?.available ?? BigInt(0) @@ -50,7 +52,7 @@ export async function createEvmToStardustTransaction( const nft = sendFlowParameters.nft as IIrc27Nft storageDepositRequired = (nft?.storageDeposit ?? BigInt(0)) + - (L2_TO_L1_STORAGE_DEPOSIT_BUFFER[SendFlowType.NftUnwrap] ?? BigInt(0)) + getL2ToL1StorageDepositBuffer(SendFlowType.NftUnwrap, destinationNetworkId as StardustNetworkId) transferredAsset = nft ? { type: AssetType.Nft, nft } : undefined } diff --git a/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts b/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts index 4d701d3538..3124ad73a5 100644 --- a/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts +++ b/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts @@ -1,5 +1,6 @@ import { FALLBACK_ESTIMATED_GAS } from '@core/layer-2/constants' -import { DEFAULT_ISC_CHAINS_CONFIGURATIONS, SupportedNetworkId } from '@core/network/constants' +import { TESTNET_EVM_CHAIN_CONFIGURATION, SupportedNetworkId } from '@core/network/constants' +import { IscChain } from '@core/network/classes' import { getOutputParameters } from '../utils' import { ReturnStrategy, SubjectType } from '../enums' import { IToken, IPersistedToken } from '@core/token/interfaces' @@ -32,7 +33,7 @@ const nativeTokenAsset: IToken = { verification: { verified: true, status: VerifiedStatus.SelfVerified }, } -const destinationNetwork = DEFAULT_ISC_CHAINS_CONFIGURATIONS[SupportedNetworkId.Testnet] +const destinationNetwork = new IscChain(TESTNET_EVM_CHAIN_CONFIGURATION) const nftId = '0xcd9430ff870a22f81f92428e5c06975fa3ec1a993331aa3db9fb2298e931ade1' const surplus = '50000' @@ -227,7 +228,7 @@ describe('File: getOutputParameters.ts', () => { ...baseTransaction, expirationDate, destinationNetworkId: destinationNetwork.id, - gasFee, + gasFee: BigInt(gasFee), } const output = getOutputParameters(sendFlowParameters, senderAddress) const expectedOutput = { @@ -259,7 +260,7 @@ describe('File: getOutputParameters.ts', () => { rawAmount: BigInt(amount), }, destinationNetworkId: destinationNetwork.id, - gasFee, + gasFee: BigInt(gasFee), } const output = getOutputParameters(sendFlowParameters, senderAddress) @@ -291,7 +292,7 @@ describe('File: getOutputParameters.ts', () => { recipient: baseTransaction.recipient, nft: testNft, destinationNetworkId: destinationNetwork.id, - gasFee, + gasFee: BigInt(gasFee), } const output = getOutputParameters(sendFlowParameters, senderAddress) diff --git a/packages/shared/src/lib/features/interfaces/onboarding-features-for-network.interface.ts b/packages/shared/src/lib/features/interfaces/onboarding-features-for-network.interface.ts index ae3c63f411..6fc84fc93c 100644 --- a/packages/shared/src/lib/features/interfaces/onboarding-features-for-network.interface.ts +++ b/packages/shared/src/lib/features/interfaces/onboarding-features-for-network.interface.ts @@ -17,4 +17,5 @@ export interface IOnboardingFeaturesForNetwork extends IFeatureFlag { strongholdBackup: IFeatureFlag ledgerBackup: IFeatureFlag } + defaultIscChains: IFeatureFlag } diff --git a/packages/shared/src/lib/features/types/onboarding-features.type.ts b/packages/shared/src/lib/features/types/onboarding-features.type.ts index 3f35ce59e7..17efeb4a06 100644 --- a/packages/shared/src/lib/features/types/onboarding-features.type.ts +++ b/packages/shared/src/lib/features/types/onboarding-features.type.ts @@ -2,7 +2,7 @@ import { OnboardingNetworkType } from '@contexts/onboarding/enums' import { IFeatureFlag, IOnboardingFeaturesForNetwork } from '../interfaces' export type OnboardingFeatures = IFeatureFlag & { - [key in OnboardingNetworkType]?: IOnboardingFeaturesForNetwork & IFeatureFlag + [key in OnboardingNetworkType]: IOnboardingFeaturesForNetwork & IFeatureFlag } & { importFromThirdParty: IFeatureFlag strongholdVersionCheck: IFeatureFlag diff --git a/packages/shared/src/lib/features/utils/index.ts b/packages/shared/src/lib/features/utils/index.ts new file mode 100644 index 0000000000..29563dad5d --- /dev/null +++ b/packages/shared/src/lib/features/utils/index.ts @@ -0,0 +1 @@ +export * from './isFeatureEnabled' diff --git a/packages/shared/src/lib/features/utils/isFeatureEnabled.ts b/packages/shared/src/lib/features/utils/isFeatureEnabled.ts new file mode 100644 index 0000000000..400afdaffa --- /dev/null +++ b/packages/shared/src/lib/features/utils/isFeatureEnabled.ts @@ -0,0 +1,19 @@ +import featuresObject from '@features/features' + +export function isFeatureEnabled(featureString: string, recursive: boolean = true): boolean { + const featurePathToCheck = featureString.split('.') + let previousFeatures = featuresObject + for (let i = 0; i < featurePathToCheck.length; i++) { + const currentFeature = previousFeatures[featurePathToCheck[i]] + + if (i === featurePathToCheck.length - 1 && currentFeature?.enabled) { + return true + } + + if (recursive && !currentFeature?.enabled) { + return false + } + previousFeatures = currentFeature + } + return false +}