Skip to content
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

436 feature complete type checks on token transactions #459

Merged
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
49a3d57
fixed: type check for transaction functions
zzggo Feb 3, 2025
352b572
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 4, 2025
1830175
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 4, 2025
a9f60e1
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 5, 2025
43d7ba4
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 5, 2025
47362e4
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 6, 2025
c2943a9
fixed: create transaction type and restructure the send folder
zzggo Feb 6, 2025
ae6c5e6
feat: set transaction state type
zzggo Feb 6, 2025
7f5451f
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 7, 2025
c0afe2a
feat: check decimal places sending to env
zzggo Feb 7, 2025
1bd97ed
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 7, 2025
e07a747
feat: set token transfer digit limits sending to flow
zzggo Feb 8, 2025
4b3858c
fixed: selected token default as flow, no null value allowed
zzggo Feb 8, 2025
3df9bfd
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 9, 2025
7bcb3fb
feat: add decimal checks on move tokens
zzggo Feb 9, 2025
df6aa29
fixed: transaction ui update and change the function handler to globa…
zzggo Feb 10, 2025
7f6dbb2
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 10, 2025
8c1e823
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 11, 2025
37c5123
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
zzggo Feb 11, 2025
44c9d57
Transaction reducer example
tombeckenham Feb 11, 2025
0b895f6
Scoped actions and removed imports
tombeckenham Feb 11, 2025
052f1a7
Corrected number entry and a couple of tests
tombeckenham Feb 12, 2025
f44f547
Merge pull request #498 from onflow:transaction-reducer
tombeckenham Feb 12, 2025
5a9740a
Updated Mapping to capitalize From To and moved TransferConfirmation …
tombeckenham Feb 12, 2025
d7712cb
Feat: add contact hook and store
zzggo Feb 12, 2025
f8177f9
feat: move the address list into store
zzggo Feb 12, 2025
35c98dd
feat: new web3 instance
zzggo Feb 12, 2025
b5104eb
Updated SendToEvm and confirmations
tombeckenham Feb 12, 2025
25c6c4e
Corrected address lookup redirect
tombeckenham Feb 12, 2025
5ec6f64
fixed: change to useContact, fixed the address check and rerendering …
zzggo Feb 12, 2025
18bf153
Merge branches '436-feature-complete-type-checks-on-token-transaction…
zzggo Feb 12, 2025
d93e6d4
EVM confirm in progress
tombeckenham Feb 12, 2025
4222512
Transitioned all send components to use reducer
tombeckenham Feb 13, 2025
266d59f
Changed routing structure for token sends
tombeckenham Feb 13, 2025
f13d4e7
Combined SendToEvm and SendToCadence
tombeckenham Feb 13, 2025
b0c5630
Consolidated all send functionality
tombeckenham Feb 13, 2025
6e963e9
feat: new contact card
zzggo Feb 13, 2025
67da668
Merge branch '436-feature-complete-type-checks-on-token-transactions'…
zzggo Feb 13, 2025
718209c
fixed: update profile with generic component passing in contact object
zzggo Feb 13, 2025
47c4f0e
fixed: move the set state out from component
zzggo Feb 13, 2025
7ac3ef9
fixed: select the store and set to a new object individually
zzggo Feb 13, 2025
bd907ee
Moved all the listen transaction stuff to the one function
tombeckenham Feb 13, 2025
a9b2a0a
Updating to call setAmount when changing tokens to adjust the decimals
tombeckenham Feb 13, 2025
93e6145
Removed value checking and manipulation from individual functions as …
tombeckenham Feb 13, 2025
76b61e1
Removed all the move FT stuff
tombeckenham Feb 13, 2025
b8dc375
Moved all transaction logic to the background 🎉
tombeckenham Feb 13, 2025
02b5ca5
Added tests for transaction reducer
tombeckenham Feb 13, 2025
1f5caa8
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
tombeckenham Feb 13, 2025
982327a
Corrected some of the tests
tombeckenham Feb 13, 2025
0e243c4
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
tombeckenham Feb 14, 2025
f4197fa
Removed code that altered values in wallet. Moved some code to number…
tombeckenham Feb 14, 2025
e5ab5be
Removed unused code and providers
tombeckenham Feb 14, 2025
3e7aaae
Removed temp code from webpack
tombeckenham Feb 14, 2025
0373993
Merge branch 'dev' into 436-feature-complete-type-checks-on-token-tra…
tombeckenham Feb 14, 2025
fc033ad
Returns empty string if empty string passed in
tombeckenham Feb 14, 2025
d05537a
Added metamask EOA address
tombeckenham Feb 14, 2025
36f8b03
fixed: return the contact card with icons first
zzggo Feb 14, 2025
f4e0bf4
Corrected evm transaction coversion to integer, and coin selector
tombeckenham Feb 14, 2025
ae3a72b
Merge remote-tracking branch 'refs/remotes/origin/436-feature-complet…
tombeckenham Feb 14, 2025
f95f71a
Corrected flow token coa transaction. Checks transaction amount in e2…
tombeckenham Feb 14, 2025
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
4 changes: 2 additions & 2 deletions e2e/sendTransaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ test('send BETA token COA to EOA', async ({ page }) => {
successtext: 'success',
});
});
//Move FTs from COA to FLOW
/* //Move FTs from COA to FLOW
test('move Flow COA to FLOW', async ({ page }) => {
// Move FLOW token from COA to FLOW
await moveTokenCOA({
Expand Down Expand Up @@ -164,7 +164,7 @@ test('move USDC token COA to FLOW homepage', async ({ page }) => {
tokenname: 'Bridged USDC (Celer)',
amount: '0.000123',
});
});
}); */
//Send NFT from COA to COA
//Send NFT from COA to FLOW
//Send NFT from COA to EOA
Expand Down
3 changes: 2 additions & 1 deletion e2e/sendTransactionFromFlow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ test('send BETA flow to EOA', async ({ page }) => {
ingoreFlowCharge: true,
});
});
//Move FTs from Flow to COA
/* //Move FTs from Flow to COA
test('move Flow Flow to COA', async ({ page }) => {
// Move FLOW token from FLOW to COA
await moveTokenFlow({
Expand Down Expand Up @@ -160,3 +160,4 @@ test('move USDC token Flow to COA homepage', async ({ page }) => {
ingoreFlowCharge: true,
});
});
*/
246 changes: 143 additions & 103 deletions src/background/controller/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { ethErrors } from 'eth-rpc-errors';
import * as ethUtil from 'ethereumjs-util';
import { getApp } from 'firebase/app';
import { getAuth } from 'firebase/auth/web-extension';
import type { TokenInfo } from 'flow-native-token-registry';
import { encode } from 'rlp';
import web3, { TransactionError } from 'web3';
import web3, { TransactionError, Web3 } from 'web3';

import {
findAddressWithNetwork,
Expand All @@ -26,10 +27,10 @@ import {
import eventBus from '@/eventBus';
import { type FeatureFlagKey, type FeatureFlags } from '@/shared/types/feature-types';
import { type TrackingEvents } from '@/shared/types/tracking-types';
import { type ActiveChildType, type LoggedInAccount } from '@/shared/types/wallet-types';
import { type TransactionState } from '@/shared/types/transaction-types';
import { type LoggedInAccount } from '@/shared/types/wallet-types';
import { ensureEvmAddressPrefix, isValidEthereumAddress, withPrefix } from '@/shared/utils/address';
import { getHashAlgo, getSignAlgo } from '@/shared/utils/algo';
import { retryOperation } from '@/shared/utils/retryOperation';
import { getSignAlgo } from '@/shared/utils/algo';
import {
keyringService,
preferenceService,
Expand Down Expand Up @@ -59,7 +60,7 @@ import emoji from 'background/utils/emoji.json';
import fetchConfig from 'background/utils/remoteConfig';
import { notification, storage } from 'background/webapi';
import { openIndexPage } from 'background/webapi/tab';
import { INTERNAL_REQUEST_ORIGIN, EVENTS, KEYRING_TYPE } from 'consts';
import { INTERNAL_REQUEST_ORIGIN, EVENTS, KEYRING_TYPE, EVM_ENDPOINT } from 'consts';

import type {
BlockchainResponse,
Expand All @@ -75,6 +76,7 @@ import type { PreferenceAccount } from '../service/preference';
import { type EvaluateStorageResult, StorageEvaluator } from '../service/storage-evaluator';
import type { UserInfoStore } from '../service/user';
import defaultConfig from '../utils/defaultConfig.json';
import erc20ABI from '../utils/erc20.abi.json';
import { getLoggedInAccount } from '../utils/getLoggedInAccount';

import BaseController from './base';
Expand Down Expand Up @@ -787,27 +789,6 @@ export class WalletController extends BaseController {
const keyring = await keyringService.getKeyringForAccount(from, type);
const res = await keyringService.signTransaction(keyring, data, options);

/*
cadence_transaction_signed: {
cadence: string; // SHA256 Hashed Cadence that was signed.
tx_id: string; // String of the transaction ID.
authorizers: string[]; // Comma separated list of authorizer account address in the transaction
proposer: string; // Address of the transactions proposer.
payer: string; // Payer of the transaction.
success: boolean; // Boolean of if the transaction was sent successful or not. true/false
};
evm_transaction_signed: {
success: boolean; // Boolean of if the transaction was sent successful or not. true/false
flow_address: string; // Address of the account that signed the transaction
evm_address: string; // EVM Address of the account that signed the transaction
tx_id: string; // transaction id
};
mixpanelTrack.track('transaction_signed', {
address: from,
type,
...res,
});
*/
return res;
};

Expand Down Expand Up @@ -892,16 +873,7 @@ export class WalletController extends BaseController {
updateAlianName = (address: string, name: string) =>
preferenceService.updateAlianName(address, name);
getAllAlianName = () => preferenceService.getAllAlianName();
// getInitAlianNameStatus = () => preferenceService.getInitAlianNameStatus();
// updateInitAlianNameStatus = () =>
// preferenceService.changeInitAlianNameStatus();
// getLastTimeGasSelection = (chainId) => {
// return preferenceService.getLastTimeGasSelection(chainId);
// };

// updateLastTimeGasSelection = (chainId: string, gas: ChainGas) => {
// return preferenceService.updateLastTimeGasSelection(chainId, gas);
// };
getIsFirstOpen = () => {
return preferenceService.getIsFirstOpen();
};
Expand All @@ -911,14 +883,6 @@ export class WalletController extends BaseController {
listChainAssets = async (address: string) => {
return await openapiService.getCoinList(address);
};
// getAddedToken = (address: string) => {
// return preferenceService.getAddedToken(address);
// };
// updateAddedToken = (address: string, tokenList: []) => {
// return preferenceService.updateAddedToken(address, tokenList);
// };

// lilico new service

// userinfo
getUserInfo = async (forceRefresh: boolean) => {
Expand Down Expand Up @@ -1014,17 +978,7 @@ export class WalletController extends BaseController {

checkAccessibleNft = async (childAccount) => {
try {
// const res = await openapiService.checkChildAccount(address);
// const nfts = await openapiService.queryAccessible(
// '0x84221fe0294044d7',
// '0x16c41a2b76dee69b'
// );
const nfts = await openapiService.checkChildAccountNFT(childAccount);
// openapiService.checkChildAccountNFT(address).then((res) => {
// console.log(res)
// }).catch((err) => {
// console.log(err)
// })

return nfts;
} catch (error) {
Expand All @@ -1037,13 +991,7 @@ export class WalletController extends BaseController {
const network = await this.getNetwork();

const address = await userWalletService.getMainWallet(network);
// const res = await openapiService.checkChildAccount(address);
const result = await openapiService.queryAccessibleFt(address, childAccount);
// openapiService.checkChildAccountNFT(address).then((res) => {
// console.log(res)
// }).catch((err) => {
// console.log(err)
// })

return result;
};
Expand Down Expand Up @@ -1806,6 +1754,132 @@ export class WalletController extends BaseController {
});
};

// Master send token function that takes a transaction state from the front end and returns the transaction ID
transferTokens = async (transactionState: TransactionState): Promise<string> => {
const transferTokensOnCadence = async () => {
return this.transferCadenceTokens(
transactionState.selectedToken.symbol,
transactionState.toAddress,
transactionState.amount
);
};

const transferTokensFromChildToCadence = async () => {
return this.sendFTfromChild(
transactionState.fromAddress,
transactionState.toAddress,
'flowTokenProvider',
transactionState.amount,
transactionState.selectedToken.symbol
);
};

const transferFlowFromEvmToCadence = async () => {
console.log('transferFlowFromEvmToCadence');
return this.withdrawFlowEvm(transactionState.amount, transactionState.toAddress);
};

const transferFTFromEvmToCadence = async () => {
return this.transferFTFromEvm(
transactionState.selectedToken['flowIdentifier'],
transactionState.amount,
transactionState.toAddress,
transactionState.selectedToken
);
};

// Returns the transaction ID
const transferTokensOnEvm = async () => {
// the amount is always stored as a string in the transaction state
const amountStr: string = transactionState.amount;
// TODO: check if the amount is a valid number
// Create an integer string based on the required token decimals
const amountBN = new BN(amountStr.replace('.', ''));

const decimalsCount = amountStr.split('.')[1]?.length || 0;
const decimalDifference = transactionState.selectedToken.decimals - decimalsCount;
if (decimalDifference < 0) {
throw new Error('Too many decimal places have been provided');
}
const scaleFactor = new BN(10).pow(decimalDifference);
const integerAmount = amountBN.multipliedBy(scaleFactor);
const integerAmountStr = integerAmount.integerValue(BN.ROUND_DOWN).toFixed();

let address, gas, value, data;

if (transactionState.selectedToken.symbol.toLowerCase() === 'flow') {
address = transactionState.toAddress;
gas = '1';
// const amountBN = new BN(transactionState.amount).multipliedBy(new BN(10).pow(18));
// the amount is always stored as a string in the transaction state
value = integerAmount.toString(16);
data = '0x';
} else {
// Get the current network
const network = await this.getNetwork();
// Get the Web3 provider
const provider = new Web3.providers.HttpProvider(EVM_ENDPOINT[network]);
// Get the web3 instance
const web3Instance = new Web3(provider);
// Get the erc20 contract
const erc20Contract = new web3Instance.eth.Contract(
erc20ABI,
transactionState.selectedToken.address
);
// Encode the data
const encodedData = erc20Contract.methods
.transfer(ensureEvmAddressPrefix(transactionState.toAddress), integerAmountStr)
.encodeABI();
gas = '1312d00';
address = ensureEvmAddressPrefix(transactionState.selectedToken.address);
value = '0x0'; // Zero value as hex
data = encodedData.startsWith('0x') ? encodedData : `0x${encodedData}`;
}

// Send the transaction
return this.sendEvmTransaction(address, gas, value, data);
};

const transferFlowFromCadenceToEvm = async () => {
return this.transferFlowEvm(transactionState.toAddress, transactionState.amount);
};

const transferFTFromCadenceToEvm = async () => {
const address = transactionState.selectedToken!.address.startsWith('0x')
? transactionState.selectedToken!.address.slice(2)
: transactionState.selectedToken!.address;

return this.transferFTToEvmV2(
`A.${address}.${transactionState.selectedToken!.contractName}.Vault`,
transactionState.amount,
transactionState.toAddress
);
};

// Switch on the current transaction state
switch (transactionState.currentTxState) {
case 'FTFromEvmToCadence':
return await transferFTFromEvmToCadence();
case 'FlowFromEvmToCadence':
return await transferFlowFromEvmToCadence();
case 'FTFromChildToCadence':
case 'FlowFromChildToCadence':
return await transferTokensFromChildToCadence();
case 'FTFromCadenceToCadence':
case 'FlowFromCadenceToCadence':
return await transferTokensOnCadence();
case 'FlowFromEvmToEvm':
case 'FTFromEvmToEvm':
return await transferTokensOnEvm();
case 'FlowFromCadenceToEvm':
return await transferFlowFromCadenceToEvm();
case 'FTFromCadenceToEvm':
return await transferFTFromCadenceToEvm();
default:
throw new Error(`Unsupported transaction state: ${transactionState.currentTxState}`);
}
};

transferFlowEvm = async (
recipientEVMAddressHex: string,
amount = '1.0',
Expand Down Expand Up @@ -1875,11 +1949,11 @@ export class WalletController extends BaseController {

transferFTToEvmV2 = async (
vaultIdentifier: string,
amount = '1.0',
recipient
amount = '0.0',
recipient: string
): Promise<string> => {
await this.getNetwork();
const formattedAmount = parseFloat(amount).toFixed(8);
const formattedAmount = new BN(amount).decimalPlaces(8, BN.ROUND_DOWN).toString();

const script = await getScripts('bridge', 'bridgeTokensToEvmAddressV2');

Expand All @@ -1902,9 +1976,9 @@ export class WalletController extends BaseController {

transferFTFromEvm = async (
flowidentifier: string,
amount = '1.0',
amount: string,
receiver: string,
tokenResult
tokenResult: TokenInfo
): Promise<string> => {
await this.getNetwork();
const amountStr = amount.toString();
Expand Down Expand Up @@ -1941,9 +2015,8 @@ export class WalletController extends BaseController {
return txID;
};

withdrawFlowEvm = async (amount = '1.0', address: string): Promise<string> => {
await this.getNetwork();
const formattedAmount = parseFloat(amount).toFixed(8);
withdrawFlowEvm = async (amount = '0.0', address: string): Promise<string> => {
const formattedAmount = new BN(amount).decimalPlaces(8, BN.ROUND_DOWN).toString();
const script = await getScripts('evm', 'withdrawCoa');

const txID = await userWalletService.sendTransaction(script, [
Expand All @@ -1955,9 +2028,7 @@ export class WalletController extends BaseController {
};

fundFlowEvm = async (amount = '1.0'): Promise<string> => {
await this.getNetwork();
const formattedAmount = parseFloat(amount).toFixed(8);

const formattedAmount = new BN(amount).decimalPlaces(8, BN.ROUND_DOWN).toString();
const script = await getScripts('evm', 'fundCoa');

return await userWalletService.sendTransaction(script, [fcl.arg(formattedAmount, t.UFix64)]);
Expand Down Expand Up @@ -1995,8 +2066,7 @@ export class WalletController extends BaseController {
};

bridgeToEvm = async (flowIdentifier, amount = '1.0'): Promise<string> => {
await this.getNetwork();
const formattedAmount = parseFloat(amount).toFixed(8);
const formattedAmount = new BN(amount).decimalPlaces(8, BN.ROUND_DOWN).toString();

const script = await getScripts('bridge', 'bridgeTokensToEvmV2');

Expand Down Expand Up @@ -2325,37 +2395,7 @@ export class WalletController extends BaseController {
};

// TODO: Replace with generic token
transferTokens = async (symbol: string, address: string, amount: string): Promise<string> => {
const token = await openapiService.getTokenInfo(symbol);
if (!token) {
throw new Error(`Invaild token name - ${symbol}`);
}
await this.getNetwork();
const script = await getScripts('ft', 'transferTokensV3');

const txID = await userWalletService.sendTransaction(
script
.replaceAll('<Token>', token.contractName)
.replaceAll('<TokenBalancePath>', token.path.balance)
.replaceAll('<TokenReceiverPath>', token.path.receiver)
.replaceAll('<TokenStoragePath>', token.path.vault)
.replaceAll('<TokenAddress>', token.address),
[fcl.arg(amount, t.UFix64), fcl.arg(address, t.Address)]
);

mixpanelTrack.track('ft_transfer', {
from_address: (await this.getCurrentAddress()) || '',
to_address: address,
amount: parseFloat(amount),
ft_identifier: token.contractName,
type: 'flow',
});

return txID;
};

// TODO: Replace with generic token
transferInboxTokens = async (
transferCadenceTokens = async (
symbol: string,
address: string,
amount: string
Expand Down
Loading