Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Update nft module internal functions #9014

Merged
merged 10 commits into from
Oct 9, 2023
46 changes: 26 additions & 20 deletions framework/src/modules/nft/cc_commands/cc_transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,24 +105,29 @@ export class CrossChainTransferCommand extends BaseCCCommand {

if (nftChainID.equals(ownChainID)) {
const storeData = await nftStore.get(getMethodContext(), nftID);

if (status === CCM_STATUS_CODE_OK) {
storeData.owner = recipientAddress;
const storedAttributes = storeData.attributesArray;
storeData.attributesArray = this._internalMethod.getNewAttributes(
nftID,
storedAttributes,
receivedAttributes,
);
await nftStore.save(getMethodContext(), nftID, storeData);
await this._internalMethod.createUserEntry(getMethodContext(), recipientAddress, nftID);
await escrowStore.del(getMethodContext(), escrowStore.getKey(sendingChainID, nftID));
} else {
}

if (status !== CCM_STATUS_CODE_OK) {
shuse2 marked this conversation as resolved.
Show resolved Hide resolved
recipientAddress = senderAddress;
storeData.owner = recipientAddress;
await nftStore.save(getMethodContext(), nftID, storeData);
await this._internalMethod.createUserEntry(getMethodContext(), recipientAddress, nftID);
await escrowStore.del(getMethodContext(), escrowStore.getKey(sendingChainID, nftID));
}

storeData.owner = recipientAddress;
shuse2 marked this conversation as resolved.
Show resolved Hide resolved
await this._internalMethod.createNFTEntry(
getMethodContext(),
recipientAddress,
nftID,
storeData.attributesArray,
);
await this._internalMethod.createUserEntry(getMethodContext(), recipientAddress, nftID);
await escrowStore.del(getMethodContext(), escrowStore.getKey(sendingChainID, nftID));
} else {
const isSupported = await this._method.isNFTSupported(getMethodContext(), nftID);
if (!isSupported) {
Expand All @@ -137,21 +142,22 @@ export class CrossChainTransferCommand extends BaseCCCommand {
);
throw new Error('Non-supported NFT');
}

if (status === CCM_STATUS_CODE_OK) {
this._feeMethod.payFee(getMethodContext(), BigInt(FEE_CREATE_NFT));
await nftStore.save(getMethodContext(), nftID, {
owner: recipientAddress,
attributesArray: receivedAttributes as NFTAttributes[],
});
await this._internalMethod.createUserEntry(getMethodContext(), recipientAddress, nftID);
} else {
}

if (status !== CCM_STATUS_CODE_OK) {
recipientAddress = senderAddress;
await nftStore.save(getMethodContext(), nftID, {
owner: recipientAddress,
attributesArray: receivedAttributes as NFTAttributes[],
});
await this._internalMethod.createUserEntry(getMethodContext(), recipientAddress, nftID);
}

await this._internalMethod.createNFTEntry(
getMethodContext(),
recipientAddress,
nftID,
receivedAttributes as NFTAttributes[],
);
await this._internalMethod.createUserEntry(getMethodContext(), recipientAddress, nftID);
}

this.events.get(CcmTransferEvent).log(context, {
Expand Down
17 changes: 11 additions & 6 deletions framework/src/modules/nft/internal_method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,8 @@ export class InternalMethod extends BaseMethod {
nftID: Buffer,
attributesArray: NFTAttributes[],
): Promise<void> {
const moduleNames = [];
for (const item of attributesArray) {
moduleNames.push(item.module);
}

if (new Set(moduleNames).size !== attributesArray.length) {
const hasDuplicates = this.hasDuplicateModuleNames(attributesArray);
if (hasDuplicates) {
throw new Error('Invalid attributes array provided');
}

Expand All @@ -82,6 +78,15 @@ export class InternalMethod extends BaseMethod {
});
}

public hasDuplicateModuleNames(attributesArray: NFTAttributes[]): boolean {
const moduleNames = [];
for (const item of attributesArray) {
moduleNames.push(item.module);
}

return new Set(moduleNames).size !== attributesArray.length;
}

public async transferInternal(
methodContext: MethodContext,
recipientAddress: Buffer,
Expand Down
34 changes: 16 additions & 18 deletions framework/src/modules/nft/method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,7 @@ export class NFTMethod extends BaseMethod {
collectionID: Buffer,
attributesArray: NFTAttributes[],
): Promise<void> {
const moduleNames = [];
for (const item of attributesArray) {
moduleNames.push(item.module);
}
if (new Set(moduleNames).size !== attributesArray.length) {
throw new Error('Invalid attributes array provided');
}
this._internalMethod.hasDuplicateModuleNames(attributesArray);
shuse2 marked this conversation as resolved.
Show resolved Hide resolved

const index = await this.getNextAvailableIndex(methodContext, collectionID);
const indexBytes = Buffer.alloc(LENGTH_INDEX);
Expand All @@ -310,16 +304,9 @@ export class NFTMethod extends BaseMethod {
const nftID = Buffer.concat([this._config.ownChainID, collectionID, indexBytes]);
this._feeMethod.payFee(methodContext, BigInt(FEE_CREATE_NFT));

const nftStore = this.stores.get(NFTStore);
await nftStore.save(methodContext, nftID, {
owner: address,
attributesArray,
});
await this._internalMethod.createNFTEntry(methodContext, address, nftID, attributesArray);

const userStore = this.stores.get(UserStore);
await userStore.set(methodContext, userStore.getKey(address, nftID), {
lockingModule: NFT_NOT_LOCKED,
});
await this._internalMethod.createUserEntry(methodContext, address, nftID);

this.events.get(CreateEvent).log(methodContext, {
address,
Expand Down Expand Up @@ -970,7 +957,12 @@ export class NFTMethod extends BaseMethod {
storedAttributes,
receivedAttributes,
);
await nftStore.save(methodContext, nftID, nftData);
await this._internalMethod.createNFTEntry(
methodContext,
nftData.owner,
nftID,
nftData.attributesArray,
);
await this._internalMethod.createUserEntry(methodContext, nftData.owner, nftID);
await escrowStore.del(methodContext, escrowStore.getKey(terminatedChainID, nftID));

Expand Down Expand Up @@ -1007,7 +999,13 @@ export class NFTMethod extends BaseMethod {
} else {
nftData.attributesArray.push({ module, attributes });
}
await nftStore.save(methodContext, nftID, nftData);

await this._internalMethod.createNFTEntry(
methodContext,
nftData.owner,
nftID,
nftData.attributesArray,
);

this.events.get(SetAttributesEvent).log(methodContext, {
nftID,
Expand Down
17 changes: 6 additions & 11 deletions framework/src/modules/nft/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ import {
LENGTH_ADDRESS,
LENGTH_CHAIN_ID,
MODULE_NAME_NFT,
NFT_NOT_LOCKED,
} from './constants';

export class NFTModule extends BaseInteroperableModule {
Expand Down Expand Up @@ -273,24 +272,20 @@ export class NFTModule extends BaseInteroperableModule {
supportedChainsKeySet.add(supportedNFT.chainID);
}

const nftStore = this.stores.get(NFTStore);
const escrowStore = this.stores.get(EscrowStore);
const userStore = this.stores.get(UserStore);

for (const nft of genesisStore.nftSubstore) {
const { owner, nftID, attributesArray } = nft;

await nftStore.save(context, nftID, {
await this._internalMethod.createNFTEntry(
context.getMethodContext(),
owner,
nftID,
attributesArray,
});
);

if (owner.length === LENGTH_CHAIN_ID) {
await escrowStore.set(context, escrowStore.getKey(owner, nftID), {});
await this._internalMethod.createEscrowEntry(context.getMethodContext(), owner, nftID);
} else {
await userStore.set(context, userStore.getKey(owner, nftID), {
lockingModule: NFT_NOT_LOCKED,
});
await this._internalMethod.createUserEntry(context.getMethodContext(), owner, nftID);
}
}

Expand Down
36 changes: 34 additions & 2 deletions framework/test/unit/modules/nft/internal_method.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { TransferEvent, TransferEventData } from '../../../../src/modules/nft/ev
import { UserStore } from '../../../../src/modules/nft/stores/user';
import { EscrowStore } from '../../../../src/modules/nft/stores/escrow';
import { NFTMethod } from '../../../../src/modules/nft/method';
import { InteroperabilityMethod } from '../../../../src/modules/nft/types';
import { InteroperabilityMethod, NFTAttributes } from '../../../../src/modules/nft/types';
import {
TransferCrossChainEvent,
TransferCrossChainEventData,
Expand Down Expand Up @@ -102,6 +102,38 @@ describe('InternalMethod', () => {
});
});

describe('hasDuplicateModuleNames', () => {
it('should return false when the attributes array is empty', () => {
const attributesArray: NFTAttributes[] = [];

expect(internalMethod.hasDuplicateModuleNames(attributesArray)).toBeFalse();
});

it('should return false when all module names are unique', () => {
const attributesArray: NFTAttributes[] = [
{ module: 'module1', attributes: Buffer.from('attributes1') },
{ module: 'module2', attributes: Buffer.from('attributes2') },
{ module: 'module3', attributes: Buffer.from('attributes3') },
];

const result = internalMethod.hasDuplicateModuleNames(attributesArray);

expect(result).toBeFalse();
});

it('should return true when there are duplicate module names', () => {
const attributesArray: NFTAttributes[] = [
{ module: 'module1', attributes: Buffer.from('attributes1') },
{ module: 'module1', attributes: Buffer.from('attributes2') },
{ module: 'module3', attributes: Buffer.from('attributes3') },
];

const result = internalMethod.hasDuplicateModuleNames(attributesArray);

expect(result).toBeTrue();
});
});

describe('createNFTEntry', () => {
it('should throw for duplicate module names in attributes array', async () => {
const attributesArray = [
Expand Down Expand Up @@ -132,7 +164,7 @@ describe('InternalMethod', () => {
},
];

const sortedAttributesArray = unsortedAttributesArray.sort((a, b) =>
const sortedAttributesArray = [...unsortedAttributesArray].sort((a, b) =>
a.module.localeCompare(b.module, 'en'),
);

Expand Down