- {#if isSmartContractCall}
+ {#if !preparedTransaction.data}
+ {@const baseCoinTransfer = {
+ token: getTokenFromSelectedAccountTokens(BASE_TOKEN_ID, evmNetwork.id),
+ rawAmount: Converter.bigIntLikeToBigInt(preparedTransaction.value),
+ }}
+
+ {:else if parsedData?.type === ParsedSmartContractType.CoinTransfer}
+ {@const baseCoinTransfer = {
+ token: getTokenFromSelectedAccountTokens(BASE_TOKEN_ID, evmNetwork.id),
+ rawAmount: parsedData.rawAmount,
+ }}
+
+ {:else if parsedData?.type === ParsedSmartContractType.TokenTransfer}
+ {@const tokenTransfer = {
+ token: getTokenFromSelectedAccountTokens(parsedData.tokenId, evmNetwork.id),
+ rawAmount: parsedData.rawAmount,
+ }}
+
+ {:else if parsedData?.type === ParsedSmartContractType.NftTransfer}
+ {@const nft = getNftByIdForAccount($selectedAccount?.index, parsedData.nftId)}
+
+ {:else if parsedData?.type === ParsedSmartContractType.TokenApproval}
+
+
+
+ {:else if parsedData?.type === ParsedSmartContractType.SmartContract}
-
-
- {localize('popups.smartContractCall.unableToVerify')}
- onExplorerClick(String(preparedTransaction.to))}
- text={localize('popups.smartContractCall.viewSmartContract')}
- />
-
+
onExplorerClick(String(preparedTransaction.to)),
},
- { key: localize('general.methodName'), value: methodName },
- { key: localize('general.parameters'), value: inputs },
+ { key: localize('general.methodName'), value: parsedData.parsedMethod?.name },
+ {
+ key: localize('general.parameters'),
+ value: parsedData?.parsedMethod?.inputs.reduce((acc, input) => {
+ acc[input.name] = input.value
+ return acc
+ }, {}),
+ },
{ key: localize('general.data'), value: String(preparedTransaction.data), copyable: true },
]}
/>
-
+
- {:else}
-
{/if}
{
+ type: ParsedSmartContractType.TokenApproval
+ standard: TokenStandard.Erc20
+ spender: string
+ tokenId: string
+ rawAmount: bigint
+}
+
export interface IParsedSmartContractData {
type: ParsedSmartContractType.SmartContract
rawMethod: string
diff --git a/packages/shared/src/lib/core/layer-2/types/erc20-abi.type.ts b/packages/shared/src/lib/core/layer-2/types/erc20-abi.type.ts
new file mode 100644
index 0000000000..8d9acb2de1
--- /dev/null
+++ b/packages/shared/src/lib/core/layer-2/types/erc20-abi.type.ts
@@ -0,0 +1,42 @@
+import { IParsedInput } from '../interfaces'
+
+type Erc20KnownContractTypes = 'transfer' | 'approve'
+
+interface Erc20TransferMethod {
+ name: 'transfer'
+ inputs: {
+ _to: {
+ name: string
+ type: string
+ value: string
+ }
+ _value: {
+ name: string
+ type: string
+ value: string
+ }
+ }
+}
+
+interface Erc20ApproveMethod {
+ name: 'approve'
+ inputs: {
+ _spender: {
+ name: string
+ type: string
+ value: string
+ }
+ _value: {
+ name: string
+ type: string
+ value: string
+ }
+ }
+}
+
+interface Erc20UnknownMethod {
+ name: Exclude
+ inputs: Record
+}
+
+export type Erc20Abi = Erc20TransferMethod | Erc20ApproveMethod | Erc20UnknownMethod
diff --git a/packages/shared/src/lib/core/layer-2/types/erc721-abi.type.ts b/packages/shared/src/lib/core/layer-2/types/erc721-abi.type.ts
new file mode 100644
index 0000000000..ee37fa3a43
--- /dev/null
+++ b/packages/shared/src/lib/core/layer-2/types/erc721-abi.type.ts
@@ -0,0 +1,36 @@
+import { IParsedInput } from '../interfaces'
+
+type Erc721KnownContractTypes = 'safeTransferFrom'
+
+interface Erc721SafeTransferMethod {
+ name: 'safeTransferFrom'
+ inputs: {
+ from: {
+ name: string
+ type: string
+ value: string
+ }
+ to: {
+ name: string
+ type: string
+ value: string
+ }
+ tokenId: {
+ name: string
+ type: string
+ value: string
+ }
+ data?: {
+ name: string
+ type: string
+ value: string
+ }
+ }
+}
+
+interface Erc721UnknwonMethod {
+ name: Exclude
+ inputs: Record
+}
+
+export type Erc721Abi = Erc721SafeTransferMethod | Erc721UnknwonMethod
diff --git a/packages/shared/src/lib/core/layer-2/types/index.ts b/packages/shared/src/lib/core/layer-2/types/index.ts
index 9841e70a0d..f0f8846aba 100644
--- a/packages/shared/src/lib/core/layer-2/types/index.ts
+++ b/packages/shared/src/lib/core/layer-2/types/index.ts
@@ -1,5 +1,8 @@
+export * from './erc20-abi.type'
+export * from './erc721-abi.type'
export * from './evm-transaction-options.type'
export * from './evm-transaction-data.type'
+export * from './isc-abi.type'
export * from './layer-2-account-balance.type'
export * from './smart-contract.type'
export * from './transferred-asset.type'
diff --git a/packages/shared/src/lib/core/layer-2/types/isc-abi.type.ts b/packages/shared/src/lib/core/layer-2/types/isc-abi.type.ts
new file mode 100644
index 0000000000..884457dfda
--- /dev/null
+++ b/packages/shared/src/lib/core/layer-2/types/isc-abi.type.ts
@@ -0,0 +1,104 @@
+import { IParsedInput } from '../interfaces'
+import { ILayer2SendMetadataParameterParameters } from '../interfaces/layer-2-send-metadata-parameter-parameters.interface'
+import { ILayer2SendOptionsParameter } from '../interfaces/layer-2-send-options-parameter.interface'
+
+interface IscCallMethod {
+ name: 'call'
+ inputs: {
+ contractHname: {
+ name: string
+ type: string
+ value: string
+ }
+ entryPoint: {
+ name: string
+ type: string
+ value: string
+ }
+ params: {
+ name: string
+ type: string
+ value: {
+ items: {
+ key: string
+ value: string
+ }[]
+ }
+ }
+ allowance: {
+ name: string
+ type: string
+ value: {
+ baseTokens: string
+ nativeTokens: {
+ ID: {
+ data: string
+ }
+ amount: string
+ }[]
+ nfts: string[]
+ }
+ }
+ }
+}
+
+interface IscSendMethod {
+ name: 'send'
+ inputs: {
+ targetAddress: {
+ name: string
+ type: string
+ value: {
+ data: string
+ }
+ }
+ assets: {
+ name: string
+ type: string
+ value: {
+ baseTokens: string
+ nativeTokens: {
+ ID: {
+ data: string
+ }
+ amount: string
+ }[]
+ nfts: string[]
+ }
+ }
+ adjustMinimumStorageDeposit: boolean
+ metadata: {
+ name: string
+ type: string
+ value: {
+ targetContract: number
+ entrypoint: number
+ params: ILayer2SendMetadataParameterParameters[]
+ allowance: {
+ baseTokens: string
+ nativeTokens: {
+ ID: {
+ data: string
+ }
+ amount: string
+ }[]
+ nfts: string[]
+ }
+ gasBudget: number
+ }
+ }
+ sendOptions: {
+ name: string
+ type: string
+ value: ILayer2SendOptionsParameter
+ }
+ }
+}
+
+type IscKnownContractTypes = 'send' | 'call'
+
+interface IscUnknownMethod {
+ name: Exclude
+ inputs: Record
+}
+export type IscAbi = IscCallMethod | IscSendMethod | IscUnknownMethod
diff --git a/packages/shared/src/lib/core/layer-2/types/parsed-smart-contract-data.type.ts b/packages/shared/src/lib/core/layer-2/types/parsed-smart-contract-data.type.ts
index acf63a00de..0711de11cb 100644
--- a/packages/shared/src/lib/core/layer-2/types/parsed-smart-contract-data.type.ts
+++ b/packages/shared/src/lib/core/layer-2/types/parsed-smart-contract-data.type.ts
@@ -1,4 +1,5 @@
import {
+ IParsedTokenApproval,
IParsedCoinTransfer,
IParsedNftTransfer,
IParsedSmartContractData,
@@ -9,4 +10,5 @@ export type ParsedSmartContractData =
| IParsedCoinTransfer
| IParsedTokenTransfer
| IParsedNftTransfer
+ | IParsedTokenApproval
| IParsedSmartContractData
diff --git a/packages/shared/src/lib/core/layer-2/utils/parseSmartContractDataFromTransactionData.ts b/packages/shared/src/lib/core/layer-2/utils/parseSmartContractDataFromTransactionData.ts
index d67542176b..4f8f0e88cc 100644
--- a/packages/shared/src/lib/core/layer-2/utils/parseSmartContractDataFromTransactionData.ts
+++ b/packages/shared/src/lib/core/layer-2/utils/parseSmartContractDataFromTransactionData.ts
@@ -4,20 +4,14 @@ import { AbiDecoder, HEX_PREFIX } from '@core/utils'
import { isTrackedNftAddress, isTrackedTokenAddress } from '@core/wallet/actions'
import { ERC20_ABI, ERC721_ABI, ISC_SANDBOX_ABI } from '../abis'
import { ISC_BASE_COIN_ADDRESS, ISC_MAGIC_CONTRACT_ADDRESS } from '../constants'
-import {
- Erc20TransferMethodInputs,
- Erc721SafeTransferMethodInputs,
- IscCallMethodInputs,
- IscSendMethodInputs,
- IParsedMethod,
- IParsedInput,
-} from '../interfaces'
+import { IParsedMethod, IParsedInput } from '../interfaces'
import { BigIntLike, BytesLike } from '@ethereumjs/util'
import { lookupMethodSignature } from './lookupMethodSignature'
import { ParsedSmartContractData } from '../types/parsed-smart-contract-data.type'
import { ParsedSmartContractType } from '../enums'
import { TokenStandard } from '@core/token'
import { NftStandard } from '@core/nfts'
+import { Erc20Abi, Erc721Abi, IscAbi } from '../types'
export function parseSmartContractDataFromTransactionData(
transaction: { to?: string; data: BytesLike; value?: BigIntLike },
@@ -50,8 +44,8 @@ function parseSmartContractDataWithIscMagicAbi(
data: string,
recipientAddress: string
): ParsedSmartContractData | undefined {
- const iscMagicDecoder = new AbiDecoder(ISC_SANDBOX_ABI, network.provider)
- const decodedData = iscMagicDecoder.decodeData(data) // TODO: Type this return
+ const iscMagicDecoder = new AbiDecoder(ISC_SANDBOX_ABI, network.provider)
+ const decodedData = iscMagicDecoder.decodeData(data)
if (!decodedData) {
return undefined
@@ -69,7 +63,7 @@ function parseSmartContractDataWithIscMagicAbi(
return undefined
}
- const inputs = decodedData.inputs as unknown as IscCallMethodInputs
+ const inputs = decodedData.inputs
const nativeToken = inputs?.allowance?.value?.nativeTokens?.[0]
const nftId = inputs?.allowance?.value?.nfts?.[0]
const agentId = inputs?.params?.value.items?.find((item) => item.key === '0x61')?.value
@@ -106,7 +100,7 @@ function parseSmartContractDataWithIscMagicAbi(
return undefined
}
- const inputs = decodedData.inputs as unknown as IscSendMethodInputs
+ const inputs = decodedData.inputs
const assets = inputs.assets?.value
const nativeToken = assets?.nativeTokens?.[0]
@@ -157,8 +151,8 @@ function parseSmartContractDataWithErc20Abi(
data: string,
recipientAddress: string
): ParsedSmartContractData | undefined {
- const erc20Decoder = new AbiDecoder(ERC20_ABI, network.provider)
- const decodedData = erc20Decoder.decodeData(data) // TODO: Type this return
+ const erc20Decoder = new AbiDecoder(ERC20_ABI, network.provider)
+ const decodedData = erc20Decoder.decodeData(data)
if (!decodedData) {
return undefined
@@ -172,19 +166,28 @@ function parseSmartContractDataWithErc20Abi(
switch (decodedData.name) {
case 'transfer': {
- const inputs = decodedData.inputs as unknown as Erc20TransferMethodInputs
-
return {
type: ParsedSmartContractType.TokenTransfer,
standard: TokenStandard.Erc20,
tokenId: recipientAddress,
- rawAmount: BigInt(inputs._value.value),
+ rawAmount: BigInt(decodedData.inputs._value.value),
rawMethod,
parsedMethod,
- recipientAddress: inputs._to.value,
+ recipientAddress: decodedData.inputs._to.value,
+ }
+ }
+ case 'approve': {
+ return {
+ type: ParsedSmartContractType.TokenApproval,
+ standard: TokenStandard.Erc20,
+ tokenId: recipientAddress,
+ spender: decodedData.inputs._spender.value,
+ rawAmount: BigInt(decodedData.inputs._value.value),
+ rawMethod,
+ parsedMethod,
+ recipientAddress,
}
}
- // TODO: Support more ERC20 methods
default: {
return {
type: ParsedSmartContractType.SmartContract,
@@ -201,8 +204,8 @@ function parseSmartContractDataWithErc721Abi(
data: string,
recipientAddress: string
): ParsedSmartContractData | undefined {
- const erc721Decoder = new AbiDecoder(ERC721_ABI, network.provider)
- const decodedData = erc721Decoder.decodeData(data) // TODO: Type this return
+ const erc721Decoder = new AbiDecoder(ERC721_ABI, network.provider)
+ const decodedData = erc721Decoder.decodeData(data)
if (!decodedData) {
return undefined
@@ -217,7 +220,7 @@ function parseSmartContractDataWithErc721Abi(
switch (decodedData.name) {
case 'safeTransferFrom': {
// Enum?
- const inputs = decodedData.inputs as unknown as Erc721SafeTransferMethodInputs
+ const inputs = decodedData.inputs
return {
type: ParsedSmartContractType.NftTransfer,
@@ -276,6 +279,10 @@ function parseSmartContractDataWithMethodRegistry(
parsedMethod: { name, inputs },
}
} catch (error) {
- return undefined
+ return {
+ type: ParsedSmartContractType.SmartContract,
+ recipientAddress,
+ rawMethod: fourBytePrefix,
+ }
}
}
diff --git a/packages/shared/src/lib/core/utils/abiDecoder.ts b/packages/shared/src/lib/core/utils/abiDecoder.ts
index a4ba9b3b52..1e7cfca6c6 100644
--- a/packages/shared/src/lib/core/utils/abiDecoder.ts
+++ b/packages/shared/src/lib/core/utils/abiDecoder.ts
@@ -1,6 +1,7 @@
+import { Erc20Abi, Erc721Abi, IscAbi } from '@core/layer-2'
import type { AbiEventFragment, AbiFunctionFragment, AbiInput, AbiParameter, ContractAbi, Web3 } from 'web3'
-export class AbiDecoder {
+export class AbiDecoder {
public abi: Record
public web3: Web3
@@ -28,19 +29,7 @@ export class AbiDecoder {
this.web3 = _web3
}
- public decodeData(data: string):
- | {
- name: string
- inputs: Record<
- string,
- {
- name: string
- type: string
- value: unknown
- }
- >
- }
- | undefined {
+ public decodeData(data: string): T | undefined {
const functionSignature = data.slice(2, 10)
const abiItem = this.abi[functionSignature]
@@ -50,13 +39,7 @@ export class AbiDecoder {
const decoded = this.web3.eth.abi.decodeParameters((abiItem.inputs as AbiInput[]) ?? [], data.slice(10))
- const inputs: {
- [key: string]: {
- name: string
- type: string
- value: unknown
- }
- } = {}
+ const inputs: T['inputs'] = {}
for (let i = 0; i < decoded.__length__; i++) {
const dataInput = decoded[i]
const abiInput = abiItem.inputs?.[i]
@@ -76,7 +59,7 @@ export class AbiDecoder {
return {
name: abiItem.name,
inputs,
- }
+ } as T
}
private parseInputParameter(input: AbiParameter, value: unknown): unknown {
diff --git a/packages/shared/src/locales/en.json b/packages/shared/src/locales/en.json
index 3fefe4d93b..da9a6eae6a 100644
--- a/packages/shared/src/locales/en.json
+++ b/packages/shared/src/locales/en.json
@@ -1094,6 +1094,12 @@
"action": "Sign",
"success": "Signed transaction"
},
+ "tokenApproval": {
+ "title": "Approve {dappName} to access {assetName}",
+ "hint": "{address} is requesting approval to spend {assetName}",
+ "action": "Approve",
+ "success": "Successfully approved"
+ },
"sendTransaction": {
"title": "Send transaction",
"action": "Send",
@@ -1728,7 +1734,8 @@
"location": "Location",
"slow": "Slow",
"average": "Average",
- "fast": "Fast"
+ "fast": "Fast",
+ "spender": "Spender"
},
"filters":{
"title": "Filters",