diff --git a/__test__/bulk-listing.test.ts b/__test__/bulk-listing.test.ts new file mode 100644 index 0000000..948a2a5 --- /dev/null +++ b/__test__/bulk-listing.test.ts @@ -0,0 +1,460 @@ +import { ActionKind, AggregatorAction, OrderKind, Orderbook, init } from '../src'; +import { BigNumber } from 'bignumber.js'; +import Web3 from 'web3'; +import { OffLineProcessor } from './common/off-line-processor'; +import { BrowserActionTaskExecutor } from '../src/modules/utils/action'; + +describe('fulfill listing main process', () => { + const mockActions = [ + { + name: 'order-signature', + description: 'Free off-chain signature to create the order', + kind: 'signature', + data: { + orderIndexes: [1, 0], + sign: { + signatureKind: 'eip712', + domain: { + name: 'Seaport', + version: '1.5', + chainId: 1, + verifyingContract: '0x00000000000000adc04c56bf30ac9d3c0aaf14dc', + }, + types: { + OrderComponents: [ + { name: 'offerer', type: 'address' }, + { name: 'zone', type: 'address' }, + { name: 'offer', type: 'OfferItem[]' }, + { name: 'consideration', type: 'ConsiderationItem[]' }, + { name: 'orderType', type: 'uint8' }, + { name: 'startTime', type: 'uint256' }, + { name: 'endTime', type: 'uint256' }, + { name: 'zoneHash', type: 'bytes32' }, + { name: 'salt', type: 'uint256' }, + { name: 'conduitKey', type: 'bytes32' }, + { name: 'counter', type: 'uint256' }, + ], + OfferItem: [ + { name: 'itemType', type: 'uint8' }, + { name: 'token', type: 'address' }, + { name: 'identifierOrCriteria', type: 'uint256' }, + { name: 'startAmount', type: 'uint256' }, + { name: 'endAmount', type: 'uint256' }, + ], + ConsiderationItem: [ + { name: 'itemType', type: 'uint8' }, + { name: 'token', type: 'address' }, + { name: 'identifierOrCriteria', type: 'uint256' }, + { name: 'startAmount', type: 'uint256' }, + { name: 'endAmount', type: 'uint256' }, + { name: 'recipient', type: 'address' }, + ], + BulkOrder: [{ name: 'tree', type: 'OrderComponents[2]' }], + }, + value: { + tree: [ + { + kind: 'single-token', + offerer: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + zone: '0x0000000000000000000000000000000000000000', + offer: [ + { + itemType: 2, + token: '0x3d053c1b9ef47f14e9d97e076b96c3a7c5054b1d', + identifierOrCriteria: '7078', + startAmount: '1', + endAmount: '1', + }, + ], + consideration: [ + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '702000000000000000', + endAmount: '702000000000000000', + recipient: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '58500000000000000', + endAmount: '58500000000000000', + recipient: '0x03d8c18655473bf155768c8d9fd1f10a022b345f', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '19500000000000000', + endAmount: '19500000000000000', + recipient: '0x0000a26b00c1f0df003000390027140000faa719', + }, + ], + orderType: 0, + startTime: 1694783545, + endTime: 1694883545, + zoneHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + salt: '0x360c6ebe1d4da48b00000000000000001a57400a70383da878f97229e1cba1eb', + conduitKey: '0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000', + counter: '0', + signature: '0x0000000000000000000000000000000000000000000000000000000000000000', + }, + { + kind: 'single-token', + offerer: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + zone: '0x0000000000000000000000000000000000000000', + offer: [ + { + itemType: 2, + token: '0x3d053c1b9ef47f14e9d97e076b96c3a7c5054b1d', + identifierOrCriteria: '7079', + startAmount: '1', + endAmount: '1', + }, + ], + consideration: [ + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '702000000000000000', + endAmount: '702000000000000000', + recipient: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '58500000000000000', + endAmount: '58500000000000000', + recipient: '0x03d8c18655473bf155768c8d9fd1f10a022b345f', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '19500000000000000', + endAmount: '19500000000000000', + recipient: '0x0000a26b00c1f0df003000390027140000faa719', + }, + ], + orderType: 0, + startTime: 1694783545, + endTime: 1694883545, + zoneHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + salt: '0x360c6ebe1d4da48b00000000000000007b473991111b4ba60ad453505276e530', + conduitKey: '0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000', + counter: '0', + signature: '0x0000000000000000000000000000000000000000000000000000000000000000', + }, + ], + }, + primaryType: 'BulkOrder', + __no_us: true, + }, + body: { + items: [ + { + order: { + kind: 'seaport-v1.5', + data: { + kind: 'single-token', + offerer: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + zone: '0x0000000000000000000000000000000000000000', + offer: [ + { + itemType: 2, + token: '0x3d053c1b9ef47f14e9d97e076b96c3a7c5054b1d', + identifierOrCriteria: '7078', + startAmount: '1', + endAmount: '1', + }, + ], + consideration: [ + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '702000000000000000', + endAmount: '702000000000000000', + recipient: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '58500000000000000', + endAmount: '58500000000000000', + recipient: '0x03d8c18655473bf155768c8d9fd1f10a022b345f', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '19500000000000000', + endAmount: '19500000000000000', + recipient: '0x0000a26b00c1f0df003000390027140000faa719', + }, + ], + orderType: 0, + startTime: 1694783545, + endTime: 1694883545, + zoneHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + salt: '0x360c6ebe1d4da48b00000000000000001a57400a70383da878f97229e1cba1eb', + conduitKey: '0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000', + counter: '0', + signature: '0x0000000000000000000000000000000000000000000000000000000000000000', + }, + }, + orderbook: 'opensea', + bulkData: { + kind: 'seaport-v1.5', + data: { + orderIndex: 0, + merkleProof: ['0x3a748491e16062bb996595b113d220763c11583dc5870d024af22254d72d65a3'], + }, + }, + }, + { + order: { + kind: 'seaport-v1.5', + data: { + kind: 'single-token', + offerer: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + zone: '0x0000000000000000000000000000000000000000', + offer: [ + { + itemType: 2, + token: '0x3d053c1b9ef47f14e9d97e076b96c3a7c5054b1d', + identifierOrCriteria: '7079', + startAmount: '1', + endAmount: '1', + }, + ], + consideration: [ + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '702000000000000000', + endAmount: '702000000000000000', + recipient: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '58500000000000000', + endAmount: '58500000000000000', + recipient: '0x03d8c18655473bf155768c8d9fd1f10a022b345f', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '19500000000000000', + endAmount: '19500000000000000', + recipient: '0x0000a26b00c1f0df003000390027140000faa719', + }, + ], + orderType: 0, + startTime: 1694783545, + endTime: 1694883545, + zoneHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + salt: '0x360c6ebe1d4da48b00000000000000007b473991111b4ba60ad453505276e530', + conduitKey: '0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000', + counter: '0', + signature: '0x0000000000000000000000000000000000000000000000000000000000000000', + }, + }, + orderbook: 'opensea', + bulkData: { + kind: 'seaport-v1.5', + data: { + orderIndex: 1, + merkleProof: ['0xaa357fbbed4a1c61e5720802a1a2c12cd3d6c73a12e2923de8947be58ec73234'], + }, + }, + }, + ], + source: 'czy-dev.io', + __no_us: true, + }, + }, + }, + { + name: 'post-order-to-marketplace', + description: 'Post order to marketplace', + kind: 'pass-through', + data: { + endpoint: '/trade/v1/nft/post-order', + method: 'POST', + orderIndexes: [1], + payload: { + order: { + kind: 'seaport-v1.5', + data: { + kind: 'single-token', + offerer: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + zone: '0x0000000000000000000000000000000000000000', + offer: [ + { + itemType: 2, + token: '0x3d053c1b9ef47f14e9d97e076b96c3a7c5054b1d', + identifierOrCriteria: '7078', + startAmount: '1', + endAmount: '1', + }, + ], + consideration: [ + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '702000000000000000', + endAmount: '702000000000000000', + recipient: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '58500000000000000', + endAmount: '58500000000000000', + recipient: '0x03d8c18655473bf155768c8d9fd1f10a022b345f', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '19500000000000000', + endAmount: '19500000000000000', + recipient: '0x0000a26b00c1f0df003000390027140000faa719', + }, + ], + orderType: 0, + startTime: 1694783545, + endTime: 1694883545, + zoneHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + salt: '0x360c6ebe1d4da48b00000000000000001a57400a70383da878f97229e1cba1eb', + conduitKey: '0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000', + counter: '0', + signature: '0x0000000000000000000000000000000000000000000000000000000000000000', + }, + }, + orderbook: 'opensea', + bulkData: { + kind: 'seaport-v1.5', + data: { + orderIndex: 0, + merkleProof: ['0x3a748491e16062bb996595b113d220763c11583dc5870d024af22254d72d65a3'], + }, + }, + orderType: 'listing', + extraArgs: { version: 'v4' }, + }, + }, + }, + { + name: 'post-order-to-marketplace', + description: 'Post order to marketplace', + kind: 'pass-through', + data: { + endpoint: '/trade/v1/nft/post-order', + method: 'POST', + orderIndexes: [0], + payload: { + order: { + kind: 'seaport-v1.5', + data: { + kind: 'single-token', + offerer: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + zone: '0x0000000000000000000000000000000000000000', + offer: [ + { + itemType: 2, + token: '0x3d053c1b9ef47f14e9d97e076b96c3a7c5054b1d', + identifierOrCriteria: '7079', + startAmount: '1', + endAmount: '1', + }, + ], + consideration: [ + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '702000000000000000', + endAmount: '702000000000000000', + recipient: '0x9398ba28015f0ce82b00ccb0da0c686a86dbad36', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '58500000000000000', + endAmount: '58500000000000000', + recipient: '0x03d8c18655473bf155768c8d9fd1f10a022b345f', + }, + { + itemType: 0, + token: '0x0000000000000000000000000000000000000000', + identifierOrCriteria: '0', + startAmount: '19500000000000000', + endAmount: '19500000000000000', + recipient: '0x0000a26b00c1f0df003000390027140000faa719', + }, + ], + orderType: 0, + startTime: 1694783545, + endTime: 1694883545, + zoneHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + salt: '0x360c6ebe1d4da48b00000000000000007b473991111b4ba60ad453505276e530', + conduitKey: '0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000', + counter: '0', + signature: '0x0000000000000000000000000000000000000000000000000000000000000000', + }, + }, + orderbook: 'opensea', + bulkData: { + kind: 'seaport-v1.5', + data: { + orderIndex: 1, + merkleProof: ['0xaa357fbbed4a1c61e5720802a1a2c12cd3d6c73a12e2923de8947be58ec73234'], + }, + }, + orderType: 'listing', + extraArgs: { version: 'v4' }, + }, + }, + }, + ] as AggregatorAction[]; + const endpoint = process.env.PROVIDER_URL!, + address = process.env.ADDRESS!, + privateKey = process.env.PRIVATE_KEY!, + apiKey = process.env.API_KEY!, + web3Provider = new Web3.providers.HttpProvider(endpoint); + + const sdk = init({ + apiKey, + baseUrl: 'https://data-api.nftgo.dev', + web3Provider, + walletConfig: { + address, + privateKey, + }, + }); + + test('Execute Action should be success', async () => { + const processor = new OffLineProcessor(); + + const executor = new BrowserActionTaskExecutor(mockActions, processor); + + for (const task of executor) { + await task.execute(); + expect(task.status).toBe('success'); + } + }); +}); diff --git a/__test__/common/off-line-processor.ts b/__test__/common/off-line-processor.ts new file mode 100644 index 0000000..6444188 --- /dev/null +++ b/__test__/common/off-line-processor.ts @@ -0,0 +1,47 @@ +import { + ActionKind, + ActionName, + ActionProcessor, + AggregatorAction, + PassThroughActionInfo, + ProcessPassThroughActionParams, + SignatureActionInfo, + TransactionActionInfo, +} from '../../src'; + +export class OffLineProcessor implements ActionProcessor { + async processSignatureAction(action: AggregatorAction) { + const { name, data } = action; + if (name === 'order-signature') { + const { sign } = data; + if (!sign) { + throw new Error('sign is required'); + } + const signature = 'signature' + data.orderIndexes.join(','); + return signature; + } + return Promise.reject(new Error('no match action name')); + } + + async processTransactionAction(action: AggregatorAction) { + const { name, data } = action; + const { txData, safeMode } = data; + if (!txData) { + throw new Error('txData is required'); + } + } + + async processPassThroughAction( + action: AggregatorAction, + params: ProcessPassThroughActionParams + ) { + const { name, data } = action; + console.log(data.orderIndexes, params.signature); + } + + async processControllerAction( + action: AggregatorAction + ): Promise[]> { + return []; + } +} diff --git a/src/modules/utils/action/task/pass-through.ts b/src/modules/utils/action/task/pass-through.ts index 956617a..b149569 100644 --- a/src/modules/utils/action/task/pass-through.ts +++ b/src/modules/utils/action/task/pass-through.ts @@ -3,16 +3,22 @@ import { ActionTaskTemplate } from './template'; export class PassThroughActionTask extends ActionTaskTemplate { protected run = async () => { - const pre = this.pre; + let pre = this.pre; while (pre) { + // when can we use it for post-order + // condition 1: it's a signature kind action + // condition 2: it's orderIndexes must include passthrough order index if (pre.action.kind === ActionKind.Signature) { - const params = pre.result as ProcessPassThroughActionParams; - await this.processor.processPassThroughAction(this.action, params); - break; - } else { - continue; + const { orderIndexes } = pre.action.data; + const result = pre.result as ProcessPassThroughActionParams; + const needThisSignature = this.action.data.orderIndexes.every(index => orderIndexes.includes(index)); + if (needThisSignature) { + await this.processor.processPassThroughAction(this.action, result); + return null; + } } + pre = pre.pre; } - return null; + throw new Error('Can not found signature for post order'); }; } diff --git a/src/types/action/action.ts b/src/types/action/action.ts index fc68d4a..7469eac 100644 --- a/src/types/action/action.ts +++ b/src/types/action/action.ts @@ -62,6 +62,7 @@ export type SignatureActionInfo = { }; export type PassThroughActionInfo = { + orderIndexes: number[]; endpoint: string; method: 'POST' | 'GET'; payload: SafeAny; diff --git a/src/types/action/processor.ts b/src/types/action/processor.ts index 0117b87..910df23 100644 --- a/src/types/action/processor.ts +++ b/src/types/action/processor.ts @@ -15,5 +15,5 @@ export interface ActionProcessor { } export type ProcessPassThroughActionParams = { - signature?: string; + signature: string; };