From 4b8351607da8acbb17bb4d345424e3dd49da1e3f Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Thu, 30 Nov 2023 07:28:17 -0800 Subject: [PATCH 1/5] feat: update erc1155 sale --- src/heuristics/erc1155Purchase.spec.ts | 22 +-- src/heuristics/erc1155Sale.spec.ts | 12 ++ src/heuristics/erc1155Sale.ts | 148 +++++++++++++++++ src/heuristics/erc1155Swap.ts | 100 ------------ src/heuristics/erc721Sale.ts | 150 ++++++++++++++++++ src/heuristics/erc721Swap.ts | 99 ------------ src/heuristics/index.ts | 2 - ...2334d.json => erc1155Sale-0x16b2334d.json} | 0 8 files changed, 321 insertions(+), 212 deletions(-) create mode 100644 src/heuristics/erc1155Sale.spec.ts create mode 100644 src/heuristics/erc1155Sale.ts delete mode 100644 src/heuristics/erc1155Swap.ts create mode 100644 src/heuristics/erc721Sale.ts delete mode 100644 src/heuristics/erc721Swap.ts rename src/test/transactions/{erc1155Purchase-0x16b2334d.json => erc1155Sale-0x16b2334d.json} (100%) diff --git a/src/heuristics/erc1155Purchase.spec.ts b/src/heuristics/erc1155Purchase.spec.ts index 7fe978fa..e5950df4 100644 --- a/src/heuristics/erc1155Purchase.spec.ts +++ b/src/heuristics/erc1155Purchase.spec.ts @@ -1,12 +1,12 @@ -import { Transaction } from '../types'; -import { detectERC1155Purchase } from './erc1155Purchase'; -import erc1155Purchase0x16b2334d from '../test/transactions/erc1155Purchase-0x16b2334d.json'; +// import { Transaction } from '../types'; +// import { detectERC1155Purchase } from './erc1155Purchase'; +// import erc1155Purchase0x16b2334d from '../test/transactions/erc1155Purchase-0x16b2334d.json'; -describe('ERC1155 Purchase', () => { - it('Should detect ERC1155 Purchase transaction', () => { - const isERC1155Purchase1 = detectERC1155Purchase( - erc1155Purchase0x16b2334d as Transaction, - ); - expect(isERC1155Purchase1).toBe(true); - }); -}); +// describe('ERC1155 Purchase', () => { +// it('Should detect ERC1155 Purchase transaction', () => { +// const isERC1155Purchase1 = detectERC1155Purchase( +// erc1155Purchase0x16b2334d as Transaction, +// ); +// expect(isERC1155Purchase1).toBe(true); +// }); +// }); diff --git a/src/heuristics/erc1155Sale.spec.ts b/src/heuristics/erc1155Sale.spec.ts new file mode 100644 index 00000000..9e4cf795 --- /dev/null +++ b/src/heuristics/erc1155Sale.spec.ts @@ -0,0 +1,12 @@ +import { Transaction } from '../types'; +import { detectERC1155Sale } from './erc1155Sale'; +import erc1155Sale0x16b2334d from '../test/transactions/erc1155Sale-0x16b2334d.json'; + +describe('ERC1155 Sale', () => { + it('Should detect ERC1155 Sale transaction', () => { + const isERC1155Sale1 = detectERC1155Sale( + erc1155Sale0x16b2334d as Transaction, + ); + expect(isERC1155Sale1).toBe(true); + }); +}); diff --git a/src/heuristics/erc1155Sale.ts b/src/heuristics/erc1155Sale.ts new file mode 100644 index 00000000..880d11b0 --- /dev/null +++ b/src/heuristics/erc1155Sale.ts @@ -0,0 +1,148 @@ +import { ethers } from 'ethers'; +import { Asset, Transaction } from '../types'; + +export function erc1155SaleContextualizer( + transaction: Transaction, +): Transaction { + const isERC1155Sale = detectERC1155Sale(transaction); + if (!isERC1155Sale) return transaction; + + return generateERC1155SaleContext(transaction); +} + +/** + * Detection criteria + * + * A tx is an ERC1155 sale when the tx.from sends and receives exactly 1 asset (look at netAssetTransfers). + * The tx.from must send exactly 1 ERC1155, where the value (special to 1155s) can be arbitrary + * The tx.from must receive either ETH/WETH/Blur ETH + * There are no other recipients of ERC721/ERC20s/ERC1155s. + */ +export function detectERC1155Sale(transaction: Transaction): boolean { + /** + * There is a degree of overlap between the 'detect' and 'generateContext' functions, + * and while this might seem redundant, maintaining the 'detect' function aligns with + * established patterns in our other modules. This consistency is beneficial, + * and it also serves to decouple the logic, thereby simplifying the testing process + */ + + if (!transaction.netAssetTransfers) return false; + + const addresses = transaction.netAssetTransfers + ? Object.keys(transaction.netAssetTransfers) + : []; + // check if transfer.from sent and received one asset + const transfers = transaction.netAssetTransfers[transaction.from]; + const nftsSent = transfers.sent.filter((t) => t.type === 'erc1155'); + const tokenReceived = transfers.received.filter( + (t) => t.type === 'eth' || t.type === 'erc20', + ); + + if (nftsSent.length > 0 && tokenReceived.length > 0) { + return true; + } + + return false; +} + +function generateERC1155SaleContext(transaction: Transaction): Transaction { + const receivingAddresses: string[] = []; + const receivedNfts: Asset[] = []; + const sentPayments: { type: string; asset: string; value: string }[] = []; + + for (const [address, data] of Object.entries(transaction.netAssetTransfers)) { + const nftTransfers = data.received.filter((t) => t.type === 'erc1155'); + const paymentTransfers = data.sent.filter( + (t) => t.type === 'erc20' || t.type === 'eth', + ); + if (nftTransfers.length > 0) { + receivingAddresses.push(address); + nftTransfers.forEach((nft) => receivedNfts.push(nft)); + } + if (paymentTransfers.length > 0) { + paymentTransfers.forEach((payment) => + sentPayments.push({ + type: payment.type, + asset: payment.asset, + value: payment.value, + }), + ); + } + } + + const receivedNftContracts = Array.from( + new Set(receivedNfts.map((x) => x.asset)), + ); + const totalPayments = Object.values( + sentPayments.reduce((acc, next) => { + acc[next.asset] = { + type: next.type, + asset: next.asset, + value: ethers.BigNumber.from(acc[next.asset]?.value || '0') + .add(next.value) + .toString(), + }; + return acc; + }, {}), + ) as { type: 'eth' | 'erc20'; asset: string; value: string }[]; + + transaction.context = { + variables: { + userOrUsers: { + type: receivingAddresses.length > 1 ? 'emphasis' : 'address', + value: + receivingAddresses.length > 1 + ? `${receivingAddresses.length} Users` + : receivingAddresses[0], + }, + tokenOrTokens: + receivedNfts.length === 1 + ? { + type: 'erc1155', + token: receivedNfts[0].asset, + tokenId: receivedNfts[0].tokenId, + value: receivedNfts[0].value, + } + : receivedNftContracts.length === 1 + ? { + type: 'address', + value: receivedNftContracts[0], + } + : { + type: 'emphasis', + value: `${receivedNfts.length} NFTs`, + }, + price: + totalPayments.length > 1 + ? { + type: 'emphasis', + value: `${totalPayments.length} Assets`, + } + : totalPayments[0].type === 'eth' + ? { + type: 'eth', + value: totalPayments[0].value, + } + : { + type: 'erc20', + token: totalPayments[0].asset, + value: totalPayments[0].value, + }, + }, + summaries: { + category: 'NFT', + en: { + title: 'NFT Purchase', + default: '[[userOrUsers]] [[bought]] [[tokenOrTokens]] for [[price]]', + variables: { + bought: { + type: 'contextAction', + value: 'bought', + }, + }, + }, + }, + }; + + return transaction; +} diff --git a/src/heuristics/erc1155Swap.ts b/src/heuristics/erc1155Swap.ts deleted file mode 100644 index 73d77b86..00000000 --- a/src/heuristics/erc1155Swap.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Transaction } from '../types'; -import { TOKEN_SWAP_CONTRACTS } from '../helpers/constants'; - -export function erc1155SwapContextualizer( - transaction: Transaction, -): Transaction { - const isERC1155Purchase = detectERC1155Swap(transaction); - if (!isERC1155Purchase) return transaction; - - return generateERC1155SwapContext(transaction); -} - -function detectERC1155Swap(transaction: Transaction): boolean { - /** - * There is a degree of overlap between the 'detect' and 'generateContext' functions, - * and while this might seem redundant, maintaining the 'detect' function aligns with - * established patterns in our other modules. This consistency is beneficial, - * and it also serves to decouple the logic, thereby simplifying the testing process - */ - - // Break if this transaction isn't to a token swap contract - if (TOKEN_SWAP_CONTRACTS.indexOf(transaction.to) === -1) { - return false; - } - - const addresses = transaction.netAssetTransfers - ? Object.keys(transaction.netAssetTransfers) - : []; - - for (let i = 0; i < addresses.length; i++) { - const address = addresses[i]; - const sent = transaction.netAssetTransfers[address].sent; - const received = transaction.netAssetTransfers[address].received; - - const sentCount = sent?.length || 0; - const receivedCount = received?.length || 0; - if (sentCount === 1 && receivedCount === 1) { - if (transaction.netAssetTransfers[address].sent[0].type === 'erc1155') { - return true; - } - } - } - - return false; -} - -function generateERC1155SwapContext(transaction: Transaction): Transaction { - const addresses = transaction.netAssetTransfers - ? Object.keys(transaction.netAssetTransfers) - : []; - - for (let i = 0; i < addresses.length; i++) { - const address = addresses[i]; - const sent = transaction.netAssetTransfers[address].sent; - const received = transaction.netAssetTransfers[address].received; - - const sentCount = sent?.length || 0; - const receivedCount = received?.length || 0; - if (sentCount === 1 && receivedCount === 1) { - if (transaction.netAssetTransfers[address].sent[0].type === 'erc1155') { - transaction.context = { - variables: { - swapper: { - type: 'address', - value: address, - }, - sentToken: { - token: sent[0].asset, - type: sent[0].type, - value: sent[0].value, - }, - receivedToken: { - token: received[0].asset, - type: received[0].type, - value: received[0].value, - }, - }, - summaries: { - category: 'NFT', - en: { - title: 'ERC1155 Swap', - default: - '[[swapper]] [[swapped]] [[sentToken]] for [[receivedToken]]', - variables: { - swapped: { - type: 'contextAction', - value: 'swapped', - }, - }, - }, - }, - }; - - break; - } - } - } - - return transaction; -} diff --git a/src/heuristics/erc721Sale.ts b/src/heuristics/erc721Sale.ts new file mode 100644 index 00000000..de246ac4 --- /dev/null +++ b/src/heuristics/erc721Sale.ts @@ -0,0 +1,150 @@ +import { ethers } from 'ethers'; +import { Asset, Transaction } from '../types'; + +export function erc721SaleContextualizer( + transaction: Transaction, +): Transaction { + const isERC721SaleTransaction = detectERC721Sale(transaction); + + if (!isERC721SaleTransaction) return transaction; + + return generateERC21PurchaseContext(transaction); +} + +export function detectERC721Sale(transaction: Transaction): boolean { + /** + * There is a degree of overlap between the 'detect' and 'generateContext' functions, + * and while this might seem redundant, maintaining the 'detect' function aligns with + * established patterns in our other modules. This consistency is beneficial, + * and it also serves to decouple the logic, thereby simplifying the testing process + */ + if (!transaction.netAssetTransfers) return false; + + const addresses = transaction.netAssetTransfers + ? Object.keys(transaction.netAssetTransfers) + : []; + + for (const address of addresses) { + const transfers = transaction.netAssetTransfers[address]; + const nftsReceived = transfers.received.filter((t) => t.type === 'erc721'); + const nftsSent = transfers.sent.filter((t) => t.type === 'erc721'); + + const ethOrErc20Sent = transfers.sent.filter( + (t) => t.type === 'eth' || t.type === 'erc20', + ); + const ethOrErc20Received = transfers.received.filter( + (t) => t.type === 'eth' || t.type === 'erc20', + ); + + if (nftsReceived.length > 0 && ethOrErc20Sent.length > 0) { + return true; + } + + if (nftsSent.length > 0 && ethOrErc20Received.length > 0) { + return true; + } + } + + return false; +} + +function generateERC21PurchaseContext(transaction: Transaction): Transaction { + const receivingAddresses: string[] = []; + const receivedNfts: Asset[] = []; + const sentPayments: { type: string; asset: string; value: string }[] = []; + + for (const [address, data] of Object.entries(transaction.netAssetTransfers)) { + const nftTransfers = data.received.filter((t) => t.type === 'erc721'); + const paymentTransfers = data.sent.filter( + (t) => t.type === 'erc20' || t.type === 'eth', + ); + if (nftTransfers.length > 0) { + receivingAddresses.push(address); + nftTransfers.forEach((nft) => receivedNfts.push(nft)); + } + if (paymentTransfers.length > 0) { + paymentTransfers.forEach((payment) => + sentPayments.push({ + type: payment.type, + asset: payment.asset, + value: payment.value, + }), + ); + } + } + + const receivedNftContracts = Array.from( + new Set(receivedNfts.map((x) => x.asset)), + ); + const totalPayments = Object.values( + sentPayments.reduce((acc, next) => { + acc[next.asset] = { + type: next.type, + asset: next.asset, + value: ethers.BigNumber.from(acc[next.asset]?.value || '0') + .add(next.value) + .toString(), + }; + return acc; + }, {}), + ) as { type: 'eth' | 'erc20'; asset: string; value: string }[]; + + transaction.context = { + variables: { + userOrUsers: { + type: receivingAddresses.length > 1 ? 'emphasis' : 'address', + value: + receivingAddresses.length > 1 + ? `${receivingAddresses.length} Users` + : receivingAddresses[0], + }, + tokenOrTokens: + receivedNfts.length === 1 + ? { + type: 'erc721', + token: receivedNfts[0].asset, + tokenId: receivedNfts[0].tokenId, + } + : receivedNftContracts.length === 1 + ? { + type: 'address', + value: receivedNftContracts[0], + } + : { + type: 'emphasis', + value: `${receivedNfts.length} NFTs`, + }, + price: + totalPayments.length > 1 + ? { + type: 'emphasis', + value: `${totalPayments.length} Assets`, + } + : totalPayments[0].type === 'eth' + ? { + type: 'eth', + value: totalPayments[0].value, + } + : { + type: 'erc20', + token: totalPayments[0].asset, + value: totalPayments[0].value, + }, + }, + summaries: { + category: 'NFT', + en: { + title: 'NFT Purchase', + default: '[[userOrUsers]] [[bought]] [[tokenOrTokens]] for [[price]]', + variables: { + bought: { + type: 'contextAction', + value: 'bought', + }, + }, + }, + }, + }; + + return transaction; +} diff --git a/src/heuristics/erc721Swap.ts b/src/heuristics/erc721Swap.ts deleted file mode 100644 index 4912b0da..00000000 --- a/src/heuristics/erc721Swap.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { Transaction } from '../types'; -import { TOKEN_SWAP_CONTRACTS } from '../helpers/constants'; - -export function erc721SwapContextualizer( - transaction: Transaction, -): Transaction { - const isERC721SwapTx = detectERC721Swap(transaction); - if (!isERC721SwapTx) return transaction; - - return generateERC721SwapContext(transaction); -} - -function detectERC721Swap(transaction: Transaction): boolean { - /** - * There is a degree of overlap between the 'detect' and 'generateContext' functions, - * and while this might seem redundant, maintaining the 'detect' function aligns with - * established patterns in our other modules. This consistency is beneficial, - * and it also serves to decouple the logic, thereby simplifying the testing process - */ - // Break if this transaction isn't to a token swap contract - if (TOKEN_SWAP_CONTRACTS.indexOf(transaction.to) === -1) { - return false; - } - - const addresses = transaction.netAssetTransfers - ? Object.keys(transaction.netAssetTransfers) - : []; - - for (let i = 0; i < addresses.length; i++) { - const address = addresses[i]; - const sent = transaction.netAssetTransfers[address].sent; - const received = transaction.netAssetTransfers[address].received; - - const sentCount = sent?.length || 0; - const receivedCount = received?.length || 0; - if (sentCount === 1 && receivedCount === 1) { - if (transaction.netAssetTransfers[address].sent[0].type === 'erc721') { - return true; - } - } - } - - return false; -} - -function generateERC721SwapContext(transaction: any) { - const addresses = transaction.netAssetTransfers - ? Object.keys(transaction.netAssetTransfers) - : []; - - for (let i = 0; i < addresses.length; i++) { - const address = addresses[i]; - const sent = transaction.netAssetTransfers[address].sent; - const received = transaction.netAssetTransfers[address].received; - - const sentCount = sent?.length || 0; - const receivedCount = received?.length || 0; - if (sentCount === 1 && receivedCount === 1) { - if (transaction.netAssetTransfers[address].sent[0].type === 'erc721') { - transaction.context = { - variables: { - swapper: { - type: 'address', - value: address, - }, - sentToken: { - token: sent[0].asset, - type: sent[0].type, - value: sent[0].value, - }, - receivedToken: { - token: received[0].asset, - type: received[0].type, - value: received[0].value, - }, - }, - summaries: { - category: 'NFT', - en: { - title: 'ERC721 Swap', - default: - '[[swapper]] [[swapped]] [[sentToken]] for [[receivedToken]]', - variables: { - swapped: { - type: 'contextAction', - value: 'swapped', - }, - }, - }, - }, - }; - - break; - } - } - } - - return transaction; -} diff --git a/src/heuristics/index.ts b/src/heuristics/index.ts index 853c0f23..4fcdf289 100644 --- a/src/heuristics/index.ts +++ b/src/heuristics/index.ts @@ -2,9 +2,7 @@ export * from './cancelPendingTransaction'; export * from './contractDeployment'; export * from './erc20Swap'; export * from './erc721Purchase'; -export * from './erc721Swap'; export * from './erc1155Purchase'; -export * from './erc1155Swap'; export * from './ethTransfer'; export * from './idm'; export * from './tokenAirdrop'; diff --git a/src/test/transactions/erc1155Purchase-0x16b2334d.json b/src/test/transactions/erc1155Sale-0x16b2334d.json similarity index 100% rename from src/test/transactions/erc1155Purchase-0x16b2334d.json rename to src/test/transactions/erc1155Sale-0x16b2334d.json From 5ea4a0424dd0a29dc55e8b237d3f8e458b1e8263 Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Thu, 30 Nov 2023 09:34:13 -0800 Subject: [PATCH 2/5] feat: update erc721 sale --- src/heuristics/erc721Purchase.spec.ts | 18 --------- src/heuristics/erc721Purchase.ts | 37 ++++++++----------- src/heuristics/erc721Sale.spec.ts | 10 +++++ src/heuristics/erc721Sale.ts | 33 ++++++++--------- ...b8cee6.json => erc721Sale-0x05b8cee6.json} | 0 5 files changed, 40 insertions(+), 58 deletions(-) create mode 100644 src/heuristics/erc721Sale.spec.ts rename src/test/transactions/{erc721Purchase-0x05b8cee6.json => erc721Sale-0x05b8cee6.json} (100%) diff --git a/src/heuristics/erc721Purchase.spec.ts b/src/heuristics/erc721Purchase.spec.ts index e0521109..c4c1d61b 100644 --- a/src/heuristics/erc721Purchase.spec.ts +++ b/src/heuristics/erc721Purchase.spec.ts @@ -4,8 +4,6 @@ import { generateERC21PurchaseContext, } from './erc721Purchase'; import erc721Purchase0x2558f104 from '../test/transactions/erc721Purchase-0x2558f104.json'; -import erc721Purchase0x05b8cee6 from '../test/transactions/erc721Purchase-0x05b8cee6.json'; -import erc721Purchase0xdeba4248 from '../test/transactions/erc721Purchase-0xdeba4248.json'; describe('ERC721 Purchase', () => { it('Should detect ERC721 Purchase transaction', () => { @@ -13,21 +11,5 @@ describe('ERC721 Purchase', () => { erc721Purchase0x2558f104 as Transaction, ); expect(isERC721Purchase1).toBe(true); - - const isERC721Purchase2 = detectERC721Purchase( - erc721Purchase0x05b8cee6 as Transaction, - ); - expect(isERC721Purchase2).toBe(true); - const isERC721Purchase3 = detectERC721Purchase( - erc721Purchase0xdeba4248 as Transaction, - ); - expect(isERC721Purchase3).toBe(true); - }); - - it('Should create ERC721 Purchase context', () => { - const result1 = generateERC21PurchaseContext( - erc721Purchase0xdeba4248 as Transaction, - ); - expect(result1.context.summaries.en.title).toBe('NFT Purchase'); }); }); diff --git a/src/heuristics/erc721Purchase.ts b/src/heuristics/erc721Purchase.ts index 9352e891..9a974e7b 100644 --- a/src/heuristics/erc721Purchase.ts +++ b/src/heuristics/erc721Purchase.ts @@ -11,6 +11,14 @@ export function erc721PurchaseContextualizer( return generateERC21PurchaseContext(transaction); } +/** + * Detection criteria + * + * Transaction.from sends ETH/WETH/blur eth and receives only NFTs. + * Nothing is minted (exception being weth) + * In netAssetTransfers, the address that sent the NFTs receives either eth/weth/blur eth. + * The rest of the parties only receive eth/weth/blur eth (royalties/fees) + */ export function detectERC721Purchase(transaction: Transaction): boolean { /** * There is a degree of overlap between the 'detect' and 'generateContext' functions, @@ -20,29 +28,14 @@ export function detectERC721Purchase(transaction: Transaction): boolean { */ if (!transaction.netAssetTransfers) return false; - const addresses = transaction.netAssetTransfers - ? Object.keys(transaction.netAssetTransfers) - : []; - - for (const address of addresses) { - const transfers = transaction.netAssetTransfers[address]; - const nftsReceived = transfers.received.filter((t) => t.type === 'erc721'); - const nftsSent = transfers.sent.filter((t) => t.type === 'erc721'); - - const ethOrErc20Sent = transfers.sent.filter( - (t) => t.type === 'eth' || t.type === 'erc20', - ); - const ethOrErc20Received = transfers.received.filter( - (t) => t.type === 'eth' || t.type === 'erc20', - ); - - if (nftsReceived.length > 0 && ethOrErc20Sent.length > 0) { - return true; - } + const transfers = transaction.netAssetTransfers[transaction.from]; + const nftsReceived = transfers.received.filter((t) => t.type === 'erc721'); + const tokenSent = transfers.sent.filter( + (t) => t.type === 'eth' || t.type === 'erc20', + ); - if (nftsSent.length > 0 && ethOrErc20Received.length > 0) { - return true; - } + if (nftsReceived.length > 0 && tokenSent.length > 0) { + return true; } return false; diff --git a/src/heuristics/erc721Sale.spec.ts b/src/heuristics/erc721Sale.spec.ts new file mode 100644 index 00000000..803db467 --- /dev/null +++ b/src/heuristics/erc721Sale.spec.ts @@ -0,0 +1,10 @@ +import { Transaction } from '../types'; +import { detectERC721Sale } from './erc721Sale'; +import erc721Sale0x05b8cee6 from '../test/transactions/erc721Sale-0x05b8cee6.json'; + +describe('ERC721 Sale', () => { + it('Should detect ERC721 Sale transaction', () => { + const isERC721Sale1 = detectERC721Sale(erc721Sale0x05b8cee6 as Transaction); + expect(isERC721Sale1).toBe(true); + }); +}); diff --git a/src/heuristics/erc721Sale.ts b/src/heuristics/erc721Sale.ts index de246ac4..c82dba79 100644 --- a/src/heuristics/erc721Sale.ts +++ b/src/heuristics/erc721Sale.ts @@ -11,6 +11,14 @@ export function erc721SaleContextualizer( return generateERC21PurchaseContext(transaction); } +/** + * Detection criteria + * + * Transaction.from receives ETH/WETH/blur eth and sends only NFTs. + * Nothing is minted (exception being weth) + * In netAssetTransfers, the address that sent the NFTs receives either eth/weth/blur eth. + * The rest of the parties only receive eth/weth/blur eth (royalties/fees) + */ export function detectERC721Sale(transaction: Transaction): boolean { /** * There is a degree of overlap between the 'detect' and 'generateContext' functions, @@ -24,25 +32,14 @@ export function detectERC721Sale(transaction: Transaction): boolean { ? Object.keys(transaction.netAssetTransfers) : []; - for (const address of addresses) { - const transfers = transaction.netAssetTransfers[address]; - const nftsReceived = transfers.received.filter((t) => t.type === 'erc721'); - const nftsSent = transfers.sent.filter((t) => t.type === 'erc721'); - - const ethOrErc20Sent = transfers.sent.filter( - (t) => t.type === 'eth' || t.type === 'erc20', - ); - const ethOrErc20Received = transfers.received.filter( - (t) => t.type === 'eth' || t.type === 'erc20', - ); - - if (nftsReceived.length > 0 && ethOrErc20Sent.length > 0) { - return true; - } + const transfers = transaction.netAssetTransfers[transaction.from]; + const nftsSent = transfers.sent.filter((t) => t.type === 'erc721'); + const tokenReceived = transfers.received.filter( + (t) => t.type === 'eth' || t.type === 'erc20', + ); - if (nftsSent.length > 0 && ethOrErc20Received.length > 0) { - return true; - } + if (nftsSent.length > 0 && tokenReceived.length > 0) { + return true; } return false; diff --git a/src/test/transactions/erc721Purchase-0x05b8cee6.json b/src/test/transactions/erc721Sale-0x05b8cee6.json similarity index 100% rename from src/test/transactions/erc721Purchase-0x05b8cee6.json rename to src/test/transactions/erc721Sale-0x05b8cee6.json From a82db0d733dacb5a5c088ce1f3b454471209e303 Mon Sep 17 00:00:00 2001 From: ponyjackal Date: Thu, 30 Nov 2023 10:08:25 -0800 Subject: [PATCH 3/5] feat: add unit test for erc1155 purchase --- src/heuristics/erc1155Purchase.spec.ts | 22 +- .../erc1155Purchase-0x156df9f7.json | 707 ++++++++++++++++++ 2 files changed, 718 insertions(+), 11 deletions(-) create mode 100644 src/test/transactions/erc1155Purchase-0x156df9f7.json diff --git a/src/heuristics/erc1155Purchase.spec.ts b/src/heuristics/erc1155Purchase.spec.ts index e5950df4..3328a9fd 100644 --- a/src/heuristics/erc1155Purchase.spec.ts +++ b/src/heuristics/erc1155Purchase.spec.ts @@ -1,12 +1,12 @@ -// import { Transaction } from '../types'; -// import { detectERC1155Purchase } from './erc1155Purchase'; -// import erc1155Purchase0x16b2334d from '../test/transactions/erc1155Purchase-0x16b2334d.json'; +import { Transaction } from '../types'; +import { detectERC1155Purchase } from './erc1155Purchase'; +import erc1155Purchase0x156df9f7 from '../test/transactions/erc1155Purchase-0x156df9f7.json'; -// describe('ERC1155 Purchase', () => { -// it('Should detect ERC1155 Purchase transaction', () => { -// const isERC1155Purchase1 = detectERC1155Purchase( -// erc1155Purchase0x16b2334d as Transaction, -// ); -// expect(isERC1155Purchase1).toBe(true); -// }); -// }); +describe('ERC1155 Purchase', () => { + it('Should detect ERC1155 Purchase transaction', () => { + const isERC1155Purchase1 = detectERC1155Purchase( + erc1155Purchase0x156df9f7 as Transaction, + ); + expect(isERC1155Purchase1).toBe(true); + }); +}); diff --git a/src/test/transactions/erc1155Purchase-0x156df9f7.json b/src/test/transactions/erc1155Purchase-0x156df9f7.json new file mode 100644 index 00000000..2e20888b --- /dev/null +++ b/src/test/transactions/erc1155Purchase-0x156df9f7.json @@ -0,0 +1,707 @@ +{ + "blockHash": "0x1dafbe13d2405cfa0211f2e24387b138b5e2c557cb0e8da5f5d59c0de0abe054", + "blockNumber": 17867693, + "from": "0x02085755fa2636a2d6bfb11d98a07618231a1c8d", + "gas": 333187, + "gasPrice": "25247528479", + "maxFeePerGas": "33350484205", + "maxPriorityFeePerGas": "100000000", + "hash": "0x156d113afa25d937390a95cc9fb9106e9ac4805a719a9a44dd1c54ac3cf3f9f7", + "input": "0x87201b4100000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000bc00000000000000000000000000000000000000000000000000000000000000be00000000000000000000000000000000000000000000000000000000000000d000000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000078f8c78a212d64ce1148355dee3f26a6e029ebba000000000000000000000000004c00500000ad104d7dbd00e3ae0a5c00560c000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000064bdd8c00000000000000000000000000000000000000000000000000000000065b06cbd0000000000000000000000000000000000000000000000000000000000000000360c6ebe000000000000000000000000000000000000000044e151b9952a60e00000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000f7f18a919bb12246aa32b2a62bb0230a6a27f56200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022a392c68f60000000000000000000000000000000000000000000000000000022a392c68f600000000000000000000000000078f8c78a212d64ce1148355dee3f26a6e029ebba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e35fa931a0000000000000000000000000000000000000000000000000000000e35fa931a0000000000000000000000000000000a26b00c1f0df003000390027140000faa719000000000000000000000000000000000000000000000000000000000000004080d92f8eacffe29c5830cc48ae2b73896ae6c56b2c6a917bf079a33eaff8e14634c2da88b5accce209c7eaafcac6753c8cc4d0359f69573cd726fb8636311721000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000005200000000000000000000000000000000000000000000000000000000000000580000000000000000000000000c03847169a0acf76cfd8cf844f27e98b7cf199a0000000000000000000000000004c00500000ad104d7dbd00e3ae0a5c00560c000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000064b491580000000000000000000000000000000000000000000000000000000064d5137c0000000000000000000000000000000000000000000000000000000000000000360c6ebe00000000000000000000000000000000000000003d74c1c0d5ef62720000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000f7f18a919bb12246aa32b2a62bb0230a6a27f56200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041b9a6e85840000000000000000000000000000000000000000000000000000041b9a6e8584000000000000000000000000000c03847169a0acf76cfd8cf844f27e98b7cf199a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c6bf526340000000000000000000000000000000000000000000000000000001c6bf526340000000000000000000000000000000a26b00c1f0df003000390027140000faa71900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038d7ea4c6800000000000000000000000000000000000000000000000000000038d7ea4c6800000000000000000000000000002085755fa2636a2d6bfb11d98a07618231a1c8d00000000000000000000000000000000000000000000000000000000000000405402141806bbcf859bbd7a3223aea60a8bcad08ef6bc25394ba60a947eef970f688d21447879305b02d2b919ad2e2a7ea2f72745f99dc83f1aca0420b9408a58000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002a3bb4bb8360c6ebe", + "nonce": 216, + "to": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "transactionIndex": 104, + "value": "30000000000000000", + "type": 2, + "accessList": [], + "chainId": 1, + "v": "0x1", + "r": "0x281b085a111b581410628fecbc8cc05ff6aea7e494baf3e37882cc14ae52e899", + "s": "0x2606b765cd73ab278b56cec0814ae8acdb4906a4c2b2dc13c19763d65e730335", + "timestamp": 1691467355, + "isoTimestamp": "2023-08-08T04:02:35.000Z", + "fork": "shanghai", + "baseFeePerGas": 25147528479, + "burntFees": "6133431900971142", + "minerFees": "24389800000000", + "transactionFee": "6157821700971142", + "assetTransfers": [ + { + "from": "0x02085755fa2636a2d6bfb11d98a07618231a1c8d", + "to": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "type": "eth", + "value": "30000000000000000" + }, + { + "from": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "to": "0x78f8c78a212d64ce1148355dee3f26a6e029ebba", + "type": "eth", + "value": "9750000000000000" + }, + { + "from": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "to": "0x0000a26b00c1f0df003000390027140000faa719", + "type": "eth", + "value": "750000000000000" + }, + { + "from": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "to": "0xc03847169a0acf76cfd8cf844f27e98b7cf199a0", + "type": "eth", + "value": "18500000000000000" + }, + { + "from": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "to": "0x02085755fa2636a2d6bfb11d98a07618231a1c8d", + "type": "eth", + "value": "1000000000000000" + }, + { + "asset": "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562", + "from": "0x78f8c78a212d64ce1148355dee3f26a6e029ebba", + "to": "0x02085755fa2636a2d6bfb11d98a07618231a1c8d", + "tokenId": "0", + "value": "1", + "type": "erc1155" + }, + { + "asset": "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562", + "from": "0xc03847169a0acf76cfd8cf844f27e98b7cf199a0", + "to": "0x02085755fa2636a2d6bfb11d98a07618231a1c8d", + "tokenId": "0", + "value": "1", + "type": "erc1155" + } + ], + "sigHash": "0x87201b41", + "internalSigHashes": [ + { + "from": "0x02085755fa2636a2d6bfb11d98a07618231a1c8d", + "to": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "sigHash": "0x87201b41" + }, + { + "from": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "to": "0x78f8c78a212d64ce1148355dee3f26a6e029ebba", + "sigHash": "0x" + }, + { + "from": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "to": "0x0000a26b00c1f0df003000390027140000faa719", + "sigHash": "0x" + }, + { + "from": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "to": "0xc03847169a0acf76cfd8cf844f27e98b7cf199a0", + "sigHash": "0x" + }, + { + "from": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "to": "0x02085755fa2636a2d6bfb11d98a07618231a1c8d", + "sigHash": "0x" + }, + { + "from": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "to": "0x1e0049783f008a0085193e00003d00cd54003c71", + "sigHash": "0x4ce34aa2" + }, + { + "from": "0x1e0049783f008a0085193e00003d00cd54003c71", + "to": "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562", + "sigHash": "0xf242432a" + }, + { + "from": "0x1e0049783f008a0085193e00003d00cd54003c71", + "to": "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562", + "sigHash": "0xf242432a" + } + ], + "parties": [ + "0x02085755fa2636a2d6bfb11d98a07618231a1c8d", + "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "0x78f8c78a212d64ce1148355dee3f26a6e029ebba", + "0x0000a26b00c1f0df003000390027140000faa719", + "0xc03847169a0acf76cfd8cf844f27e98b7cf199a0", + "0x1e0049783f008a0085193e00003d00cd54003c71", + "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562", + "0x004c00500000ad104d7dbd00e3ae0a5c00560c00", + "0x0000000000000000000000000000000000000000" + ], + "decode": { + "fragment": { + "type": "function", + "inputs": [ + { + "name": "", + "type": "tuple((address,address,(uint8,address,uint256,uint256,uint256)[],(uint8,address,uint256,uint256,uint256,address)[],uint8,uint256,uint256,bytes32,uint256,bytes32,uint256),uint120,uint120,bytes,bytes)[]", + "baseType": "array", + "indexed": null, + "components": null, + "arrayLength": -1, + "arrayChildren": { + "name": "", + "type": "tuple((address,address,(uint8,address,uint256,uint256,uint256)[],(uint8,address,uint256,uint256,uint256,address)[],uint8,uint256,uint256,bytes32,uint256,bytes32,uint256),uint120,uint120,bytes,bytes)", + "baseType": "tuple", + "indexed": null, + "components": [ + { + "name": "", + "type": "tuple(address,address,(uint8,address,uint256,uint256,uint256)[],(uint8,address,uint256,uint256,uint256,address)[],uint8,uint256,uint256,bytes32,uint256,bytes32,uint256)", + "baseType": "tuple", + "indexed": null, + "components": [ + { + "name": "", + "type": "address", + "baseType": "address", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "address", + "baseType": "address", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "tuple(uint8,address,uint256,uint256,uint256)[]", + "baseType": "array", + "indexed": null, + "components": null, + "arrayLength": -1, + "arrayChildren": { + "name": "", + "type": "tuple(uint8,address,uint256,uint256,uint256)", + "baseType": "tuple", + "indexed": null, + "components": [ + { + "name": "", + "type": "uint8", + "baseType": "uint8", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "address", + "baseType": "address", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + } + ], + "arrayLength": null, + "arrayChildren": null + } + }, + { + "name": "", + "type": "tuple(uint8,address,uint256,uint256,uint256,address)[]", + "baseType": "array", + "indexed": null, + "components": null, + "arrayLength": -1, + "arrayChildren": { + "name": "", + "type": "tuple(uint8,address,uint256,uint256,uint256,address)", + "baseType": "tuple", + "indexed": null, + "components": [ + { + "name": "", + "type": "uint8", + "baseType": "uint8", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "address", + "baseType": "address", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "address", + "baseType": "address", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + } + ], + "arrayLength": null, + "arrayChildren": null + } + }, + { + "name": "", + "type": "uint8", + "baseType": "uint8", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "bytes32", + "baseType": "bytes32", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "bytes32", + "baseType": "bytes32", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + } + ], + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint120", + "baseType": "uint120", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint120", + "baseType": "uint120", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "bytes", + "baseType": "bytes", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "bytes", + "baseType": "bytes", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + } + ], + "arrayLength": null, + "arrayChildren": null + } + }, + { + "name": "", + "type": "tuple(uint256,uint8,uint256,uint256,bytes32[])[]", + "baseType": "array", + "indexed": null, + "components": null, + "arrayLength": -1, + "arrayChildren": { + "name": "", + "type": "tuple(uint256,uint8,uint256,uint256,bytes32[])", + "baseType": "tuple", + "indexed": null, + "components": [ + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint8", + "baseType": "uint8", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "bytes32[]", + "baseType": "array", + "indexed": null, + "components": null, + "arrayLength": -1, + "arrayChildren": { + "name": "", + "type": "bytes32", + "baseType": "bytes32", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + } + } + ], + "arrayLength": null, + "arrayChildren": null + } + }, + { + "name": "", + "type": "tuple(uint256,uint256)[][]", + "baseType": "array", + "indexed": null, + "components": null, + "arrayLength": -1, + "arrayChildren": { + "name": "", + "type": "tuple(uint256,uint256)[]", + "baseType": "array", + "indexed": null, + "components": null, + "arrayLength": -1, + "arrayChildren": { + "name": "", + "type": "tuple(uint256,uint256)", + "baseType": "tuple", + "indexed": null, + "components": [ + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + } + ], + "arrayLength": null, + "arrayChildren": null + } + } + }, + { + "name": "", + "type": "tuple(uint256,uint256)[][]", + "baseType": "array", + "indexed": null, + "components": null, + "arrayLength": -1, + "arrayChildren": { + "name": "", + "type": "tuple(uint256,uint256)[]", + "baseType": "array", + "indexed": null, + "components": null, + "arrayLength": -1, + "arrayChildren": { + "name": "", + "type": "tuple(uint256,uint256)", + "baseType": "tuple", + "indexed": null, + "components": [ + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + } + ], + "arrayLength": null, + "arrayChildren": null + } + } + }, + { + "name": "", + "type": "bytes32", + "baseType": "bytes32", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "address", + "baseType": "address", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + }, + { + "name": "", + "type": "uint256", + "baseType": "uint256", + "indexed": null, + "components": null, + "arrayLength": null, + "arrayChildren": null + } + ], + "name": "fulfillAvailableAdvancedOrders", + "constant": false, + "outputs": [], + "stateMutability": "nonpayable", + "payable": false, + "gas": null + }, + "name": "fulfillAvailableAdvancedOrders", + "args": [ + "0x78f8C78a212d64CE1148355DEE3F26a6e029EbBa,0x004C00500000aD104D7DBd00e3ae0A5C00560C00,3,0xf7f18a919bB12246AA32B2a62BB0230a6A27F562,0,1,1,0,0x0000000000000000000000000000000000000000,0,9750000000000000,9750000000000000,0x78f8C78a212d64CE1148355DEE3F26a6e029EbBa,0,0x0000000000000000000000000000000000000000,0,250000000000000,250000000000000,0x0000a26b00c1F0DF003000390027140000fAa719,1,1690163392,1706060989,0x0000000000000000000000000000000000000000000000000000000000000000,24446860302761739304752683030156737591518664810215442929805346026557104873696,0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000,2,1,1,0x80d92f8eacffe29c5830cc48ae2b73896ae6c56b2c6a917bf079a33eaff8e14634c2da88b5accce209c7eaafcac6753c8cc4d0359f69573cd726fb8636311721,0x,0xc03847169A0acf76cfd8cf844F27E98B7Cf199a0,0x004C00500000aD104D7DBd00e3ae0A5C00560C00,3,0xf7f18a919bB12246AA32B2a62BB0230a6A27F562,0,1,1,0,0x0000000000000000000000000000000000000000,0,18500000000000000,18500000000000000,0xc03847169A0acf76cfd8cf844F27E98B7Cf199a0,0,0x0000000000000000000000000000000000000000,0,500000000000000,500000000000000,0x0000a26b00c1F0DF003000390027140000fAa719,0,0x0000000000000000000000000000000000000000,0,1000000000000000,1000000000000000,0x02085755Fa2636a2d6BFB11D98a07618231A1c8d,1,1689555288,1691685756,0x0000000000000000000000000000000000000000000000000000000000000000,24446860302761739304752683030156737591518664810215442929804811065802831651442,0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000,3,1,1,0x5402141806bbcf859bbd7a3223aea60a8bcad08ef6bc25394ba60a947eef970f688d21447879305b02d2b919ad2e2a7ea2f72745f99dc83f1aca0420b9408a58,0x", + "", + "0,0,1,0", + "0,0,0,1,1,1,1,0,1,2", + "0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000", + "0x0000000000000000000000000000000000000000", + "2" + ], + "signature": "fulfillAvailableAdvancedOrders(((address,address,(uint8,address,uint256,uint256,uint256)[],(uint8,address,uint256,uint256,uint256,address)[],uint8,uint256,uint256,bytes32,uint256,bytes32,uint256),uint120,uint120,bytes,bytes)[],(uint256,uint8,uint256,uint256,bytes32[])[],(uint256,uint256)[][],(uint256,uint256)[][],bytes32,address,uint256)", + "selector": "0x87201b41", + "value": "0" + }, + "netAssetTransfers": { + "0x02085755fa2636a2d6bfb11d98a07618231a1c8d": { + "received": [ + { + "asset": "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562", + "id": "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562-0", + "tokenId": "0", + "type": "erc1155", + "value": "2" + } + ], + "sent": [ + { + "asset": "eth", + "id": "eth", + "type": "eth", + "value": "29000000000000000" + } + ] + }, + "0x78f8c78a212d64ce1148355dee3f26a6e029ebba": { + "received": [ + { + "asset": "eth", + "id": "eth", + "type": "eth", + "value": "9750000000000000" + } + ], + "sent": [ + { + "asset": "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562", + "id": "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562-0", + "tokenId": "0", + "type": "erc1155", + "value": "1" + } + ] + }, + "0x0000a26b00c1f0df003000390027140000faa719": { + "received": [ + { + "asset": "eth", + "id": "eth", + "type": "eth", + "value": "750000000000000" + } + ], + "sent": [] + }, + "0xc03847169a0acf76cfd8cf844f27e98b7cf199a0": { + "received": [ + { + "asset": "eth", + "id": "eth", + "type": "eth", + "value": "18500000000000000" + } + ], + "sent": [ + { + "asset": "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562", + "id": "0xf7f18a919bb12246aa32b2a62bb0230a6a27f562-0", + "tokenId": "0", + "type": "erc1155", + "value": "1" + } + ] + } + }, + "receipt": { + "blockHash": "0x1dafbe13d2405cfa0211f2e24387b138b5e2c557cb0e8da5f5d59c0de0abe054", + "blockNumber": 17867693, + "contractAddress": null, + "cumulativeGasUsed": 14798644, + "effectiveGasPrice": 25247528479, + "from": "0x02085755fa2636a2d6bfb11d98a07618231a1c8d", + "gasUsed": 243898, + "logsBloom": "0x00000000400000000000000000000028400000000000000000000000000000000000000000000200000000000000000000000000000000008000000000002000000000000008000020000000000000000000000000000080000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000080000010000000000000000880001000000400000000000100000000000000000000002000000000000000000000000000000000000000000000000000000000008000800000000000000000000000000000000000000000000000000000001000810000000080000400000", + "status": true, + "to": "0x00000000000000adc04c56bf30ac9d3c0aaf14dc", + "transactionHash": "0x156d113afa25d937390a95cc9fb9106e9ac4805a719a9a44dd1c54ac3cf3f9f7", + "transactionIndex": 104, + "type": "0x2" + } +} \ No newline at end of file From b6e96a6276e661e38ecb93296c5a402faf07b307 Mon Sep 17 00:00:00 2001 From: Paul Cowgill Date: Thu, 30 Nov 2023 15:21:23 -0600 Subject: [PATCH 4/5] Fix generate names --- src/heuristics/erc721Sale.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/heuristics/erc721Sale.ts b/src/heuristics/erc721Sale.ts index c82dba79..1b129d54 100644 --- a/src/heuristics/erc721Sale.ts +++ b/src/heuristics/erc721Sale.ts @@ -8,7 +8,7 @@ export function erc721SaleContextualizer( if (!isERC721SaleTransaction) return transaction; - return generateERC21PurchaseContext(transaction); + return generateERC21SaleContext(transaction); } /** @@ -45,7 +45,7 @@ export function detectERC721Sale(transaction: Transaction): boolean { return false; } -function generateERC21PurchaseContext(transaction: Transaction): Transaction { +function generateERC21SaleContext(transaction: Transaction): Transaction { const receivingAddresses: string[] = []; const receivedNfts: Asset[] = []; const sentPayments: { type: string; asset: string; value: string }[] = []; From 116fa9a68e5086590e1dd2e2add7a5a60d111ed3 Mon Sep 17 00:00:00 2001 From: Paul Cowgill Date: Thu, 30 Nov 2023 15:22:11 -0600 Subject: [PATCH 5/5] Comment spacing fix --- src/heuristics/erc1155Sale.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/heuristics/erc1155Sale.ts b/src/heuristics/erc1155Sale.ts index 880d11b0..94dcf6b0 100644 --- a/src/heuristics/erc1155Sale.ts +++ b/src/heuristics/erc1155Sale.ts @@ -21,7 +21,7 @@ export function erc1155SaleContextualizer( export function detectERC1155Sale(transaction: Transaction): boolean { /** * There is a degree of overlap between the 'detect' and 'generateContext' functions, - * and while this might seem redundant, maintaining the 'detect' function aligns with + * and while this might seem redundant, maintaining the 'detect' function aligns with * established patterns in our other modules. This consistency is beneficial, * and it also serves to decouple the logic, thereby simplifying the testing process */