From 6dc7d249e0264246c7dc81e9a734f4825f264d1b Mon Sep 17 00:00:00 2001 From: imsk17 Date: Fri, 4 Oct 2024 13:36:54 +0530 Subject: [PATCH] feat(mx): implement locking and claiming SFTs --- src/handlers/multiversx/index.ts | 194 ++++++++++++++++++++----------- src/handlers/multiversx/types.ts | 60 +++++++++- 2 files changed, 186 insertions(+), 68 deletions(-) diff --git a/src/handlers/multiversx/index.ts b/src/handlers/multiversx/index.ts index 35beead1..647c0f7f 100644 --- a/src/handlers/multiversx/index.ts +++ b/src/handlers/multiversx/index.ts @@ -7,20 +7,15 @@ import { AbiRegistry, Account, Address, - AddressType, AddressValue, - BigUIntType, BigUIntValue, - BytesType, BytesValue, ContractCallPayloadBuilder, ContractFunction, Field, - FieldDefinition, ResultsParser, SmartContract, Struct, - StructType, TokenTransfer, Transaction, TransactionPayload, @@ -35,6 +30,7 @@ import { multiversXBridgeABI } from "../../contractsTypes/multiversx"; import { raise } from "../ton"; import { fetchHttpOrIpfs } from "../utils"; import { + StructClaimDataType, TMultiversXHandler, TMultiversXParams, TMultiversXSigner, @@ -179,6 +175,133 @@ export function multiversxHandler({ getProvider() { return provider; }, + async claimSft(signer, claimData, sigs) { + const userAddress = Address.fromString(await signer.getAddress()); + const userAccount = new Account(userAddress); + const userOnNetwork = await provider.getAccount(userAddress); + userAccount.update(userOnNetwork); + + const imgUri = (await fetchHttpOrIpfs(claimData.metadata)).image; + + const claimDataArgs = new Struct(StructClaimDataType, [ + new Field( + new BytesValue( + Buffer.from(new Nonce(Number(claimData.tokenId)).hex(), "hex"), + ), + "token_id", + ), + new Field( + new BytesValue(Buffer.from(claimData.sourceChain)), + "source_chain", + ), + new Field( + new BytesValue(Buffer.from(claimData.destinationChain)), + "destination_chain", + ), + new Field( + new AddressValue(new Address(claimData.destinationUserAddress)), + "destination_user_address", + ), + new Field( + new BytesValue(Buffer.from(claimData.sourceNftContractAddress)), + "source_nft_contract_address", + ), + new Field(new BytesValue(Buffer.from(claimData.name)), "name"), + new Field(new BytesValue(Buffer.from(claimData.symbol)), "symbol"), + new Field(new BigUIntValue(Number(claimData.royalty)), "royalty"), + new Field( + new AddressValue(new Address(claimData.royaltyReceiver)), + "royalty_receiver", + ), + new Field(new BytesValue(Buffer.from(claimData.metadata)), "attrs"), + new Field( + new BytesValue(Buffer.from(claimData.transactionHash)), + "transaction_hash", + ), + new Field(new BigUIntValue(claimData.tokenAmount), "token_amount"), + new Field(new BytesValue(Buffer.from(claimData.nftType)), "nft_type"), + new Field(new BigUIntValue(claimData.fee), "fee"), + new Field( + new BytesValue(Buffer.from(claimData.lockTxChain)), + "lock_tx_chain", + ), + new Field(new BytesValue(Buffer.from(imgUri)), "img_uri"), + ]); + const data = [ + claimDataArgs, + + sigs.map((item) => { + return { + public_key: new AddressValue( + new Address(Buffer.from(item.signerAddress, "hex")), + ), + sig: new BytesValue( + Buffer.from(item.signature.replace("0x", ""), "hex"), + ), + }; + }), + ]; + const transaction = multiversXBridgeContract.methods + .claimNft721(data) + .withSender(Address.fromString(await signer.getAddress())) + .withChainID("D") + .withGasLimit(6_000_000_00) + .withValue(new BigUIntValue("50000000000000000")) + .buildTransaction(); + transaction.setNonce(userAccount.getNonceThenIncrement()); + const signed = await signer.signTransaction(transaction); + const hash = await provider.sendTransaction(signed); + return { hash: () => hash, ret: hash }; + }, + async lockSft(signer, sourceNft, destinationChain, to, tokenId, amt) { + const ba = new Address(bridge); + + const userAddress = Address.fromString(await signer.getAddress()); + + const userAccount = new Account(userAddress); + const userOnNetwork = await provider.getAccount(userAddress); + userAccount.update(userOnNetwork); + + const collectionIdentifiers = `@${Buffer.from(sourceNft).toString( + "hex", + )}`; + const amount = `@${amt}`; + const nonce = new Nonce(Number(tokenId)).hex(); + const noncec = `@${nonce}`; + const quantity = "@" + "01"; + const destination_address = `@${ba.hex()}`; + const method = `@${Buffer.from("lock721").toString("hex")}`; + const token_id = `@${Buffer.from(`${sourceNft}-0${tokenId}`).toString( + "hex", + )}`; + const destination_chain = `@${Buffer.from(destinationChain).toString( + "hex", + )}`; + const destination_user_address = `@${Buffer.from(to).toString("hex")}`; + const source_nft_contract_address = collectionIdentifiers; + + const tx3 = new Transaction({ + data: new TransactionPayload( + `ESDTNFTTransfer${collectionIdentifiers}${noncec}${quantity}${destination_address}${method}${token_id}${destination_chain}${destination_user_address}${source_nft_contract_address}${amount}${noncec}`, + ), + gasLimit: 600000000, + sender: Address.fromString(await signer.getAddress()), + receiver: Address.fromString(await signer.getAddress()), + chainID: "D", + }); + + tx3.setNonce(userAccount.getNonceThenIncrement()); + + const signed = await signer.signTransaction(tx3); + + const txHash = await provider.sendTransaction(signed); + return { + tx: txHash, + hash() { + return txHash; + }, + }; + }, async readClaimed721Event(hash) { await waitForTransaction(hash); const response = ( @@ -408,66 +531,7 @@ export function multiversxHandler({ const imgUri = (await fetchHttpOrIpfs(claimData.metadata)).image; - const structClaimData = new StructType("ClaimData", [ - new FieldDefinition("token_id", "name of the nft", new BytesType()), - new FieldDefinition( - "source_chain", - "attributes of the nft", - new BytesType(), - ), - new FieldDefinition( - "destination_chain", - "attributes of the nft", - new BytesType(), - ), - new FieldDefinition( - "destination_user_address", - "attributes of the nft", - new AddressType(), - ), - new FieldDefinition( - "source_nft_contract_address", - "attributes of the nft", - new BytesType(), - ), - new FieldDefinition("name", "attributes of the nft", new BytesType()), - new FieldDefinition("symbol", "attributes of the nft", new BytesType()), - new FieldDefinition( - "royalty", - "attributes of the nft", - new BigUIntType(), - ), - new FieldDefinition( - "royalty_receiver", - "attributes of the nft", - new AddressType(), - ), - new FieldDefinition("attrs", "attributes of the nft", new BytesType()), - new FieldDefinition( - "transaction_hash", - "attributes of the nft", - new BytesType(), - ), - new FieldDefinition( - "token_amount", - "attributes of the nft", - new BigUIntType(), - ), - new FieldDefinition( - "nft_type", - "attributes of the nft", - new BytesType(), - ), - new FieldDefinition("fee", "attributes of the nft", new BigUIntType()), - new FieldDefinition( - "lock_tx_chain", - "Chain identifier on which nft was locked", - new BytesType(), - ), - new FieldDefinition("img_uri", "uri of the image", new BytesType()), - ]); - - const claimDataArgs = new Struct(structClaimData, [ + const claimDataArgs = new Struct(StructClaimDataType, [ new Field( new BytesValue( Buffer.from(new Nonce(Number(claimData.tokenId)).hex(), "hex"), diff --git a/src/handlers/multiversx/types.ts b/src/handlers/multiversx/types.ts index 4351d463..4689691c 100644 --- a/src/handlers/multiversx/types.ts +++ b/src/handlers/multiversx/types.ts @@ -1,4 +1,11 @@ -import { Transaction } from "@multiversx/sdk-core/out"; +import { + AddressType, + BigUIntType, + BytesType, + FieldDefinition, + StructType, + Transaction, +} from "@multiversx/sdk-core/out"; import { INetworkProvider } from "@multiversx/sdk-network-providers/out/interface"; import { BridgeStorage } from "../../contractsTypes/evm"; import { @@ -6,7 +13,7 @@ import { MintNft, ReadClaimed721Event, ReadClaimed1155Event, - TSingularNftChain, + TNftChain, } from "../types"; // Custom Interface because there is no such signer interface in mx-sdk. @@ -48,7 +55,7 @@ export type NftIssueArgs = { readonly ticker: string; }; -export type TMultiversXHandler = TSingularNftChain< +export type TMultiversXHandler = TNftChain< TMultiversXSigner, TMultiversXClaimArgs, unknown, @@ -83,3 +90,50 @@ export type TMultiversXParams = { chainId: string; identifier: string; }; + +export const StructClaimDataType = new StructType("ClaimData", [ + new FieldDefinition("token_id", "name of the nft", new BytesType()), + new FieldDefinition("source_chain", "attributes of the nft", new BytesType()), + new FieldDefinition( + "destination_chain", + "attributes of the nft", + new BytesType(), + ), + new FieldDefinition( + "destination_user_address", + "attributes of the nft", + new AddressType(), + ), + new FieldDefinition( + "source_nft_contract_address", + "attributes of the nft", + new BytesType(), + ), + new FieldDefinition("name", "attributes of the nft", new BytesType()), + new FieldDefinition("symbol", "attributes of the nft", new BytesType()), + new FieldDefinition("royalty", "attributes of the nft", new BigUIntType()), + new FieldDefinition( + "royalty_receiver", + "attributes of the nft", + new AddressType(), + ), + new FieldDefinition("attrs", "attributes of the nft", new BytesType()), + new FieldDefinition( + "transaction_hash", + "attributes of the nft", + new BytesType(), + ), + new FieldDefinition( + "token_amount", + "attributes of the nft", + new BigUIntType(), + ), + new FieldDefinition("nft_type", "attributes of the nft", new BytesType()), + new FieldDefinition("fee", "attributes of the nft", new BigUIntType()), + new FieldDefinition( + "lock_tx_chain", + "Chain identifier on which nft was locked", + new BytesType(), + ), + new FieldDefinition("img_uri", "uri of the image", new BytesType()), +]);