Skip to content
This repository has been archived by the owner on Jul 15, 2022. It is now read-only.

Commit

Permalink
[LIVE-1909] - Bugfix: OpenSea Lazy mint quantity fix (#1862)
Browse files Browse the repository at this point in the history
* Fix lazyminting issue for nfts quantity

* run ci
  • Loading branch information
lambertkevin authored Apr 6, 2022
1 parent 01a10e1 commit bc0a98c
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import "../../__tests__/test-helpers/setup";
import BigNumber from "bignumber.js";
import { toNFTRaw } from "../../account";
import type { ProtoNFT } from "../../types";
import { encodeAccountId, toNFTRaw } from "../../account";
import { Operation } from "../../types";
import { ProtoNFT } from "../../types/nft";
import { mergeNfts } from "../../bridge/jsHelpers";
import { encodeNftId } from "../../nft";
import { encodeNftId, nftsFromOperations } from "../../nft";

describe("nft merging", () => {
const makeNFT = (
Expand Down Expand Up @@ -79,3 +80,62 @@ describe("nft merging", () => {
expect(addToNft1[0]).toBe(nfts[3]);
});
});

describe("OpenSea lazy minting bs", () => {
test("should have a correct on-chain nft amount even with OpenSea lazy minting", () => {
const makeNftOperation = (type: Operation["type"], value): Operation => {
if (!["NFT_IN", "NFT_OUT"].includes(type)) {
return {} as Operation;
}

const id = encodeAccountId({
type: "type",
currencyId: "polygon",
xpubOrAddress: "0xbob",
derivationMode: "",
version: "1",
});
const sender = type === "NFT_IN" ? "0xbob" : "0xkvn";
const receiver = type === "NFT_IN" ? "0xkvn" : "0xbob";
const contract = "0x0000000000000000000000000000000000000000";
const fee = new BigNumber(0);
const tokenId = "42069";
const hash = "FaKeHasH";

return {
id,
hash,
senders: [sender],
recipients: [receiver],
contract,
fee,
standard: "ERC1155",
tokenId,
value: new BigNumber(value),
type,
accountId: id,
} as Operation;
};

// scenario with bob lazy minting 10 NFTs
const ops = [
makeNftOperation("NFT_OUT", 5), // lazy mint sending 5 NFT
makeNftOperation("NFT_IN", 1), // receiving 1 of them back
makeNftOperation("NFT_IN", 2), // receiving 2 of them back
makeNftOperation("NFT_OUT", 2), // lazy mint sending 5 NFT (transformed by OpenSea in 2 txs) 1/2 (off-chain)
makeNftOperation("NFT_OUT", 3), // lazy mint sending 5 NFT (transformed by OpenSea in 2 txs) 2/2 (on-chain)
makeNftOperation("NFT_IN", 1), // receiving 1 back
];

// What happened for bob:
//
// -5 off-chain -> 0 on-chain (5 off-chain)
// +1 on-chain -> 1 on-chain (5 off-chain)
// +2 on-chain -> 3 on-chain (5 off-chain)
// -2 off-chain & -3 on-chain -> 0 on-chain (3 off-chain)
// +1 on-chain -> 1 on-chain (and 3 off-chain)

const nfts = nftsFromOperations(ops);
expect(nfts[0].amount.toNumber()).toBe(1);
});
});
16 changes: 15 additions & 1 deletion src/nft/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,21 @@ export const nftsFromOperations = (ops: Operation[]): ProtoNFT[] => {
if (nftOp.type === "NFT_IN") {
nft.amount = nft.amount.plus(nftOp.value);
} else if (nftOp.type === "NFT_OUT") {
nft.amount = nft.amount.minus(nftOp.value);
const newAmount = nft.amount.minus(nftOp.value);

// In case of OpenSea lazy minting feature (minting an NFT off-chain)
// OpenSea will fire a false ERC1155 event saying that you sent an NFT
// from your account that you never received first.
//
// E.g.: I'm creating 10 ERC1155 on OpenSea. It's not going to create anything on-chain.
// Then I (bob) decide to transfer 5 to someone (kvn). OpenSea is going to mint the NFT in its
// collection (`OpenSea Shared Storefront` / `OpenSea Collections`) and transfer it to kvn.
// But the event fired by the Smart Contract is going to be `bob transfered 5 NFT to kvn` which is false.
// It would then result in bob have -5 NFTs since he never received them first.
// If kvn send 2 back to bob, based on the events we would think that bob has -3 NFTs.
//
// To mitigate that we put a minimum value of 0 when an account is transferring some NFTs.
nft.amount = newAmount.isNegative() ? new BigNumber(0) : newAmount;
}

acc[id] = nft;
Expand Down

0 comments on commit bc0a98c

Please sign in to comment.