From 722383b4046f0467aa46c2a0b90e47120772febb Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 14 Jun 2024 14:57:43 +0200 Subject: [PATCH 1/6] [skip ci] wip: efox arbitrum Txs parser --- .../src/evm/arbitrum/parser/index.ts | 8 + .../src/evm/parser/abi/rfox.ts | 539 ++++++++++++++++++ .../unchained-client/src/evm/parser/rfox.ts | 57 ++ .../unchained-client/src/evm/parser/types.ts | 2 + src/assets/translations/en/main.json | 7 + .../TransactionHistoryRows/TransactionTag.tsx | 7 + src/hooks/useTxDetails/useTxDetails.ts | 1 + 7 files changed, 621 insertions(+) create mode 100644 packages/unchained-client/src/evm/parser/abi/rfox.ts create mode 100644 packages/unchained-client/src/evm/parser/rfox.ts diff --git a/packages/unchained-client/src/evm/arbitrum/parser/index.ts b/packages/unchained-client/src/evm/arbitrum/parser/index.ts index c6738c0860b..c8d676b6455 100644 --- a/packages/unchained-client/src/evm/arbitrum/parser/index.ts +++ b/packages/unchained-client/src/evm/arbitrum/parser/index.ts @@ -1,11 +1,15 @@ +import { foxOnArbitrumOneAssetId } from '@shapeshiftoss/caip' + import type { Tx } from '../../../generated/arbitrum' import type { BaseTransactionParserArgs } from '../../parser' import { BaseTransactionParser } from '../../parser' import * as erc20 from '../../parser/erc20' import * as nft from '../../parser/nft' +import * as rfox from '../../parser/rfox' import * as zrx from '../../parser/zrx' export const ZRX_ARBITRUM_PROXY_CONTRACT = '0xDef1C0ded9bec7F1a1670819833240f027b25EfF' +const RFOX_PROXY_CONTRACT_ADDRESS = '0xd612B64A134f3D4830542B7463CE8ca8a29D7268' export class TransactionParser extends BaseTransactionParser { constructor(args: BaseTransactionParserArgs) { @@ -19,6 +23,10 @@ export class TransactionParser extends BaseTransactionParser { }), new erc20.Parser({ chainId: this.chainId, provider: this.provider }), new zrx.Parser({ proxyContract: ZRX_ARBITRUM_PROXY_CONTRACT }), + new rfox.Parser({ + proxyContract: RFOX_PROXY_CONTRACT_ADDRESS, + stakingAssetId: foxOnArbitrumOneAssetId, + }), ]) } } diff --git a/packages/unchained-client/src/evm/parser/abi/rfox.ts b/packages/unchained-client/src/evm/parser/abi/rfox.ts new file mode 100644 index 00000000000..d3b1b7018d9 --- /dev/null +++ b/packages/unchained-client/src/evm/parser/abi/rfox.ts @@ -0,0 +1,539 @@ +import type { InterfaceAbi } from 'ethers' + +export const RFOX_ABI: InterfaceAbi = [ + { type: 'constructor', inputs: [], stateMutability: 'nonpayable' }, + { + type: 'function', + inputs: [], + name: 'REWARD_RATE', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'UPGRADE_INTERFACE_VERSION', + outputs: [{ name: '', internalType: 'string', type: 'string' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'WAD', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'account', internalType: 'address', type: 'address' }], + name: 'balanceOf', + outputs: [{ name: 'total', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'cooldownPeriod', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'account', internalType: 'address', type: 'address' }], + name: 'earned', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'account', internalType: 'address', type: 'address' }, + { name: 'index', internalType: 'uint256', type: 'uint256' }, + ], + name: 'getUnstakingRequest', + outputs: [ + { + name: '', + internalType: 'struct UnstakingRequest', + type: 'tuple', + components: [ + { + name: 'unstakingBalance', + internalType: 'uint256', + type: 'uint256', + }, + { name: 'cooldownExpiry', internalType: 'uint256', type: 'uint256' }, + ], + }, + ], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'account', internalType: 'address', type: 'address' }], + name: 'getUnstakingRequestCount', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'stakingTokenAddress', internalType: 'address', type: 'address' }], + name: 'initialize', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'lastUpdateTimestamp', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'owner', + outputs: [{ name: '', internalType: 'address', type: 'address' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'pause', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'pauseStaking', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'pauseUnstaking', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'pauseWithdrawals', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'paused', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'proxiableUUID', + outputs: [{ name: '', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'renounceOwnership', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'rewardPerToken', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'rewardPerTokenStored', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'newCooldownPeriod', internalType: 'uint256', type: 'uint256' }], + name: 'setCooldownPeriod', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: 'runeAddress', internalType: 'string', type: 'string' }], + name: 'setRuneAddress', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'amount', internalType: 'uint256', type: 'uint256' }, + { name: 'runeAddress', internalType: 'string', type: 'string' }, + ], + name: 'stake', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: '', internalType: 'address', type: 'address' }], + name: 'stakingInfo', + outputs: [ + { name: 'stakingBalance', internalType: 'uint256', type: 'uint256' }, + { name: 'unstakingBalance', internalType: 'uint256', type: 'uint256' }, + { name: 'earnedRewards', internalType: 'uint256', type: 'uint256' }, + { + name: 'rewardPerTokenStored', + internalType: 'uint256', + type: 'uint256', + }, + { name: 'runeAddress', internalType: 'string', type: 'string' }, + ], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'stakingPaused', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'stakingToken', + outputs: [{ name: '', internalType: 'contract IERC20', type: 'address' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'totalCoolingDown', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'totalStaked', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'newOwner', internalType: 'address', type: 'address' }], + name: 'transferOwnership', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'unpause', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'unpauseStaking', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'unpauseUnstaking', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'unpauseWithdrawals', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: 'amount', internalType: 'uint256', type: 'uint256' }], + name: 'unstake', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'unstakingPaused', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: 'newImplementation', internalType: 'address', type: 'address' }, + { name: 'data', internalType: 'bytes', type: 'bytes' }, + ], + name: 'upgradeToAndCall', + outputs: [], + stateMutability: 'payable', + }, + { + type: 'function', + inputs: [], + name: 'version', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'index', internalType: 'uint256', type: 'uint256' }], + name: 'withdraw', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'withdraw', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'withdrawalsPaused', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'version', + internalType: 'uint64', + type: 'uint64', + indexed: false, + }, + ], + name: 'Initialized', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'previousOwner', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'newOwner', + internalType: 'address', + type: 'address', + indexed: true, + }, + ], + name: 'OwnershipTransferred', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'account', + internalType: 'address', + type: 'address', + indexed: false, + }, + ], + name: 'Paused', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'account', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'oldRuneAddress', + internalType: 'string', + type: 'string', + indexed: true, + }, + { + name: 'newRuneAddress', + internalType: 'string', + type: 'string', + indexed: true, + }, + ], + name: 'SetRuneAddress', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'account', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + { + name: 'runeAddress', + internalType: 'string', + type: 'string', + indexed: true, + }, + ], + name: 'Stake', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'account', + internalType: 'address', + type: 'address', + indexed: false, + }, + ], + name: 'Unpaused', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'account', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + { + name: 'cooldownExpiry', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'Unstake', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'newCooldownPeriod', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'UpdateCooldownPeriod', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'implementation', + internalType: 'address', + type: 'address', + indexed: true, + }, + ], + name: 'Upgraded', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'account', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'amount', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'Withdraw', + }, + { + type: 'error', + inputs: [{ name: 'target', internalType: 'address', type: 'address' }], + name: 'AddressEmptyCode', + }, + { + type: 'error', + inputs: [{ name: 'account', internalType: 'address', type: 'address' }], + name: 'AddressInsufficientBalance', + }, + { + type: 'error', + inputs: [{ name: 'implementation', internalType: 'address', type: 'address' }], + name: 'ERC1967InvalidImplementation', + }, + { type: 'error', inputs: [], name: 'ERC1967NonPayable' }, + { type: 'error', inputs: [], name: 'EnforcedPause' }, + { type: 'error', inputs: [], name: 'ExpectedPause' }, + { type: 'error', inputs: [], name: 'FailedInnerCall' }, + { type: 'error', inputs: [], name: 'InvalidInitialization' }, + { type: 'error', inputs: [], name: 'NotInitializing' }, + { + type: 'error', + inputs: [{ name: 'owner', internalType: 'address', type: 'address' }], + name: 'OwnableInvalidOwner', + }, + { + type: 'error', + inputs: [{ name: 'account', internalType: 'address', type: 'address' }], + name: 'OwnableUnauthorizedAccount', + }, + { type: 'error', inputs: [], name: 'ReentrancyGuardReentrantCall' }, + { + type: 'error', + inputs: [{ name: 'token', internalType: 'address', type: 'address' }], + name: 'SafeERC20FailedOperation', + }, + { type: 'error', inputs: [], name: 'UUPSUnauthorizedCallContext' }, + { + type: 'error', + inputs: [{ name: 'slot', internalType: 'bytes32', type: 'bytes32' }], + name: 'UUPSUnsupportedProxiableUUID', + }, +] diff --git a/packages/unchained-client/src/evm/parser/rfox.ts b/packages/unchained-client/src/evm/parser/rfox.ts new file mode 100644 index 00000000000..5876082248a --- /dev/null +++ b/packages/unchained-client/src/evm/parser/rfox.ts @@ -0,0 +1,57 @@ +import type { AssetId } from '@shapeshiftoss/caip' +import { ethers } from 'ethers' + +import type { BaseTxMetadata } from '../../types' +import type { SubParser, TxSpecific } from '.' +import { getSigHash, txInteractsWithContract } from '.' +import { RFOX_ABI } from './abi/rfox' +import type { Tx } from './types' + +export interface TxMetadata extends BaseTxMetadata { + parser: 'rfox' +} + +export interface ParserArgs { + proxyContract: string + stakingAssetId: AssetId +} + +export class Parser implements SubParser { + private readonly proxyContract + readonly abiInterface = new ethers.Interface(RFOX_ABI) + private readonly stakingAssetId: AssetId + + readonly supportedFunctions = { + stake: this.abiInterface.getFunction('stake')!.selector, + unstake: this.abiInterface.getFunction('unstake')!.selector, + withdrawClaim: this.abiInterface.getFunction('withdraw(uint256)')!.selector, + withdraw: this.abiInterface.getFunction('withdraw()')!.selector, + setRuneAddress: this.abiInterface.getFunction('setRuneAddress')!.selector, + } + + constructor(args: ParserArgs) { + this.proxyContract = args.proxyContract + this.stakingAssetId = args.stakingAssetId + } + + async parse(tx: Tx): Promise { + if (!txInteractsWithContract(tx, this.proxyContract)) return + if (!tx.inputData) return + + const txSigHash = getSigHash(tx.inputData) + + if (!Object.values(this.supportedFunctions).some(hash => hash === txSigHash)) return + + const decoded = this.abiInterface.parseTransaction({ data: tx.inputData }) + + if (!decoded) return + + return await Promise.resolve({ + data: { + method: decoded.name, + parser: 'rfox', + assetId: this.stakingAssetId, + }, + }) + } +} diff --git a/packages/unchained-client/src/evm/parser/types.ts b/packages/unchained-client/src/evm/parser/types.ts index 6aa1c3c19d2..ce70e736c18 100644 --- a/packages/unchained-client/src/evm/parser/types.ts +++ b/packages/unchained-client/src/evm/parser/types.ts @@ -9,6 +9,7 @@ import type * as uniV2 from '../ethereum/parser/uniV2' import type * as weth from '../ethereum/parser/weth' import type * as erc20 from '../parser/erc20' import type * as nft from '../parser/nft' +import type * as rfox from '../parser/rfox' import type * as zrx from '../parser/zrx' export type Tx = evm.Tx @@ -23,6 +24,7 @@ export type TxMetadata = | weth.TxMetadata | zrx.TxMetadata | nft.TxMetadata + | rfox.TxMetadata export interface ParsedTx extends StandardTx { data?: TxMetadata diff --git a/src/assets/translations/en/main.json b/src/assets/translations/en/main.json index 185c0f4fab1..8681a63c696 100644 --- a/src/assets/translations/en/main.json +++ b/src/assets/translations/en/main.json @@ -640,6 +640,13 @@ "for": "for", "emptyMessage": "Your %{status} transactions will appear here.", "parser": { + "rfox": { + "stake": "Stake", + "withdraw": "Withdraw", + "unstake": "Unstake", + "setRuneAddress": "Set Rune Address" + + }, "weth": { "deposit": "Deposit", "approve": "Approve", diff --git a/src/components/TransactionHistoryRows/TransactionTag.tsx b/src/components/TransactionHistoryRows/TransactionTag.tsx index 3bd86a026b0..be9e8875df4 100644 --- a/src/components/TransactionHistoryRows/TransactionTag.tsx +++ b/src/components/TransactionHistoryRows/TransactionTag.tsx @@ -29,6 +29,13 @@ export const TransactionTag: React.FC = ({ txDetails, trans ) } + if (txData && txData.parser === 'rfox') { + return ( + + rFOX + + ) + } if (txData && txData.parser === 'thorchain' && txData.liquidity) { return ( diff --git a/src/hooks/useTxDetails/useTxDetails.ts b/src/hooks/useTxDetails/useTxDetails.ts index 6438f7a4154..6cfb6a5be69 100644 --- a/src/hooks/useTxDetails/useTxDetails.ts +++ b/src/hooks/useTxDetails/useTxDetails.ts @@ -49,6 +49,7 @@ export enum Method { Refund = 'refund', RemoveLiquidityEth = 'removeLiquidityETH', Revoke = 'revoke', + SetRuneAddress = 'setRuneAddress', Stake = 'stake', SwapOut = 'swapOut', SwapRefund = 'swapRefund', From 9bf1d1161421b7e88e31fea051b463f9bb2fc0b7 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:27:55 +0200 Subject: [PATCH 2/6] feat: add tests --- .../parser/__tests__/arbitrum.test.ts | 113 ++++++++++++++++++ .../__tests__/mockData/rfoxSetRuneAddress.ts | 21 ++++ .../parser/__tests__/mockData/rfoxStake.ts | 34 ++++++ .../parser/__tests__/mockData/rfoxUnstake.ts | 20 ++++ .../parser/__tests__/mockData/rfoxWithdraw.ts | 32 +++++ .../unchained-client/src/evm/parser/rfox.ts | 3 + 6 files changed, 223 insertions(+) create mode 100644 packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxSetRuneAddress.ts create mode 100644 packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxStake.ts create mode 100644 packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxUnstake.ts create mode 100644 packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxWithdraw.ts diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/arbitrum.test.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/arbitrum.test.ts index b476ec68ea4..c7b52f7f752 100644 --- a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/arbitrum.test.ts +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/arbitrum.test.ts @@ -12,6 +12,10 @@ import erc721 from './mockData/erc721' import erc1155 from './mockData/erc1155' import ethSelfSend from './mockData/ethSelfSend' import ethStandard from './mockData/ethStandard' +import rfoxSetRuneAddress from './mockData/rfoxSetRuneAddress' +import rfoxStake from './mockData/rfoxStake' +import rfoxUnstake from './mockData/rfoxUnstake' +import rfoxWithdraw from './mockData/rfoxWithdraw' import { usdcToken } from './mockData/tokens' import tokenSelfSend from './mockData/tokenSelfSend' import tokenStandard from './mockData/tokenStandard' @@ -878,4 +882,113 @@ describe('parseTx', () => { expect(actual).toEqual(expected) }) }) + describe('rfox', () => { + it('should be able to stake', async () => { + const { tx } = rfoxStake + const address = '0xa684bAEfeE2D6595d330d1762A9e8AcA789e7098' + + const expected: ParsedTx = { + txid: tx.txid, + blockHeight: tx.blockHeight, + blockTime: tx.timestamp, + blockHash: tx.blockHash, + address, + chainId: arbitrumChainId, + confirmations: tx.confirmations, + data: { + method: 'stake', + parser: 'rfox', + assetId: 'eip155:42161/erc20:0xf929de51d91c77e42f5090069e0ad7a09e513c73', + }, + + status: TxStatus.Confirmed, + transfers: [], + trade: undefined, + } + + const actual = await txParser.parse(tx, address) + expect(actual).toEqual(expected) + }) + it('should be able to unstake', async () => { + const { tx } = rfoxUnstake + const address = '0xa684bAEfeE2D6595d330d1762A9e8AcA789e7098' + + const expected: ParsedTx = { + txid: tx.txid, + blockHeight: tx.blockHeight, + blockTime: tx.timestamp, + blockHash: tx.blockHash, + address, + chainId: arbitrumChainId, + confirmations: tx.confirmations, + data: { + method: 'unstake', + parser: 'rfox', + assetId: 'eip155:42161/erc20:0xf929de51d91c77e42f5090069e0ad7a09e513c73', + }, + + status: TxStatus.Confirmed, + transfers: [], + trade: undefined, + } + + const actual = await txParser.parse(tx, address) + + expect(actual).toEqual(expected) + }) + it('should be able to withdraw', async () => { + const { tx } = rfoxWithdraw + const address = '0xa684bAEfeE2D6595d330d1762A9e8AcA789e7098' + + const expected: ParsedTx = { + txid: tx.txid, + blockHeight: tx.blockHeight, + blockTime: tx.timestamp, + blockHash: tx.blockHash, + address, + chainId: arbitrumChainId, + confirmations: tx.confirmations, + data: { + method: 'withdraw', + parser: 'rfox', + assetId: 'eip155:42161/erc20:0xf929de51d91c77e42f5090069e0ad7a09e513c73', + }, + + status: TxStatus.Confirmed, + transfers: [], + trade: undefined, + } + + const actual = await txParser.parse(tx, address) + + expect(actual).toEqual(expected) + }) + it('should be able to set RUNE address', async () => { + const { tx } = rfoxSetRuneAddress + const address = '0xa684bAEfeE2D6595d330d1762A9e8AcA789e7098' + + const expected: ParsedTx = { + txid: tx.txid, + blockHeight: tx.blockHeight, + blockTime: tx.timestamp, + blockHash: tx.blockHash, + address, + chainId: arbitrumChainId, + confirmations: tx.confirmations, + data: { + method: 'setRuneAddress', + parser: 'rfox', + assetId: 'eip155:42161/erc20:0xf929de51d91c77e42f5090069e0ad7a09e513c73', + }, + + status: TxStatus.Confirmed, + transfers: [], + trade: undefined, + } + + const actual = await txParser.parse(tx, address) + + expect(actual).toEqual(expected) + }) + }) }) diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxSetRuneAddress.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxSetRuneAddress.ts new file mode 100644 index 00000000000..bbb5f193e42 --- /dev/null +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxSetRuneAddress.ts @@ -0,0 +1,21 @@ +import type { Tx } from '../../../..' + +const tx: Tx = { + txid: '0x0145c782916e9e8683caac3b24c6c93a22b738cd2e019d7c43cd3d60c82e6b9b', + blockHash: '0x76787a0a3d5b6a43a308b828b58edb841d13b6671f366ad1308fb7bdaaf5cc6a', + blockHeight: 221516124, + timestamp: 1718305602, + from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + to: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', + confirmations: 259682, + value: '0', + fee: '39355169490000', + gasLimit: '145286', + gasUsed: '126711', + gasPrice: '310590000', + status: 1, + inputData: + '0xf6d0b2ed0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002b74686f7231636c70637a676c726b7276647139787463736d6a3961386179726a656574326c6c637175666c000000000000000000000000000000000000000000', +} + +export default { tx } diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxStake.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxStake.ts new file mode 100644 index 00000000000..a48d7773812 --- /dev/null +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxStake.ts @@ -0,0 +1,34 @@ +import type { Tx } from '../../../..' + +const tx: Tx = { + txid: '0x38532538617c6db07af876e0fbe070526e549d0d48cd5c73b67fad0bc5551fd2', + blockHash: '0x54a56f8a3162328adfc8c7c796aa6bce78d2c21dcca9fd2d18cf1938014c243b', + blockHeight: 221776349, + timestamp: 1718370601, + status: 1, + from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + to: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', + confirmations: 5, + value: '0', + fee: '3013123887600', + gasLimit: '236001', + gasUsed: '205844', + gasPrice: '14637900', + inputData: + '0xe7e4e1f70000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002b74686f723132356477736133397965796c716337706e35396c3037396475723530326e736c657972677570000000000000000000000000000000000000000000', + tokenTransfers: [ + { + contract: '0xf929de51D91C77E42f5090069E0AD7A09e513c73', + decimals: 18, + name: 'FOX', + symbol: 'FOX', + type: 'ERC20', + from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + to: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', + value: '1000000000000000000', + }, + ], + internalTxs: [], +} + +export default { tx } diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxUnstake.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxUnstake.ts new file mode 100644 index 00000000000..b75300e574e --- /dev/null +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxUnstake.ts @@ -0,0 +1,20 @@ +import type { Tx } from '../../../..' + +const tx: Tx = { + txid: '0x971e268f63572aee723b2ecd1a08aa8cdb873927fba6fc55146516bc26fc319a', + blockHash: '0x086aa823ff9e888ab8d7c3026a45de90f5a0df69fdb78ebd8b35868573387dbc', + blockHeight: 221510033, + timestamp: 1718304084, + from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + to: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', + confirmations: 265773, + value: '0', + fee: '44360779710690', + gasLimit: '234173', + gasUsed: '210690', + gasPrice: '210550001', + status: 1, + inputData: '0x2e17de780000000000000000000000000000000000000000000000002d6e3fc582c0754c', +} + +export default { tx } diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxWithdraw.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxWithdraw.ts new file mode 100644 index 00000000000..345c6462e97 --- /dev/null +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxWithdraw.ts @@ -0,0 +1,32 @@ +import type { Tx } from '../../../..' + +const tx: Tx = { + txid: '0x6f800e60876460c749e8a9e6dbccd4d166ffc8243a9a63c0c323327ab9764d81', + blockHash: '0x34e3fdfac2e0780254ab3e1f10135bfd2097402c472862a00305b609d65cf4f5', + blockHeight: 221510152, + timestamp: 1718304113, + from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + to: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', + confirmations: 265654, + value: '0', + fee: '41698790000000', + gasLimit: '195355', + gasUsed: '159460', + gasPrice: '261500000', + status: 1, + inputData: '0x2e1a7d4d0000000000000000000000000000000000000000000000000000000000000000', + tokenTransfers: [ + { + contract: '0xf929de51D91C77E42f5090069E0AD7A09e513c73', + decimals: 18, + name: 'FOX', + symbol: 'FOX', + type: 'ERC20', + from: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', + to: '0x5daF465a9cCf64DEB146eEaE9E7Bd40d6761c986', + value: '4364832128906250000', + }, + ], +} + +export default { tx } diff --git a/packages/unchained-client/src/evm/parser/rfox.ts b/packages/unchained-client/src/evm/parser/rfox.ts index 5876082248a..96181c22d30 100644 --- a/packages/unchained-client/src/evm/parser/rfox.ts +++ b/packages/unchained-client/src/evm/parser/rfox.ts @@ -9,6 +9,7 @@ import type { Tx } from './types' export interface TxMetadata extends BaseTxMetadata { parser: 'rfox' + assetId: AssetId } export interface ParserArgs { @@ -44,6 +45,8 @@ export class Parser implements SubParser { const decoded = this.abiInterface.parseTransaction({ data: tx.inputData }) + console.log({ methodName: decoded?.name, tx }) + if (!decoded) return return await Promise.resolve({ From eacd95ef52032a3a4ec6295e0974704e0ec7ea72 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:39:01 +0200 Subject: [PATCH 3/6] feat: cleanup log --- packages/unchained-client/src/evm/parser/rfox.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/unchained-client/src/evm/parser/rfox.ts b/packages/unchained-client/src/evm/parser/rfox.ts index 96181c22d30..3cae306b25f 100644 --- a/packages/unchained-client/src/evm/parser/rfox.ts +++ b/packages/unchained-client/src/evm/parser/rfox.ts @@ -45,8 +45,6 @@ export class Parser implements SubParser { const decoded = this.abiInterface.parseTransaction({ data: tx.inputData }) - console.log({ methodName: decoded?.name, tx }) - if (!decoded) return return await Promise.resolve({ From 356cc68181626f06f0467a47632b4c63e1e677c6 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:45:10 +0200 Subject: [PATCH 4/6] fix: types --- packages/unchained-client/src/evm/parser/rfox.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/unchained-client/src/evm/parser/rfox.ts b/packages/unchained-client/src/evm/parser/rfox.ts index 3cae306b25f..3dc2e5c1d50 100644 --- a/packages/unchained-client/src/evm/parser/rfox.ts +++ b/packages/unchained-client/src/evm/parser/rfox.ts @@ -10,6 +10,7 @@ import type { Tx } from './types' export interface TxMetadata extends BaseTxMetadata { parser: 'rfox' assetId: AssetId + value?: string } export interface ParserArgs { From a64207c6eaaf66927a0f87e0a709e7d98c2ce2c3 Mon Sep 17 00:00:00 2001 From: kaladinlight <35275952+kaladinlight@users.noreply.github.com> Date: Fri, 14 Jun 2024 11:43:21 -0600 Subject: [PATCH 5/6] update tests and metadata --- .../parser/__tests__/arbitrum.test.ts | 77 ++++++++++++++----- .../__tests__/mockData/rfoxSetRuneAddress.ts | 7 +- .../parser/__tests__/mockData/rfoxStake.ts | 6 +- .../parser/__tests__/mockData/rfoxUnstake.ts | 7 +- .../parser/__tests__/mockData/rfoxWithdraw.ts | 7 +- .../parser/__tests__/mockData/tokens.ts | 7 ++ .../src/evm/arbitrum/parser/index.ts | 2 +- .../unchained-client/src/evm/parser/rfox.ts | 34 ++++++-- 8 files changed, 108 insertions(+), 39 deletions(-) diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/arbitrum.test.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/arbitrum.test.ts index c7b52f7f752..d8e4212f3da 100644 --- a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/arbitrum.test.ts +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/arbitrum.test.ts @@ -6,7 +6,11 @@ import type { Trade, Transfer } from '../../../../types' import { Dex, TradeType, TransferType, TxStatus } from '../../../../types' import type { ParsedTx } from '../../../parser' import { V1Api } from '../../index' -import { TransactionParser, ZRX_ARBITRUM_PROXY_CONTRACT } from '../index' +import { + RFOX_PROXY_CONTRACT_ADDRESS, + TransactionParser, + ZRX_ARBITRUM_PROXY_CONTRACT, +} from '../index' import erc20Approve from './mockData/erc20Approve' import erc721 from './mockData/erc721' import erc1155 from './mockData/erc1155' @@ -16,7 +20,7 @@ import rfoxSetRuneAddress from './mockData/rfoxSetRuneAddress' import rfoxStake from './mockData/rfoxStake' import rfoxUnstake from './mockData/rfoxUnstake' import rfoxWithdraw from './mockData/rfoxWithdraw' -import { usdcToken } from './mockData/tokens' +import { foxToken, usdcToken } from './mockData/tokens' import tokenSelfSend from './mockData/tokenSelfSend' import tokenStandard from './mockData/tokenStandard' import zrxTradeEthToUsdc from './mockData/zrxTradeEthToUsdc' @@ -882,10 +886,11 @@ describe('parseTx', () => { expect(actual).toEqual(expected) }) }) + describe('rfox', () => { it('should be able to stake', async () => { const { tx } = rfoxStake - const address = '0xa684bAEfeE2D6595d330d1762A9e8AcA789e7098' + const address = '0x5daF465a9cCf64DEB146eEaE9E7Bd40d6761c986' const expected: ParsedTx = { txid: tx.txid, @@ -895,23 +900,38 @@ describe('parseTx', () => { address, chainId: arbitrumChainId, confirmations: tx.confirmations, + fee: { + assetId: arbitrumAssetId, + value: '3013123887600', + }, data: { method: 'stake', parser: 'rfox', assetId: 'eip155:42161/erc20:0xf929de51d91c77e42f5090069e0ad7a09e513c73', + runeAddress: 'thor125dwsa39yeylqc7pn59l079dur502nsleyrgup', }, - status: TxStatus.Confirmed, - transfers: [], - trade: undefined, + transfers: [ + { + assetId: 'eip155:42161/erc20:0xf929de51d91c77e42f5090069e0ad7a09e513c73', + components: [{ value: '1000000000000000000' }], + from: address, + to: RFOX_PROXY_CONTRACT_ADDRESS, + token: foxToken, + totalValue: '1000000000000000000', + type: TransferType.Send, + }, + ], } const actual = await txParser.parse(tx, address) + expect(actual).toEqual(expected) }) + it('should be able to unstake', async () => { const { tx } = rfoxUnstake - const address = '0xa684bAEfeE2D6595d330d1762A9e8AcA789e7098' + const address = '0x5daF465a9cCf64DEB146eEaE9E7Bd40d6761c986' const expected: ParsedTx = { txid: tx.txid, @@ -921,24 +941,28 @@ describe('parseTx', () => { address, chainId: arbitrumChainId, confirmations: tx.confirmations, + fee: { + assetId: arbitrumAssetId, + value: '44360779710690', + }, data: { - method: 'unstake', + method: 'unstakeRequest', parser: 'rfox', assetId: 'eip155:42161/erc20:0xf929de51d91c77e42f5090069e0ad7a09e513c73', + value: '3273624096679687500', }, - status: TxStatus.Confirmed, transfers: [], - trade: undefined, } const actual = await txParser.parse(tx, address) expect(actual).toEqual(expected) }) - it('should be able to withdraw', async () => { + + it('should be able to withdraw claim', async () => { const { tx } = rfoxWithdraw - const address = '0xa684bAEfeE2D6595d330d1762A9e8AcA789e7098' + const address = '0x5daF465a9cCf64DEB146eEaE9E7Bd40d6761c986' const expected: ParsedTx = { txid: tx.txid, @@ -948,24 +972,38 @@ describe('parseTx', () => { address, chainId: arbitrumChainId, confirmations: tx.confirmations, + fee: { + assetId: arbitrumAssetId, + value: '41698790000000', + }, data: { method: 'withdraw', parser: 'rfox', assetId: 'eip155:42161/erc20:0xf929de51d91c77e42f5090069e0ad7a09e513c73', + claimIndex: 0, }, - status: TxStatus.Confirmed, - transfers: [], - trade: undefined, + transfers: [ + { + assetId: 'eip155:42161/erc20:0xf929de51d91c77e42f5090069e0ad7a09e513c73', + components: [{ value: '4364832128906250000' }], + from: RFOX_PROXY_CONTRACT_ADDRESS, + to: address, + token: foxToken, + totalValue: '4364832128906250000', + type: TransferType.Receive, + }, + ], } const actual = await txParser.parse(tx, address) expect(actual).toEqual(expected) }) + it('should be able to set RUNE address', async () => { const { tx } = rfoxSetRuneAddress - const address = '0xa684bAEfeE2D6595d330d1762A9e8AcA789e7098' + const address = '0x5daF465a9cCf64DEB146eEaE9E7Bd40d6761c986' const expected: ParsedTx = { txid: tx.txid, @@ -975,15 +1013,18 @@ describe('parseTx', () => { address, chainId: arbitrumChainId, confirmations: tx.confirmations, + fee: { + assetId: arbitrumAssetId, + value: '39355169490000', + }, data: { method: 'setRuneAddress', parser: 'rfox', assetId: 'eip155:42161/erc20:0xf929de51d91c77e42f5090069e0ad7a09e513c73', + runeAddress: 'thor1clpczglrkrvdq9xtcsmj9a8ayrjeet2llcqufl', }, - status: TxStatus.Confirmed, transfers: [], - trade: undefined, } const actual = await txParser.parse(tx, address) diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxSetRuneAddress.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxSetRuneAddress.ts index bbb5f193e42..3cd8adaa1e2 100644 --- a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxSetRuneAddress.ts +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxSetRuneAddress.ts @@ -5,17 +5,18 @@ const tx: Tx = { blockHash: '0x76787a0a3d5b6a43a308b828b58edb841d13b6671f366ad1308fb7bdaaf5cc6a', blockHeight: 221516124, timestamp: 1718305602, - from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + status: 1, + from: '0x5daF465a9cCf64DEB146eEaE9E7Bd40d6761c986', to: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', - confirmations: 259682, + confirmations: 303953, value: '0', fee: '39355169490000', gasLimit: '145286', gasUsed: '126711', gasPrice: '310590000', - status: 1, inputData: '0xf6d0b2ed0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002b74686f7231636c70637a676c726b7276647139787463736d6a3961386179726a656574326c6c637175666c000000000000000000000000000000000000000000', + internalTxs: [], } export default { tx } diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxStake.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxStake.ts index a48d7773812..4f3e8a21ace 100644 --- a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxStake.ts +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxStake.ts @@ -6,9 +6,9 @@ const tx: Tx = { blockHeight: 221776349, timestamp: 1718370601, status: 1, - from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + from: '0x5daF465a9cCf64DEB146eEaE9E7Bd40d6761c986', to: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', - confirmations: 5, + confirmations: 41943, value: '0', fee: '3013123887600', gasLimit: '236001', @@ -23,7 +23,7 @@ const tx: Tx = { name: 'FOX', symbol: 'FOX', type: 'ERC20', - from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + from: '0x5daF465a9cCf64DEB146eEaE9E7Bd40d6761c986', to: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', value: '1000000000000000000', }, diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxUnstake.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxUnstake.ts index b75300e574e..6496ce52a39 100644 --- a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxUnstake.ts +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxUnstake.ts @@ -5,16 +5,17 @@ const tx: Tx = { blockHash: '0x086aa823ff9e888ab8d7c3026a45de90f5a0df69fdb78ebd8b35868573387dbc', blockHeight: 221510033, timestamp: 1718304084, - from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + status: 1, + from: '0x5daF465a9cCf64DEB146eEaE9E7Bd40d6761c986', to: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', - confirmations: 265773, + confirmations: 309306, value: '0', fee: '44360779710690', gasLimit: '234173', gasUsed: '210690', gasPrice: '210550001', - status: 1, inputData: '0x2e17de780000000000000000000000000000000000000000000000002d6e3fc582c0754c', + internalTxs: [], } export default { tx } diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxWithdraw.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxWithdraw.ts index 345c6462e97..8651bf85223 100644 --- a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxWithdraw.ts +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/rfoxWithdraw.ts @@ -5,15 +5,15 @@ const tx: Tx = { blockHash: '0x34e3fdfac2e0780254ab3e1f10135bfd2097402c472862a00305b609d65cf4f5', blockHeight: 221510152, timestamp: 1718304113, - from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + status: 1, + from: '0x5daF465a9cCf64DEB146eEaE9E7Bd40d6761c986', to: '0xd612B64A134f3D4830542B7463CE8ca8a29D7268', - confirmations: 265654, + confirmations: 309455, value: '0', fee: '41698790000000', gasLimit: '195355', gasUsed: '159460', gasPrice: '261500000', - status: 1, inputData: '0x2e1a7d4d0000000000000000000000000000000000000000000000000000000000000000', tokenTransfers: [ { @@ -27,6 +27,7 @@ const tx: Tx = { value: '4364832128906250000', }, ], + internalTxs: [], } export default { tx } diff --git a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/tokens.ts b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/tokens.ts index 9e8378c0f95..685e68b33a1 100644 --- a/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/tokens.ts +++ b/packages/unchained-client/src/evm/arbitrum/parser/__tests__/mockData/tokens.ts @@ -6,3 +6,10 @@ export const usdcToken: Token = { name: 'USD Coin', symbol: 'USDC', } + +export const foxToken: Token = { + contract: '0xf929de51D91C77E42f5090069E0AD7A09e513c73', + decimals: 18, + name: 'FOX', + symbol: 'FOX', +} diff --git a/packages/unchained-client/src/evm/arbitrum/parser/index.ts b/packages/unchained-client/src/evm/arbitrum/parser/index.ts index c8d676b6455..e486bd50e76 100644 --- a/packages/unchained-client/src/evm/arbitrum/parser/index.ts +++ b/packages/unchained-client/src/evm/arbitrum/parser/index.ts @@ -9,7 +9,7 @@ import * as rfox from '../../parser/rfox' import * as zrx from '../../parser/zrx' export const ZRX_ARBITRUM_PROXY_CONTRACT = '0xDef1C0ded9bec7F1a1670819833240f027b25EfF' -const RFOX_PROXY_CONTRACT_ADDRESS = '0xd612B64A134f3D4830542B7463CE8ca8a29D7268' +export const RFOX_PROXY_CONTRACT_ADDRESS = '0xd612B64A134f3D4830542B7463CE8ca8a29D7268' export class TransactionParser extends BaseTransactionParser { constructor(args: BaseTransactionParserArgs) { diff --git a/packages/unchained-client/src/evm/parser/rfox.ts b/packages/unchained-client/src/evm/parser/rfox.ts index 3dc2e5c1d50..2557a669800 100644 --- a/packages/unchained-client/src/evm/parser/rfox.ts +++ b/packages/unchained-client/src/evm/parser/rfox.ts @@ -11,6 +11,8 @@ export interface TxMetadata extends BaseTxMetadata { parser: 'rfox' assetId: AssetId value?: string + runeAddress?: string + claimIndex?: number } export interface ParserArgs { @@ -20,9 +22,10 @@ export interface ParserArgs { export class Parser implements SubParser { private readonly proxyContract - readonly abiInterface = new ethers.Interface(RFOX_ABI) private readonly stakingAssetId: AssetId + readonly abiInterface = new ethers.Interface(RFOX_ABI) + readonly supportedFunctions = { stake: this.abiInterface.getFunction('stake')!.selector, unstake: this.abiInterface.getFunction('unstake')!.selector, @@ -48,12 +51,27 @@ export class Parser implements SubParser { if (!decoded) return - return await Promise.resolve({ - data: { - method: decoded.name, - parser: 'rfox', - assetId: this.stakingAssetId, - }, - }) + const data: TxMetadata = { + method: decoded.name, + parser: 'rfox', + assetId: this.stakingAssetId, + } + + switch (txSigHash) { + case this.supportedFunctions.unstake: + const amount = decoded.args.amount as BigInt + return await Promise.resolve({ + data: { ...data, method: `${data.method}Request`, value: amount.toString() }, + }) + case this.supportedFunctions.stake: + case this.supportedFunctions.setRuneAddress: + const runeAddress = decoded.args.runeAddress as string + return await Promise.resolve({ data: { ...data, runeAddress } }) + case this.supportedFunctions.withdrawClaim: + const index = decoded.args.index as BigInt + return await Promise.resolve({ data: { ...data, claimIndex: Number(index) } }) + default: + return await Promise.resolve({ data }) + } } } From 0c9f53a2e186e86daae063a524801294995cf219 Mon Sep 17 00:00:00 2001 From: kaladinlight <35275952+kaladinlight@users.noreply.github.com> Date: Fri, 14 Jun 2024 11:43:33 -0600 Subject: [PATCH 6/6] update transaction row details --- src/assets/translations/en/main.json | 2 +- .../TransactionDetails/Amount.tsx | 42 ++++++++++++------- .../TransactionGenericRow.tsx | 19 ++++++++- src/hooks/useTxDetails/useTxDetails.ts | 1 + 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/assets/translations/en/main.json b/src/assets/translations/en/main.json index 8681a63c696..b1b10327415 100644 --- a/src/assets/translations/en/main.json +++ b/src/assets/translations/en/main.json @@ -643,7 +643,7 @@ "rfox": { "stake": "Stake", "withdraw": "Withdraw", - "unstake": "Unstake", + "unstakeRequest": "Unstake Request", "setRuneAddress": "Set Rune Address" }, diff --git a/src/components/TransactionHistoryRows/TransactionDetails/Amount.tsx b/src/components/TransactionHistoryRows/TransactionDetails/Amount.tsx index 42fe3bb3636..d1ec2c9e954 100644 --- a/src/components/TransactionHistoryRows/TransactionDetails/Amount.tsx +++ b/src/components/TransactionHistoryRows/TransactionDetails/Amount.tsx @@ -1,19 +1,33 @@ +import type { AssetId } from '@shapeshiftoss/caip' import { Amount as AmountComponent } from 'components/Amount/Amount' import { fromBaseUnit } from 'lib/math' +import { selectAssetById } from 'state/slices/selectors' +import { useAppSelector } from 'state/store' -export const Amount = ({ - value, - symbol, - precision, -}: { +type AmountArgs = { value: string - symbol: string - precision: number -}) => ( - +} & ( + | { + assetId: AssetId + precision?: never + symbol?: never + } + | { + assetId?: never + precision: number + symbol: string + } ) + +export const Amount = ({ value, symbol, precision, assetId }: AmountArgs) => { + const asset = useAppSelector(state => selectAssetById(state, assetId ?? '')) + + return ( + + ) +} diff --git a/src/components/TransactionHistoryRows/TransactionGenericRow.tsx b/src/components/TransactionHistoryRows/TransactionGenericRow.tsx index fb29323a4fa..2f9e0b3fdd1 100644 --- a/src/components/TransactionHistoryRows/TransactionGenericRow.tsx +++ b/src/components/TransactionHistoryRows/TransactionGenericRow.tsx @@ -1,5 +1,5 @@ import { ChevronRightIcon } from '@chakra-ui/icons' -import { Center, Flex, HStack } from '@chakra-ui/react' +import { Center, Flex, HStack, Tag } from '@chakra-ui/react' import type { AssetId } from '@shapeshiftoss/caip' import type { TxMetadata } from '@shapeshiftoss/chain-adapters' import type { Asset } from '@shapeshiftoss/types' @@ -17,6 +17,7 @@ import { fromBaseUnit } from 'lib/math' import { middleEllipsis } from 'lib/utils' import type { TxId } from 'state/slices/txHistorySlice/txHistorySlice' +import { Amount as CryptoAmount } from './TransactionDetails/Amount' import { ApprovalAmount } from './TransactionDetails/ApprovalAmount' import { TransactionTag } from './TransactionTag' import { TransactionTeaser } from './TransactionTeaser' @@ -175,10 +176,14 @@ export const TransactionGenericRow = ({ // asset(s) label const bottomLeft = useMemo(() => { - if (type === Method.Approve) { + if (type === Method.Approve || txData?.method === Method.UnstakeRequest) { return } + if (txData?.parser === 'rfox' && txData?.method === Method.SetRuneAddress) { + return {txData.runeAddress ?? ''} + } + if (hasNoTransfers) return // send only @@ -263,6 +268,7 @@ export const TransactionGenericRow = ({ uniqueAssets, transfersByType.Receive, transfersByType.Send, + txData, txMetadataWithAssetId?.assetId, type, divider, @@ -281,6 +287,14 @@ export const TransactionGenericRow = ({ ) } + if (txData?.parser === 'rfox' && txData?.method === Method.UnstakeRequest) { + return ( + + + + ) + } + if (hasNoReceiveAssets) return sendAmount if (hasSingleReceiveAsset) { @@ -314,6 +328,7 @@ export const TransactionGenericRow = ({ hasSingleReceiveAsset, hasManyReceiveAssets, transfersByType.Receive, + txData, txMetadataWithAssetId?.assetId, txMetadataWithAssetId?.parser, txMetadataWithAssetId?.value, diff --git a/src/hooks/useTxDetails/useTxDetails.ts b/src/hooks/useTxDetails/useTxDetails.ts index 6cfb6a5be69..008af562fa8 100644 --- a/src/hooks/useTxDetails/useTxDetails.ts +++ b/src/hooks/useTxDetails/useTxDetails.ts @@ -55,6 +55,7 @@ export enum Method { SwapRefund = 'swapRefund', Transfer = 'transfer', Unstake = 'unstake', + UnstakeRequest = 'unstakeRequest', Withdraw = 'withdraw', WithdrawNative = 'withdrawNative', WithdrawDelegatorReward = 'withdraw_delegator_reward',