diff --git a/.changeset/sour-bikes-occur.md b/.changeset/sour-bikes-occur.md new file mode 100644 index 00000000..ab357813 --- /dev/null +++ b/.changeset/sour-bikes-occur.md @@ -0,0 +1,5 @@ +--- +'@3loop/transaction-interpreter': patch +--- + +Add context field to the intepreted swap transacitons diff --git a/packages/transaction-interpreter/interpreters/1inch.ts b/packages/transaction-interpreter/interpreters/1inch.ts index f274e3a5..7c825732 100644 --- a/packages/transaction-interpreter/interpreters/1inch.ts +++ b/packages/transaction-interpreter/interpreters/1inch.ts @@ -1,29 +1,9 @@ -import { displayAsset, getNetTransfers, isSwap, defaultEvent } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' +import { genericSwapInterpreter } from './std.js' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = defaultEvent(event) - - const netSent = getNetTransfers({ - transfers: event.transfers, - fromAddresses: [event.fromAddress], - }) - - const netReceived = getNetTransfers({ - transfers: event.transfers, - toAddresses: [event.fromAddress], - }) - - if (isSwap(event)) { - return { - ...newEvent, - type: 'swap', - action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), - } - } - - return newEvent + return genericSwapInterpreter(event) } export const contracts = [ diff --git a/packages/transaction-interpreter/interpreters/aa.ts b/packages/transaction-interpreter/interpreters/aa.ts index 2af5a3cb..25d3dd9e 100644 --- a/packages/transaction-interpreter/interpreters/aa.ts +++ b/packages/transaction-interpreter/interpreters/aa.ts @@ -1,16 +1,10 @@ -import { - assetsReceived, - assetsSent, - categorizedDefaultEvent, - displayAddress, - displayAsset, - toAssetTransfer, -} from './std.js' +import { assetsReceived, assetsSent, genericInterpreter, displayAddress, displayAsset, toAssetTransfer } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = categorizedDefaultEvent(event) + const newEvent = genericInterpreter(event) + const userOpEvents = event.interactions.filter((e) => e.event.eventName === 'UserOperationEvent') if (newEvent.type !== 'unknown') { diff --git a/packages/transaction-interpreter/interpreters/aerodrom.ts b/packages/transaction-interpreter/interpreters/aerodrom.ts index 82bbaac0..00bd2d68 100644 --- a/packages/transaction-interpreter/interpreters/aerodrom.ts +++ b/packages/transaction-interpreter/interpreters/aerodrom.ts @@ -1,29 +1,9 @@ -import { displayAsset, getNetTransfers, isSwap, defaultEvent } from './std.js' +import { genericSwapInterpreter } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = defaultEvent(event) - - const netSent = getNetTransfers({ - transfers: event.transfers, - fromAddresses: [event.fromAddress], - }) - - const netReceived = getNetTransfers({ - transfers: event.transfers, - toAddresses: [event.fromAddress], - }) - - if (isSwap(event)) { - return { - ...newEvent, - type: 'swap', - action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), - } - } - - return newEvent + return genericSwapInterpreter(event) } export const contracts = ['8453:0x6cb442acf35158d5eda88fe602221b67b400be3e'] diff --git a/packages/transaction-interpreter/interpreters/banana-gun.ts b/packages/transaction-interpreter/interpreters/banana-gun.ts index 54e33af9..f22236d4 100644 --- a/packages/transaction-interpreter/interpreters/banana-gun.ts +++ b/packages/transaction-interpreter/interpreters/banana-gun.ts @@ -1,29 +1,9 @@ -import { displayAsset, getNetTransfers, isSwap, defaultEvent } from './std.js' +import { genericSwapInterpreter } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = defaultEvent(event) - - const netSent = getNetTransfers({ - transfers: event.transfers, - fromAddresses: [event.fromAddress], - }) - - const netReceived = getNetTransfers({ - transfers: event.transfers, - toAddresses: [event.fromAddress], - }) - - if (isSwap(event)) { - return { - ...newEvent, - type: 'swap', - action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), - } - } - - return newEvent + return genericSwapInterpreter(event) } export const contracts = [ diff --git a/packages/transaction-interpreter/interpreters/erc1155.ts b/packages/transaction-interpreter/interpreters/erc1155.ts index 6d953933..8e22feda 100644 --- a/packages/transaction-interpreter/interpreters/erc1155.ts +++ b/packages/transaction-interpreter/interpreters/erc1155.ts @@ -1,10 +1,10 @@ -import { assetsReceived, assetsSent, categorizedDefaultEvent } from './std.js' +import { assetsReceived, assetsSent, genericInterpreter } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { const methodName = event.methodCall.name - const newEvent = categorizedDefaultEvent(event) + const newEvent = genericInterpreter(event) switch (methodName) { case 'setApprovalForAll': { diff --git a/packages/transaction-interpreter/interpreters/erc20.ts b/packages/transaction-interpreter/interpreters/erc20.ts index 1c0f5674..335a276b 100644 --- a/packages/transaction-interpreter/interpreters/erc20.ts +++ b/packages/transaction-interpreter/interpreters/erc20.ts @@ -1,10 +1,10 @@ -import { assetsReceived, assetsSent, formatNumber, categorizedDefaultEvent, displayAsset } from './std.js' +import { assetsReceived, assetsSent, formatNumber, genericInterpreter, displayAsset } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { const methodName = event.methodCall.name - const newEvent = categorizedDefaultEvent(event) + const newEvent = genericInterpreter(event) switch (methodName) { case 'approve': { diff --git a/packages/transaction-interpreter/interpreters/erc721.ts b/packages/transaction-interpreter/interpreters/erc721.ts index 25f8db83..0c9205cf 100644 --- a/packages/transaction-interpreter/interpreters/erc721.ts +++ b/packages/transaction-interpreter/interpreters/erc721.ts @@ -1,10 +1,10 @@ -import { assetsReceived, assetsSent, categorizedDefaultEvent } from './std.js' +import { assetsReceived, assetsSent, genericInterpreter } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { const methodName = event.methodCall.name - const newEvent = categorizedDefaultEvent(event) + const newEvent = genericInterpreter(event) switch (methodName) { case 'approve': { diff --git a/packages/transaction-interpreter/interpreters/fallback.ts b/packages/transaction-interpreter/interpreters/fallback.ts index 87e25e2a..38bfa9bf 100644 --- a/packages/transaction-interpreter/interpreters/fallback.ts +++ b/packages/transaction-interpreter/interpreters/fallback.ts @@ -1,9 +1,7 @@ import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' -import { categorizedDefaultEvent } from './std.js' +import { genericInterpreter } from './std.js' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = categorizedDefaultEvent(event) - - return newEvent + return genericInterpreter(event) } diff --git a/packages/transaction-interpreter/interpreters/gnosis-safe.ts b/packages/transaction-interpreter/interpreters/gnosis-safe.ts index 21bf1e6f..5728d7d8 100644 --- a/packages/transaction-interpreter/interpreters/gnosis-safe.ts +++ b/packages/transaction-interpreter/interpreters/gnosis-safe.ts @@ -1,9 +1,9 @@ import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' -import { assetsSent, assetsReceived, categorizedDefaultEvent } from './std.js' +import { assetsSent, assetsReceived, genericInterpreter } from './std.js' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = categorizedDefaultEvent(event) + const newEvent = genericInterpreter(event) const methodName = event.methodCall?.name const safeMultisigEvent = event.interactions.find((i) => i.event.eventName === 'SafeMultiSigTransaction') const successEvents = event.interactions.filter((i) => i.event.eventName === 'ExecutionSuccess') diff --git a/packages/transaction-interpreter/interpreters/kyberswap.ts b/packages/transaction-interpreter/interpreters/kyberswap.ts index c24ff12d..cf3cc882 100644 --- a/packages/transaction-interpreter/interpreters/kyberswap.ts +++ b/packages/transaction-interpreter/interpreters/kyberswap.ts @@ -1,29 +1,9 @@ -import { displayAsset, getNetTransfers, isSwap, defaultEvent } from './std.js' +import { genericSwapInterpreter } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = defaultEvent(event) - - const netSent = getNetTransfers({ - transfers: event.transfers, - fromAddresses: [event.fromAddress], - }) - - const netReceived = getNetTransfers({ - transfers: event.transfers, - toAddresses: [event.fromAddress], - }) - - if (isSwap(event)) { - return { - ...newEvent, - type: 'swap', - action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), - } - } - - return newEvent + return genericSwapInterpreter(event) } export const contracts = [ diff --git a/packages/transaction-interpreter/interpreters/metamaskRouter.ts b/packages/transaction-interpreter/interpreters/metamaskRouter.ts index 4c228ce9..585902d6 100644 --- a/packages/transaction-interpreter/interpreters/metamaskRouter.ts +++ b/packages/transaction-interpreter/interpreters/metamaskRouter.ts @@ -1,29 +1,9 @@ -import { displayAsset, getNetTransfers, isSwap, defaultEvent } from './std.js' +import { genericSwapInterpreter } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = defaultEvent(event) - - const netSent = getNetTransfers({ - transfers: event.transfers, - fromAddresses: [event.fromAddress], - }) - - const netReceived = getNetTransfers({ - transfers: event.transfers, - toAddresses: [event.fromAddress], - }) - - if (isSwap(event)) { - return { - ...newEvent, - type: 'swap', - action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), - } - } - - return newEvent + return genericSwapInterpreter(event) } export const contracts = ['1:0x881D40237659C251811CEC9c364ef91dC08D300C'] diff --git a/packages/transaction-interpreter/interpreters/moxie.ts b/packages/transaction-interpreter/interpreters/moxie.ts index 002cf36c..469c2007 100644 --- a/packages/transaction-interpreter/interpreters/moxie.ts +++ b/packages/transaction-interpreter/interpreters/moxie.ts @@ -2,7 +2,7 @@ import { displayAsset, formatNumber, NULL_ADDRESS, - categorizedDefaultEvent, + genericInterpreter, toAssetTransfer, assetsSent, assetsReceived, @@ -22,7 +22,7 @@ import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { const methodName = event.methodCall.name - const newEvent = categorizedDefaultEvent(event) + const newEvent = genericInterpreter(event) const { assetsMinted, assetsBurned } = newEvent const purchaseOrSaleEvent = event.interactions.find( diff --git a/packages/transaction-interpreter/interpreters/okx.ts b/packages/transaction-interpreter/interpreters/okx.ts index fa88bf67..697177c0 100644 --- a/packages/transaction-interpreter/interpreters/okx.ts +++ b/packages/transaction-interpreter/interpreters/okx.ts @@ -1,29 +1,9 @@ -import { displayAsset, getNetTransfers, isSwap, defaultEvent } from './std.js' +import { genericSwapInterpreter } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = defaultEvent(event) - - const netSent = getNetTransfers({ - transfers: event.transfers, - fromAddresses: [event.fromAddress], - }) - - const netReceived = getNetTransfers({ - transfers: event.transfers, - toAddresses: [event.fromAddress], - }) - - if (isSwap(event)) { - return { - ...newEvent, - type: 'swap', - action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), - } - } - - return newEvent + return genericSwapInterpreter(event) } export const contracts = [ diff --git a/packages/transaction-interpreter/interpreters/pendle.ts b/packages/transaction-interpreter/interpreters/pendle.ts index c20787ab..ce2a31f3 100644 --- a/packages/transaction-interpreter/interpreters/pendle.ts +++ b/packages/transaction-interpreter/interpreters/pendle.ts @@ -1,29 +1,9 @@ -import { displayAsset, getNetTransfers, isSwap, defaultEvent } from './std.js' +import { genericSwapInterpreter } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = defaultEvent(event) - - const netSent = getNetTransfers({ - transfers: event.transfers, - fromAddresses: [event.fromAddress], - }) - - const netReceived = getNetTransfers({ - transfers: event.transfers, - toAddresses: [event.fromAddress], - }) - - if (isSwap(event)) { - return { - ...newEvent, - type: 'swap', - action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), - } - } - - return newEvent + return genericSwapInterpreter(event) } export const contracts = [ diff --git a/packages/transaction-interpreter/interpreters/rainbow.ts b/packages/transaction-interpreter/interpreters/rainbow.ts index f4ffba2a..3a13294e 100644 --- a/packages/transaction-interpreter/interpreters/rainbow.ts +++ b/packages/transaction-interpreter/interpreters/rainbow.ts @@ -1,28 +1,9 @@ -import { displayAsset, getNetTransfers, defaultEvent } from './std.js' +import { genericSwapInterpreter } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = defaultEvent(event) - - const netSent = getNetTransfers({ - transfers: event.transfers, - fromAddresses: [event.fromAddress], - }) - - const netReceived = getNetTransfers({ - transfers: event.transfers, - toAddresses: [event.fromAddress], - }) - - if (netSent.length === 1 && netReceived.length === 1) { - return { - ...newEvent, - type: 'swap', - action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), - } - } - return newEvent + return genericSwapInterpreter(event) } export const contracts = ['8453:0x00000000009726632680FB29d3F7A9734E3010E2'] diff --git a/packages/transaction-interpreter/interpreters/std.ts b/packages/transaction-interpreter/interpreters/std.ts index ab350cf2..171d1500 100644 --- a/packages/transaction-interpreter/interpreters/std.ts +++ b/packages/transaction-interpreter/interpreters/std.ts @@ -1,4 +1,4 @@ -import type { AssetTransfer, InterpretedTransaction, Payment } from '@/types.js' +import type { AssetTransfer, InterpretedTransaction, InterpretedSwapTransaction } from '@/types.js' import { Asset, DecodedTransaction } from '@3loop/transaction-decoder' export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000' @@ -13,6 +13,8 @@ interface FilterOptions { sumUpRepeated?: boolean } +type Payment = Omit + export const filterTransfers = (transfers: Asset[], filters: FilterOptions = {}): Asset[] => { let filtered = [...transfers] @@ -307,7 +309,40 @@ export function defaultEvent(event: DecodedTransaction): InterpretedTransaction return newEvent } -export function categorizedDefaultEvent(event: DecodedTransaction): InterpretedTransaction { +// ------------------------------------------------------------------------------ +// Generic Interpreters + +export function genericSwapInterpreter(event: DecodedTransaction): InterpretedTransaction { + const newEvent = defaultEvent(event) + + const netSent = getNetTransfers({ + transfers: event.transfers, + fromAddresses: [event.fromAddress], + }) + + const netReceived = getNetTransfers({ + transfers: event.transfers, + toAddresses: [event.fromAddress], + }) + + if (isSwap(event)) { + const swapEvent: InterpretedSwapTransaction = { + ...newEvent, + type: 'swap', + action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), + context: { + sent: [netSent[0]], + received: [netReceived[0]], + }, + } + + return swapEvent + } + + return newEvent +} + +export function genericInterpreter(event: DecodedTransaction): InterpretedTransaction { const newEvent = defaultEvent(event) const transfers = filterTransfers(event.transfers, { excludeDuplicates: true, @@ -365,7 +400,9 @@ export function categorizedDefaultEvent(event: DecodedTransaction): InterpretedT nonZeroTransfers[0].to.toLowerCase() === event.fromAddress.toLowerCase() ? event.fromAddress : nonZeroTransfers[0].from + const asset = toAssetTransfer(nonZeroTransfers[0]) + return { ...newEvent, type: 'transfer-token', @@ -375,22 +412,9 @@ export function categorizedDefaultEvent(event: DecodedTransaction): InterpretedT } } + //Generic Swap Interpreter if (isSwap(event)) { - const netSent = getNetTransfers({ - transfers: event.transfers, - fromAddresses: [event.fromAddress], - }) - - const netReceived = getNetTransfers({ - transfers: event.transfers, - toAddresses: [event.fromAddress], - }) - - return { - ...newEvent, - type: 'swap', - action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), - } + return genericSwapInterpreter(event) } return newEvent diff --git a/packages/transaction-interpreter/interpreters/uniswapv3.ts b/packages/transaction-interpreter/interpreters/uniswapv3.ts index e69d40ff..e9c84e4a 100644 --- a/packages/transaction-interpreter/interpreters/uniswapv3.ts +++ b/packages/transaction-interpreter/interpreters/uniswapv3.ts @@ -1,30 +1,9 @@ -import { displayAsset, defaultEvent, getNetTransfers, isSwap } from './std.js' +import { genericSwapInterpreter } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = defaultEvent(event) - const hasSwap = event.traceCalls.some((call) => call.name === 'swap') - - if (hasSwap && isSwap(event)) { - const netSent = getNetTransfers({ - transfers: event.transfers, - fromAddresses: [event.fromAddress], - }) - - const netReceived = getNetTransfers({ - transfers: event.transfers, - toAddresses: [event.fromAddress], - }) - - return { - ...newEvent, - type: 'swap', - action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), - } - } - - return newEvent + return genericSwapInterpreter(event) } export const contracts = [ diff --git a/packages/transaction-interpreter/interpreters/zeroEx.ts b/packages/transaction-interpreter/interpreters/zeroEx.ts index 237655b0..23dc6a5e 100644 --- a/packages/transaction-interpreter/interpreters/zeroEx.ts +++ b/packages/transaction-interpreter/interpreters/zeroEx.ts @@ -1,9 +1,9 @@ -import { assetsReceived, categorizedDefaultEvent, displayAsset, getNetTransfers, filterTransfers } from './std.js' +import { assetsReceived, genericInterpreter, displayAsset, getNetTransfers, filterTransfers } from './std.js' import type { InterpretedTransaction } from '@/types.js' import type { DecodedTransaction } from '@3loop/transaction-decoder' export function transformEvent(event: DecodedTransaction): InterpretedTransaction { - const newEvent = categorizedDefaultEvent(event) + const newEvent = genericInterpreter(event) if (newEvent.type !== 'unknown') return newEvent @@ -49,6 +49,10 @@ export function transformEvent(event: DecodedTransaction): InterpretedTransactio ...newEvent, type: 'swap', action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]), + context: { + sent: [netSent[0]], + received: [netReceived[0]], + }, assetsReceived: assetsReceived( filteredTransfers.filter((t) => receivedTokens.includes(t.address)), event.fromAddress, diff --git a/packages/transaction-interpreter/src/types.ts b/packages/transaction-interpreter/src/types.ts index b164c89e..1baa96f2 100644 --- a/packages/transaction-interpreter/src/types.ts +++ b/packages/transaction-interpreter/src/types.ts @@ -49,18 +49,32 @@ export type AssetTransfer = { asset: Asset } -export type Payment = Omit - -export type InterpretedTransaction = { +export interface GenericInterpretedTransaction { + type: TransactionType chain: number action: string txHash: string timestamp: number user: Address method: string | null - type: TransactionType assetsSent: AssetTransfer[] assetsReceived: AssetTransfer[] assetsMinted?: AssetTransfer[] assetsBurned?: AssetTransfer[] } + +export interface InterpretedSwapTransaction extends GenericInterpretedTransaction { + type: 'swap' + context: { + sent: { + amount: string + asset: Asset + }[] + received: { + amount: string + asset: Asset + }[] + } +} + +export type InterpretedTransaction = GenericInterpretedTransaction | InterpretedSwapTransaction