diff --git a/src/rmrk2.0.0/classes/nft.ts b/src/rmrk2.0.0/classes/nft.ts index 551a0341..6c96e1c6 100644 --- a/src/rmrk2.0.0/classes/nft.ts +++ b/src/rmrk2.0.0/classes/nft.ts @@ -129,6 +129,12 @@ export class NFT { let recipientEncoded = recipient; if (isValidAddressPolkadotAddress(recipient)) { recipientEncoded = encodeAddress(recipient, ss58Format); + } else { + const splitRecipient = String(recipientEncoded).split("-"); + if (splitRecipient[0] === "0") { + splitRecipient[0] = block; + recipientEncoded = splitRecipient.join("-"); + } } const obj = getRemarkData(dataString); return new this({ diff --git a/src/rmrk2.0.0/classes/resadd.ts b/src/rmrk2.0.0/classes/resadd.ts index cc691c0b..b911663c 100644 --- a/src/rmrk2.0.0/classes/resadd.ts +++ b/src/rmrk2.0.0/classes/resadd.ts @@ -33,7 +33,13 @@ export class Resadd { this.replace = replaceId; } - static fromRemark(remark: string): Resadd | string { + static fromRemark( + remark: string, + block?: number + ): Resadd | string { + if (!block) { + block = 0; + } try { validateResadd(remark); const [ @@ -45,7 +51,13 @@ export class Resadd { replaceId, ] = remark.split("::"); const resourceObj: Resource = getRemarkData(resource); - return new this(nftId, resourceObj, replaceId); + let the_nftId = nftId; + const splitNftId = String(nftId).split("-"); + if (splitNftId[0] === "0") { + splitNftId[0] = block; + the_nftId = splitNftId.join("-"); + } + return new this(the_nftId, resourceObj, replaceId); } catch (e: any) { console.error(e.message); console.log(`RESADD error: full input was ${remark}`); diff --git a/src/rmrk2.0.0/tools/consolidator/consolidator.ts b/src/rmrk2.0.0/tools/consolidator/consolidator.ts index f6b725fe..7505e90b 100644 --- a/src/rmrk2.0.0/tools/consolidator/consolidator.ts +++ b/src/rmrk2.0.0/tools/consolidator/consolidator.ts @@ -774,7 +774,7 @@ export class Consolidator { const invalidate = this.updateInvalidCalls(OP_TYPES.RESADD, remark).bind( this ); - const resaddEntity = Resadd.fromRemark(remark.remark); + const resaddEntity = Resadd.fromRemark(remark.remark, remark.block); if (typeof resaddEntity === "string") { invalidate( remark.remark, diff --git a/test/2.0.0/consolidator/__snapshots__/mint.test.ts.snap b/test/2.0.0/consolidator/__snapshots__/mint.test.ts.snap index e7cd654f..b2ecab96 100644 --- a/test/2.0.0/consolidator/__snapshots__/mint.test.ts.snap +++ b/test/2.0.0/consolidator/__snapshots__/mint.test.ts.snap @@ -1,5 +1,72 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`rmrk2.0.0 Consolidator: MINT Should allow minting another NFT into a NFT minted in the same block 1`] = ` +Object { + "bases": Object {}, + "collections": Object { + "d43593c715a56da27d-KANARIABIRDS": Collection { + "block": 2, + "changes": Array [], + "count": 2, + "id": "d43593c715a56da27d-KANARIABIRDS", + "issuer": "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", + "max": 0, + "metadata": "https://some.url", + "symbol": "KANARIABIRDS", + }, + }, + "invalid": Array [], + "nfts": Object { + "3-d43593c715a56da27d-KANARIABIRDS-KANR-00000777": Object { + "block": 3, + "burned": "", + "changes": Array [], + "children": Array [ + Object { + "equipped": "", + "id": "3-d43593c715a56da27d-KANARIABIRDS-KANR-00000888", + "pending": false, + }, + ], + "collection": "d43593c715a56da27d-KANARIABIRDS", + "forsale": 0n, + "id": "3-d43593c715a56da27d-KANARIABIRDS-KANR-00000777", + "metadata": undefined, + "owner": "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", + "pending": false, + "priority": Array [], + "properties": Object {}, + "reactions": Object {}, + "resources": Array [], + "rootowner": "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", + "sn": "00000777", + "symbol": "KANR", + "transferable": 1, + }, + "3-d43593c715a56da27d-KANARIABIRDS-KANR-00000888": Object { + "block": 3, + "burned": "", + "changes": Array [], + "children": Array [], + "collection": "d43593c715a56da27d-KANARIABIRDS", + "forsale": 0n, + "id": "3-d43593c715a56da27d-KANARIABIRDS-KANR-00000888", + "metadata": undefined, + "owner": "3-d43593c715a56da27d-KANARIABIRDS-KANR-00000777", + "pending": false, + "priority": Array [], + "properties": Object {}, + "reactions": Object {}, + "resources": Array [], + "rootowner": "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", + "sn": "00000888", + "symbol": "KANR", + "transferable": 1, + }, + }, +} +`; + exports[`rmrk2.0.0 Consolidator: MINT Should allow to mint NFT with royalties 1`] = ` Object { "bases": Object {}, diff --git a/test/2.0.0/consolidator/mint.test.ts b/test/2.0.0/consolidator/mint.test.ts index 3781a83f..b3d1bdb4 100644 --- a/test/2.0.0/consolidator/mint.test.ts +++ b/test/2.0.0/consolidator/mint.test.ts @@ -1,6 +1,7 @@ import { Consolidator, NFT } from "../../../src/rmrk2.0.0"; import { createCollectionMock, + createBatchMock, getBlockCallsMock, getAliceKey, getBobKey, @@ -117,4 +118,13 @@ describe("rmrk2.0.0 Consolidator: MINT", () => { "Attempted to mint into maxed out collection d43593c715a56da27d-KANARIABIRDS" ); }); + + it("Should allow minting another NFT into a NFT minted in the same block", async () => { + const remarks = getRemarksFromBlocksMock([ + ...getBlockCallsMock(createCollectionMock().create()), + ...createBatchMock(mintNftMock().mint(), mintNftMock2().mint("0-d43593c715a56da27d-KANARIABIRDS-KANR-00000777")), + ]); + const consolidator = new Consolidator(); + expect(await consolidator.consolidate(remarks)).toMatchSnapshot(); + }); }); diff --git a/test/2.0.0/consolidator/resadd.test.ts b/test/2.0.0/consolidator/resadd.test.ts index 5986621f..842a2c56 100644 --- a/test/2.0.0/consolidator/resadd.test.ts +++ b/test/2.0.0/consolidator/resadd.test.ts @@ -1,6 +1,7 @@ import { Consolidator } from "../../../src/rmrk2.0.0"; import { createCollectionMock, + createBatchMock, getBlockCallsMock, getBobKey, getRemarksFromBlocksMock, @@ -96,4 +97,22 @@ describe("rmrk2.0.0 Consolidator: RESADD", () => { consolidatedResult.nfts[mintNftMock(3).getId()].resources[0].pending ).toBeTruthy(); }); + + it("Should allow adding a resource to a NFT in the same block it was minted", async () => { + const remarks = getRemarksFromBlocksMock([ + ...getBlockCallsMock(createCollectionMock().create()), + ...createBatchMock(mintNftMock().mint(), "RMRK::RESADD::2.0.0::0-d43593c715a56da27d-KANARIABIRDS-KANR-00000777::%7B%22id%22%3A%22foo%22%2C%22metadata%22%3A%22ipfs%3A%2F%2Fipfs%2F123%22%7D"), + ]); + const consolidator = new Consolidator(); + const consolidatedResult = await consolidator.consolidate(remarks); + expect( + consolidatedResult.nfts[mintNftMock(3).getId()].resources[0].pending + ).toBeFalsy(); + expect( + consolidatedResult.nfts[mintNftMock(3).getId()].resources[0].metadata + ).toEqual("ipfs://ipfs/123"); + expect(consolidatedResult.nfts[mintNftMock(3).getId()].priority[0]).toEqual( + consolidatedResult.nfts[mintNftMock(3).getId()].resources[0].id + ); + }); }); diff --git a/test/2.0.0/mocks.ts b/test/2.0.0/mocks.ts index dedc08e6..ae963a7e 100644 --- a/test/2.0.0/mocks.ts +++ b/test/2.0.0/mocks.ts @@ -154,6 +154,38 @@ export const getBlockCallsMock = ( return blockCall; }; +export const createBatchMock = ( + remark1: string, + remark2: string, + caller: string = getAliceKey().address, + extras?: BlockCall[] +): Block[] => { + block = block + 1; + const blockCall: Block[] = [ + { + block: block, + calls: [ + { + call: "system.remark", + value: stringToHex(remark1), + caller: caller, + }, + { + call: "system.remark", + value: stringToHex(remark2), + caller: caller, + }, + ], + }, + ]; + + if (extras) { + blockCall[0].calls[0].extras = extras; + } + + return blockCall; +}; + export const getRemarksFromBlocksMock = (blockCalls: Block[]): Remark[] => { block = 1; return getRemarksFromBlocks(blockCalls, ["0x726d726b", "0x524d524b"]);