Skip to content

Commit

Permalink
TD-1484: chore: call seaport.js with a valid unitsToFill incase of ER…
Browse files Browse the repository at this point in the history
…C1155 orders. (#1908)

Co-authored-by: Sam Jeston <[email protected]>
Co-authored-by: Shine Li <[email protected]>
  • Loading branch information
3 people authored Jun 19, 2024
1 parent 42ee80e commit 7b63133
Show file tree
Hide file tree
Showing 10 changed files with 338 additions and 5 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
"@actions/core": "^1.10.1",
"@emotion/react": "^11.11.3",
"@release-it-plugins/workspaces": "^4.0.0",
"@types/chai": "^4.3.16",
"@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.57.1",
"chai": "^5.1.1",
"eslint": "^8.40.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/orderbook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@swc/jest": "^0.2.24",
"@typechain/ethers-v5": "^10.2.0",
"@types/jest": "^29.4.3",
"chai": "^5.1.1",
"dotenv": "^16.0.3",
"eslint": "^8.40.0",
"jest": "^29.4.3",
Expand Down
116 changes: 116 additions & 0 deletions packages/orderbook/src/seaport/fillable-units.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { expect } from 'chai';
import { Fee, Order, ProtocolData } from 'openapi/sdk';
import { determineFillableUnits } from './fillable-units';

describe('determineFillableUnits', () => {
function createOrder(overrides?: Partial<Order>): Order {
// Default order object
const defaultOrder: Order = {
sell: [
{
type: 'ERC1155',
amount: '100',
contract_address: '0xEEb7Da6De152597830eD16361633e362A2F59410',
token_id: '123',
},
],
buy: [
{
type: 'ERC20',
amount: '100',
contract_address: '0xFFb7Da6De152597830eD16361633e362A2F59411',
},
],
type: Order.type.LISTING,
fill_status: {
numerator: '0',
denominator: '0',
},
account_address: '0x1237Da6De152597830eD16361633e362A2F59412',
fees: [
{
type: Fee.type.PROTOCOL,
amount: '100',
recipient_address: '0x4567Da6De152597830eD16361633e362A2F59413',
},
],
chain: {
id: 'eip155:13473',
name: 'imtbl-zkevm-testnet',
},
created_at: '2024-06-18T06:16:57.902738Z',
end_at: '2026-06-18T06:16:14Z',
id: '019029fd-cf21-0a33-c77f-e121f5162f22',
order_hash: '0xba8ebe0b4ac6f1cc21a2274199b238959aaa0c59e1f2b31a8b7e8a66bf9f9635',
protocol_data: {
order_type: ProtocolData.order_type.PARTIAL_RESTRICTED,
counter: '0',
zone_address: '0x1004f9615e79462c711ff05a386bdba91a762822',
seaport_address: '0x7d117aa8bd6d31c4fa91722f246388f38ab19482',
seaport_version: '1.5',
},
salt: '0x3217c152146bf9f5',
signature: '0xf1522af4913159cdf1172d1c1bd511a3ca617f6c1d0b0ed588b2ce27618a2ac832c31ed4ee6ab2cea8af0efc2ad522468aa1c8c206291f4b343239acfea0a75e1b',
start_at: '2024-06-18T06:16:14Z',
status: {
name: 'ACTIVE',
},
updated_at: '2024-06-18T06:16:59.006679Z',
};

// Merge the overrides with the default order
return { ...defaultOrder, ...overrides };
}

it('should return the remaining fillable units for ERC1155 type when amountToFill is not provided', () => {
const orderInput = createOrder({
fill_status: {
numerator: '40',
denominator: '100',
},
});

const result = determineFillableUnits(orderInput);
expect(result).to.equal('60'); // (100 - 40) * 100 / 100
});

it('should return the original offer amount if order is unfilled i.e numerator or denominator is 0', () => {
const order: Order = createOrder();

const result = determineFillableUnits(order);
expect(result).to.equal('100');
});

it('should return amountToFill if provided', () => {
const order: Order = createOrder({
fill_status: {
numerator: '40',
denominator: '100',
},
});

const amountToFill = '50';
const result = determineFillableUnits(order, amountToFill);
expect(result).to.equal(amountToFill);
});

it('should return undefined if order type is not ERC1155', () => {
const order: Order = createOrder({
sell: [
{
type: 'ERC721',
contract_address: '0xEEb7Da6De152597830eD16361633e362A2F59410',
token_id: '123',
},
],
fill_status: {
numerator: '0',
denominator: '0',
},
});

const result = determineFillableUnits(order);
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
expect(result).to.be.undefined;
});
});
22 changes: 22 additions & 0 deletions packages/orderbook/src/seaport/fillable-units.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Order } from 'openapi/sdk';

export function determineFillableUnits(order: Order, amountToFill?: string): string | undefined {
if (order.sell[0].type === 'ERC1155' && !amountToFill) {
// fill status is expressed as a ratio
const { numerator, denominator } = order.fill_status;
const originalOfferAmt = BigInt(order.sell[0].amount);

if (numerator === '0' || denominator === '0') {
return originalOfferAmt.toString();
}

// calculate the remaining amount to fill
// remaining = ((denominator - numerator) * originalOfferAmt) / denominator
const remaining = ((BigInt(denominator) - BigInt(numerator)) * BigInt(originalOfferAmt))
/ BigInt(denominator);

return remaining.toString();
}

return amountToFill;
}
5 changes: 3 additions & 2 deletions packages/orderbook/src/seaport/seaport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { getBulkOrderComponentsFromMessage, getOrderComponentsFromMessage } from
import { SeaportLibFactory } from './seaport-lib-factory';
import { prepareTransaction } from './transaction';
import { mapImmutableOrderToSeaportOrderComponents } from './map-to-seaport-order';
import { determineFillableUnits } from './fillable-units';

export class Seaport {
constructor(
Expand Down Expand Up @@ -175,7 +176,7 @@ export class Seaport {
parameters: orderComponents,
signature: order.signature,
},
unitsToFill,
unitsToFill: determineFillableUnits(order, unitsToFill),
extraData,
tips,
},
Expand Down Expand Up @@ -244,7 +245,7 @@ export class Seaport {
parameters: orderComponents,
signature: o.order.signature,
},
unitsToFill: o.unitsToFill,
unitsToFill: determineFillableUnits(o.order, o.unitsToFill),
extraData: o.extraData,
tips,
};
Expand Down
27 changes: 27 additions & 0 deletions tests/func-tests/zkevm/features/order.feature
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,30 @@ Feature: orderbook
Then the listing should be of status active
# Assert only the ERC1155 trade in this scenario
And 1 trade should be available

Scenario: create and fully fill a ERC1155 listing without an explicit fulfill amount
Given I have a funded offerer account
And the offerer account has 100 ERC1155 tokens
And I have a funded fulfiller account
When I create a listing to sell 100 ERC1155 tokens
Then the listing should be of status active
When I fulfill the listing to buy tokens
Then the listing should be of status filled
And 100 ERC1155 tokens should be transferred to the fulfiller
And 1 trade should be available

Scenario: create and partially fill a ERC1155 listing, second fill without explicit amount
Given I have a funded offerer account
And the offerer account has 100 ERC1155 tokens
And I have a funded fulfiller account
When I create a listing to sell 100 ERC1155 tokens
Then the listing should be of status active
When I fulfill the listing to buy 90 tokens
Then the listing should be of status active
And 90 ERC1155 tokens should be transferred to the fulfiller
And 1 trade should be available
When I fulfill the listing to buy tokens
Then the listing should be of status filled
# Checks for the total amount of tokens transferred - 100 = 90 from first fulfilment + 10 from second fulfilment
And 100 ERC1155 tokens should be transferred to the fulfiller
And 2 trades should be available
87 changes: 86 additions & 1 deletion tests/func-tests/zkevm/step-definitions/order.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
givenIHaveAFundedOffererAccount, thenTheListingShouldBeOfStatus,
whenICreateAListing, whenIFulfillTheListingToBuy, andERC1155TokensShouldBeTransferredToTheFulfiller,
thenTheListingsShouldBeOfStatus,
whenIFulfillBulkListings,
whenIFulfillBulkListings, whenIFulfillTheListingToBuyWithoutExplicitFulfillmentAmt,
whenICreateABulkListing,
} from './shared';

Expand Down Expand Up @@ -257,4 +257,89 @@ defineFeature(feature, (test) => {

andTradeShouldBeAvailable(and, sdk, fulfiller, getERC1155ListingId);
}, 120_000);

test('create and fully fill a ERC1155 listing without an explicit fulfill amount', ({
given,
when,
then,
and,
}) => {
const offerer = new Wallet(Wallet.createRandom().privateKey, provider);
const fulfiller = new Wallet(Wallet.createRandom().privateKey, provider);
const testTokenId = getRandomTokenId();

let listingId: string = '';

// these callback functions are required to update / retrieve test level state variables from shared steps.
const setListingId = (id: string) => {
listingId = id;
};

const getListingId = () => listingId;
givenIHaveAFundedOffererAccount(given, bankerWallet, offerer);

andTheOffererAccountHasERC1155Tokens(and, bankerWallet, offerer, erc1155ContractAddress, testTokenId);

andIHaveAFundedFulfillerAccount(and, bankerWallet, fulfiller);

whenICreateAListing(when, sdk, offerer, erc1155ContractAddress, testTokenId, setListingId);

thenTheListingShouldBeOfStatus(then, sdk, getListingId);

whenIFulfillTheListingToBuyWithoutExplicitFulfillmentAmt(when, sdk, fulfiller, getListingId);

thenTheListingShouldBeOfStatus(then, sdk, getListingId);

// eslint-disable-next-line max-len
andERC1155TokensShouldBeTransferredToTheFulfiller(and, bankerWallet, erc1155ContractAddress, testTokenId, fulfiller);

andTradeShouldBeAvailable(and, sdk, fulfiller, getListingId);
}, 120_000);

test('create and partially fill a ERC1155 listing, second fill without explicit amount', ({
given,
when,
then,
and,
}) => {
const offerer = new Wallet(Wallet.createRandom().privateKey, provider);
const fulfiller = new Wallet(Wallet.createRandom().privateKey, provider);
const testTokenId = getRandomTokenId();

let listingId: string = '';

// these callback functions are required to update / retrieve test level state variables from shared steps.
const setListingId = (id: string) => {
listingId = id;
};

const getListingId = () => listingId;
givenIHaveAFundedOffererAccount(given, bankerWallet, offerer);

andTheOffererAccountHasERC1155Tokens(and, bankerWallet, offerer, erc1155ContractAddress, testTokenId);

andIHaveAFundedFulfillerAccount(and, bankerWallet, fulfiller);

whenICreateAListing(when, sdk, offerer, erc1155ContractAddress, testTokenId, setListingId);

thenTheListingShouldBeOfStatus(then, sdk, getListingId);

whenIFulfillTheListingToBuy(when, sdk, fulfiller, getListingId);

thenTheListingShouldBeOfStatus(then, sdk, getListingId);

// eslint-disable-next-line max-len
andERC1155TokensShouldBeTransferredToTheFulfiller(and, bankerWallet, erc1155ContractAddress, testTokenId, fulfiller);

andTradeShouldBeAvailable(and, sdk, fulfiller, getListingId);

whenIFulfillTheListingToBuyWithoutExplicitFulfillmentAmt(when, sdk, fulfiller, getListingId);

thenTheListingShouldBeOfStatus(then, sdk, getListingId);

// eslint-disable-next-line max-len
andERC1155TokensShouldBeTransferredToTheFulfiller(and, bankerWallet, erc1155ContractAddress, testTokenId, fulfiller);

andTradeShouldBeAvailable(and, sdk, fulfiller, getListingId);
}, 120_000);
});
12 changes: 12 additions & 0 deletions tests/func-tests/zkevm/step-definitions/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,18 @@ export const whenIFulfillTheListingToBuy = (
});
};

export const whenIFulfillTheListingToBuyWithoutExplicitFulfillmentAmt = (
when: DefineStepFunction,
sdk: orderbook.Orderbook,
fulfiller: Wallet,
getListingId: () => string,
) => {
when(/^I fulfill the listing to buy tokens?$/, async () => {
const listingId = getListingId();
await fulfillListing(sdk, listingId, fulfiller);
});
};

export const whenIFulfillBulkListings = (
when: DefineStepFunction,
sdk: orderbook.Orderbook,
Expand Down
4 changes: 2 additions & 2 deletions tests/func-tests/zkevm/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ __metadata:

"@imtbl/sdk@file:../../../sdk::locator=func-tests-imx%40workspace%3A.":
version: 0.0.0
resolution: "@imtbl/sdk@file:../../../sdk#../../../sdk::hash=972221&locator=func-tests-imx%40workspace%3A."
resolution: "@imtbl/sdk@file:../../../sdk#../../../sdk::hash=27c191&locator=func-tests-imx%40workspace%3A."
dependencies:
"@0xsequence/abi": ^1.4.3
"@0xsequence/core": ^1.4.3
Expand Down Expand Up @@ -1162,7 +1162,7 @@ __metadata:
optional: true
prisma:
optional: true
checksum: ff9a304bbe822028dd13295de657af04bcc19b4b5b0fd98fa49f624f05ece052041caaf690d33a495e7485dce9400c1eab48df0a3923b48534742697590f3364
checksum: ece1b9f5eb071b687eb942e1885e5718dbec44ec6bd656b1dd7bffcee58f30f46d4dbc48ee0149a00d4b99ddb20af07c990f92e435b914e3ce39764bfba8072c
languageName: node
linkType: hard

Expand Down
Loading

0 comments on commit 7b63133

Please sign in to comment.