@tatumio/nft-connector
Version:
NFT Connector for Tatum API
887 lines (856 loc) • 45.6 kB
text/typescript
import axios from 'axios';
import {PinoLogger} from 'nestjs-pino';
import BigNumber from 'bignumber.js';
import * as fcl from '@onflow/fcl';
import * as sdk from '@onflow/sdk';
import {mintNft as mintSolanaNft, SolanaMintNft, transferNft as transferSolanaNft} from '@tatumio/tatum-solana';
import {
TransferErc721 as CoreTransferErc721,
MintErc721 as CoreMintErc721,
BurnErc721 as CoreBurnErc721,
DeployErc721 as CoreDeployErc721,
} from '@tatumio/tatum-core';
import {
prepareBurnErc721SignedTransaction as prepareKcsBurnErc721SignedTransaction,
prepareDeployErc721SignedTransaction as prepareKcsDeployErc721SignedTransaction,
prepareMintErc721SignedTransaction as prepareKcsMintErc721SignedTransaction,
prepareTransferErc721SignedTransaction as prepareKcsTransferErc721SignedTransaction,
prepareUpdateCashbackForAuthorErc721SignedTransaction as prepareKcsUpdateCashbackForAuthorErc721SignedTransaction
} from '@tatumio/tatum-kcs';
import {Connection, programs} from '@metaplex/js';
import {NftError} from './NftError';
import {HarmonyAddress} from '@harmony-js/crypto';
import erc721Provenance_abi from '@tatumio/tatum/dist/src/contracts/erc721Provenance/erc721Provenance_abi';
import erc721_abi from '@tatumio/tatum/dist/src/contracts/erc721/erc721_abi';
import Web3 from 'web3';
import {Transaction, TransactionReceipt} from 'web3-eth';
import {FlowTxType,} from '@tatumio/tatum/dist/src/transaction/flow';
import {
prepareOneBurn721SignedTransaction,
prepareOneDeploy721SignedTransaction,
prepareOneMint721SignedTransaction,
prepareOneMintCashback721SignedTransaction,
prepareOneMintMultiple721SignedTransaction,
prepareOneMintMultipleCashback721SignedTransaction,
prepareOneTransfer721SignedTransaction,
prepareOneUpdateCashbackForAuthor721SignedTransaction
} from '@tatumio/tatum/dist/src/transaction/one';
import {ChainEgldEsdtTransaction} from './dto/ChainEgldEsdtTransaction';
import {
AddMinter,
BurnErc721,
CeloBurnErc721,
CeloDeployErc721,
CeloMintErc721,
CeloMintMultipleErc721,
CeloTransferErc721,
CeloUpdateCashbackErc721,
convertAddressFromHex,
Currency,
DeployErc721,
EgldEsdtTransaction,
egldGetTransaction,
EgldTransaction,
EthBurnErc721,
EthDeployErc721,
EthMintErc721,
EthMintMultipleErc721,
EthTransferErc721,
FlowBurnNft,
FlowDeployNft,
FlowMintMultipleNft,
FlowMintNft,
FlowTransferNft,
getAlgoClient,
getFlowNftMetadata,
getFlowNftTokenByAddress,
OneBurn721,
OneDeploy721,
OneMint721,
OneMintMultiple721,
OneTransfer721,
OneUpdateCashback721,
prepareAddNFTMinter,
prepareAlgoBurnNFTSignedTransaction,
prepareAlgoCreateNFTSignedTransaction,
prepareAlgoTransferNFTSignedTransaction,
prepareBscBurnBep721SignedTransaction,
prepareBscDeployBep721SignedTransaction,
prepareBscMintBep721ProvenanceSignedTransaction,
prepareBscMintBep721SignedTransaction,
prepareBscMintBepCashback721SignedTransaction,
prepareBscMintMultipleBep721ProvenanceSignedTransaction,
prepareBscMintMultipleBep721SignedTransaction,
prepareBscMintMultipleCashbackBep721SignedTransaction,
prepareBscTransferBep721SignedTransaction,
prepareBscUpdateCashbackForAuthorErc721SignedTransaction,
prepareCeloBurnErc721SignedTransaction,
prepareCeloDeployErc721SignedTransaction,
prepareCeloMintCashbackErc721SignedTransaction,
prepareCeloMintErc721ProvenanceSignedTransaction,
prepareCeloMintErc721SignedTransaction,
prepareCeloMintMultipleCashbackErc721SignedTransaction,
prepareCeloMintMultipleErc721ProvenanceSignedTransaction,
prepareCeloMintMultipleErc721SignedTransaction,
prepareCeloTransferErc721SignedTransaction,
prepareCeloUpdateCashbackForAuthorErc721SignedTransaction,
prepareEgldAddOrBurnNftQuantitySignedTransaction,
prepareEgldCreateNftOrSftSignedTransaction,
prepareEgldDeployNftOrSftSignedTransaction,
prepareEgldTransferNftSignedTransaction,
prepareEthBurnErc721SignedTransaction,
prepareEthDeployErc721SignedTransaction,
prepareEthMintCashbackErc721SignedTransaction,
prepareEthMintErc721ProvenanceSignedTransaction,
prepareEthMintErc721SignedTransaction,
prepareEthMintMultipleCashbackErc721SignedTransaction,
prepareEthMintMultipleErc721ProvenanceSignedTransaction,
prepareEthMintMultipleErc721SignedTransaction,
prepareEthTransferErc721SignedTransaction,
prepareEthUpdateCashbackForAuthorErc721SignedTransaction,
prepareOneMint721ProvenanceSignedTransaction,
prepareOneMintMultiple721ProvenanceSignedTransaction,
preparePolygonBurnErc721SignedTransaction,
preparePolygonDeployErc721SignedTransaction,
preparePolygonMintCashbackErc721SignedTransaction,
preparePolygonMintErc721ProvenanceSignedTransaction,
preparePolygonMintErc721SignedTransaction,
preparePolygonMintMultipleCashbackErc721SignedTransaction,
preparePolygonMintMultipleErc721ProvenanceSignedTransaction,
preparePolygonMintMultipleErc721SignedTransaction,
preparePolygonTransferErc721SignedTransaction,
preparePolygonUpdateCashbackForAuthorErc721SignedTransaction,
prepareTronBurnTrc721SignedTransaction,
prepareTronDeployTrc721SignedTransaction,
prepareTronMintCashbackTrc721SignedTransaction,
prepareTronMintMultipleTrc721SignedTransaction,
prepareTronMintTrc721SignedTransaction,
prepareTronTransferTrc721SignedTransaction,
prepareTronUpdateCashbackForAuthorTrc721SignedTransaction,
sendBscSmartContractReadMethodInvocationTransaction,
sendCeloSmartContractReadMethodInvocationTransaction,
sendFlowNftBurnToken,
sendFlowNftMintMultipleToken,
sendFlowNftMintToken,
sendFlowNftTransferToken,
sendOneSmartContractReadMethodInvocationTransaction,
sendPolygonSmartContractReadMethodInvocationTransaction,
sendSmartContractReadMethodInvocationTransaction,
SmartContractReadMethodInvocation,
TransactionHash,
TransferErc721,
TronBurnTrc721,
TronDeployTrc721,
TronMintMultipleTrc721,
TronMintTrc721,
TronTransferTrc721,
TronUpdateCashbackTrc721,
UpdateCashbackErc721
} from '@tatumio/tatum';
export abstract class NftService {
protected constructor(protected readonly logger: PinoLogger) {
}
protected abstract storeKMSTransaction(txData: string, currency: string, signatureId: string[], index?: number): Promise<string>;
protected abstract isTestnet(): Promise<boolean>;
protected abstract wrapFlowCall(operation: (proposer: any, payer: any) => Promise<any>): Promise<any>;
protected abstract getTronClient(testnet: boolean): Promise<any>;
protected abstract getNodesUrl(chain: Currency, testnet: boolean): Promise<string[]>;
protected abstract broadcast(chain: Currency, txData: string, signatureId?: string);
protected abstract deployFlowNft(testnet: boolean, body: FlowDeployNft): Promise<TransactionHash>;
protected abstract getMintBuiltInData(body: CeloMintErc721 | EthMintErc721 | TronMintTrc721 | OneMint721): Promise<CeloMintErc721 | EthMintErc721 | TronMintTrc721 | OneMint721 | CoreMintErc721 | undefined>;
public async getMetadataErc721(chain: Currency, token: string, contractAddress: string, account?: string, nonce?: string): Promise<{ data?: string, onchainData?: any }> {
if (chain === Currency.FLOW) {
if (!account) {
throw new NftError(`Account address must be present.`, 'nft.erc721.failed');
}
try {
return {data: await getFlowNftMetadata(await this.isTestnet(), account, token, contractAddress)};
} catch (e) {
this.logger.error(e);
throw new NftError(`Unable to obtain information for token. ${e}`, 'nft.erc721.failed');
}
} else if (chain === Currency.TRON) {
const client = await this.getClient(chain, await this.isTestnet());
client.setAddress(contractAddress);
const c = await client.contract().at(contractAddress);
try {
return {data: await c.tokenURI(token).call()};
} catch (e) {
this.logger.error(e);
throw new NftError(`Unable to obtain information for token. ${e}`, 'nft.erc721.failed');
}
} else if (chain === Currency.EGLD) {
return await this.getElrondNftDataForAddress(chain, token, contractAddress, nonce, await this.isTestnet())
} else if (chain === Currency.SOL.toString()) {
const connection = new Connection((await this.getNodesUrl(Currency.SOL, await this.isTestnet()))[0]);
const metadata = await programs.metadata.Metadata.findMany(connection, {mint: contractAddress});
if (metadata?.length > 0) {
return {onchainData: metadata[0].data}
}
throw new NftError(`Unable to obtain information for token.`, 'nft.erc721.failed');
}
// @ts-ignore
const c = new (await this.getClient(chain, await this.isTestnet())).eth.Contract(erc721_abi, chain === Currency.ONE ? new HarmonyAddress(contractAddress).basicHex : contractAddress);
try {
return {data: await c.methods.tokenURI(token).call()};
} catch (e) {
this.logger.error(e);
throw new NftError(`Unable to obtain information for token. ${e}`, 'nft.erc721.failed');
}
}
public async getRoyaltyErc721(chain: Currency, token: string, contractAddress: string, nonce?: string) {
if (chain === Currency.FLOW) {
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
} else if (chain === Currency.TRON) {
const client = await this.getClient(chain, await this.isTestnet());
client.setAddress(contractAddress);
const c = await client.contract().at(contractAddress);
try {
const [addresses, values] = await Promise.all([c.tokenCashbackRecipients(token).call(), c.tokenCashbackValues(token).call()]);
return {
addresses: addresses.map(a => convertAddressFromHex(a)),
values: values.map(c => new BigNumber(c._hex).dividedBy(1e6).toString(10))
};
} catch (e) {
this.logger.error(e);
throw new NftError(`Unable to obtain information for token. ${e}`, 'nft.erc721.failed');
}
} else if (chain === Currency.EGLD) {
const data = await this.getElrondNftDataForAddress(chain, token, contractAddress, nonce, await this.isTestnet())
return {addresses: [token], values: [data?.royalties]}
} else if (chain === Currency.SOL.toString()) {
const connection = new Connection((await this.getNodesUrl(Currency.SOL, await this.isTestnet()))[0]);
const metadata = await programs.metadata.Metadata.findMany(connection, {mint: contractAddress});
if (metadata?.length > 0) {
const creators = metadata[0].data.data.creators || [];
return {addresses: creators.map(c => c.address), values: creators.map(c => c.share.toString())};
}
throw new NftError(`Unable to obtain information for token.`, 'nft.erc721.failed');
}
// @ts-ignore
const c = new (await this.getClient(chain, await this.isTestnet())).eth.Contract(erc721_abi, chain === Currency.ONE ? new HarmonyAddress(contractAddress).basicHex : contractAddress);
try {
const [addresses, values] = await Promise.all([c.methods.tokenCashbackRecipients(token).call(), c.methods.tokenCashbackValues(token,`0x${new BigNumber(1).multipliedBy(1e18).toString(16)}`).call()]);
return {addresses, values: values.map(c => new BigNumber(c).dividedBy(1e18).toString(10))};
} catch (e) {
this.logger.error(e);
throw new NftError(`Unable to obtain information for token. ${e}`, 'nft.erc721.failed');
}
}
public async getProvenanceData(chain: Currency, contractAddress: string, tokenId: string) {
try {
const testnet = await this.isTestnet();
const provider = (await this.getNodesUrl(chain, testnet))[0];
const body = new SmartContractReadMethodInvocation()
const result = [];
let txData;
body.contractAddress = contractAddress
body.params = [tokenId]
body.methodName = 'getTokenData'
body.methodABI = erc721Provenance_abi.find((a: any) => a.name === 'getTokenData')
switch (chain) {
case Currency.ETH:
txData = await sendSmartContractReadMethodInvocationTransaction(body);
break;
case Currency.CELO:
txData = await sendCeloSmartContractReadMethodInvocationTransaction(testnet, body, provider);
break;
case Currency.BSC:
txData = await sendBscSmartContractReadMethodInvocationTransaction(body);
break;
case Currency.ONE:
txData = await sendOneSmartContractReadMethodInvocationTransaction(testnet, body, provider);
break;
case Currency.MATIC:
txData = await sendPolygonSmartContractReadMethodInvocationTransaction(testnet, body, provider);
break;
default:
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
}
for (let i = 0; i < txData.data.length; i++) {
const t = txData.data[i].split("'''###'''", 2)
result.push({provenanceData: t[0], tokenPrice: t[1]})
}
return result
} catch (e) {
this.logger.error(e);
throw new NftError(`Unable to obtain information for token. ${e}`, 'nft.erc721.failed');
}
}
public async getTokensOfOwner(chain: Currency, address: string, contractAddress: string, nonce?: string | undefined) {
if (chain === Currency.FLOW) {
try {
return (await getFlowNftTokenByAddress(await this.isTestnet(), address, contractAddress)).map(e => `${e}`);
} catch (e) {
this.logger.error(e);
throw new NftError(`Unable to obtain information for token. ${e}`, 'nft.erc721.failed');
}
} else if (chain === Currency.TRON) {
const client = await this.getClient(chain, await this.isTestnet());
client.setAddress(contractAddress);
const c = await client.contract().at(contractAddress);
try {
return {data: (await c.tokensOfOwner(address).call()).map(c => new BigNumber(c._hex).toString(10))};
} catch (e) {
this.logger.error(e);
throw new NftError(`Unable to obtain information for token. ${e}`, 'nft.erc721.failed');
}
} else if (chain === Currency.EGLD) {
return {data: [(await this.getElrondNftDataForAddress(chain, address, contractAddress, nonce, await this.isTestnet()))?.creator]}
}
// @ts-ignore
const c = new (await this.getClient(chain, await this.isTestnet())).eth.Contract(erc721_abi, chain === Currency.ONE ? new HarmonyAddress(contractAddress).basicHex : contractAddress);
try {
return {data: await c.methods.tokensOfOwner(address).call()};
} catch (e) {
this.logger.error(e);
throw new NftError(`Unable to obtain information for token. ${e}`, 'nft.erc721.failed');
}
}
public async getContractAddress(chain: Currency, txId: string) {
if (chain === Currency.FLOW) {
try {
await this.getClient(chain, await this.isTestnet());
const tx = await sdk.send(sdk.build([sdk.getTransaction(txId)]));
const {args} = await sdk.decode(tx);
if (args && args.length) {
return {contractAddress: args[0].value};
}
} catch (e) {
this.logger.error(e);
}
throw new NftError('Transaction not found. Possible not exists or is still pending.', 'tx.not.found');
} else if (chain === Currency.TRON) {
try {
const tx = await (await this.getClient(chain, await this.isTestnet())).trx.getTransactionInfo(txId);
return {contractAddress: convertAddressFromHex(tx.contract_address)};
} catch (e) {
this.logger.error(e);
throw new NftError('Transaction not found. Possible not exists or is still pending.', 'tx.not.found');
}
} else if (chain === Currency.EGLD) {
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
}
try {
const web3 = await this.getClient(chain, await this.isTestnet());
const {contractAddress} = await web3.eth.getTransactionReceipt(txId);
return {contractAddress};
} catch (e) {
this.logger.error(e);
throw new NftError('Transaction not found. Possible not exists or is still pending.', 'tx.not.found');
}
}
public async getTransaction(chain: Currency, txId: string): Promise<Transaction & TransactionReceipt | EgldTransaction> {
if (chain === Currency.FLOW) {
try {
await this.getClient(chain, await this.isTestnet());
const tx = await sdk.send(sdk.build([sdk.getTransaction(txId)]));
const decoded = await sdk.decode(tx);
try {
const txStatus = await sdk.send(sdk.build([sdk.getTransactionStatus(txId)]));
return {...decoded, ...await sdk.decode(txStatus)};
} catch (e) {
this.logger.warn(e);
}
return decoded;
} catch (e) {
this.logger.error(e);
}
throw new NftError('Transaction not found. Possible not exists or is still pending.', 'tx.not.found');
} else if (chain === Currency.TRON) {
try {
return await (await this.getClient(chain, await this.isTestnet())).trx.getTransactionInfo(txId);
} catch (e) {
this.logger.error(e);
throw new NftError('Transaction not found. Possible not exists or is still pending.', 'tx.not.found');
}
} else if (chain === Currency.EGLD) {
try {
return await egldGetTransaction(txId);
} catch (e) {
this.logger.error(e);
throw new NftError('Transaction not found. Possible not exists or is still pending.', 'tx.not.found');
}
}
try {
const web3 = await this.getClient(chain, await this.isTestnet());
const {r, s, v, hash, ...transaction} = (await web3.eth.getTransaction(txId)) as any;
let receipt: TransactionReceipt = undefined;
try {
receipt = await web3.eth.getTransactionReceipt(hash);
} catch (_) {
transaction.transactionHash = hash;
}
return {...transaction, ...receipt};
} catch (e) {
this.logger.error(e);
throw new NftError('Transaction not found. Possible not exists or is still pending.', 'tx.not.found');
}
}
public async transferErc721(
body: CeloTransferErc721 | EthTransferErc721 | FlowTransferNft | TronTransferTrc721 | OneTransfer721 | ChainEgldEsdtTransaction | TransferErc721 | CoreTransferErc721
): Promise<TransactionHash | { signatureId: string }> {
const testnet = await this.isTestnet();
let txData;
const {chain} = body;
const provider = (await this.getNodesUrl(chain, testnet))[0];
switch (chain) {
case Currency.ETH:
txData = await prepareEthTransferErc721SignedTransaction(body as EthTransferErc721, provider);
break;
case Currency.ONE:
txData = await prepareOneTransfer721SignedTransaction(testnet, body as OneTransfer721, provider);
break;
case Currency.MATIC:
txData = await preparePolygonTransferErc721SignedTransaction(testnet, body as EthTransferErc721, provider);
break;
case Currency.KCS:
txData = await prepareKcsTransferErc721SignedTransaction(body as CoreTransferErc721, provider);
break;
case Currency.SOL.toString():
txData = await transferSolanaNft(body as any, provider);
if (body.signatureId) {
txData = JSON.stringify(txData);
}
break;
case Currency.TRON:
await this.getClient(chain, await this.isTestnet());
txData = await prepareTronTransferTrc721SignedTransaction(testnet, body as TronTransferTrc721);
break;
case Currency.BSC:
txData = await prepareBscTransferBep721SignedTransaction(body as EthTransferErc721, provider);
break;
case Currency.CELO:
txData = await prepareCeloTransferErc721SignedTransaction(testnet, body as CeloTransferErc721, provider);
break;
case Currency.EGLD:
txData = await prepareEgldTransferNftSignedTransaction(body as EgldEsdtTransaction, provider);
break;
case Currency.FLOW:
if (body.signatureId) {
txData = JSON.stringify({type: FlowTxType.TRANSFER_NFT, body});
} else {
return this.wrapFlowCall(async (proposer, payer) =>
await sendFlowNftTransferToken(testnet, body as FlowTransferNft, proposer, payer));
}
break;
case Currency.ALGO:
txData = await prepareAlgoTransferNFTSignedTransaction(testnet, body as TransferErc721, provider);
break;
// case Currency.XDC:
// txData = await prepareXdcTransferErc721SignedTransaction(body, (await this.getNodesUrl(chain, testnet))[0]);
// break;
default:
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
}
if (body.signatureId) {
return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)};
} else {
return this.broadcast(chain, txData);
}
}
public async mintErc721(
body: CeloMintErc721 | EthMintErc721 | FlowMintNft | TronMintTrc721 | OneMint721 | ChainEgldEsdtTransaction | SolanaMintNft | CoreMintErc721
): Promise<TransactionHash | { signatureId: string } | { txId: string, tokenId: number }> {
const testnet = await this.isTestnet();
let txData;
const {chain} = body;
const provider = (await this.getNodesUrl(chain, testnet))[0];
switch (chain) {
case Currency.ETH: {
const builtInBody = await this.getMintBuiltInData(body as EthMintErc721)
if ((body as EthMintErc721).provenance) {
txData = await prepareEthMintErc721ProvenanceSignedTransaction((builtInBody || body) as EthMintErc721, provider);
} else {
if (!(body as EthMintErc721).authorAddresses) {
txData = await prepareEthMintErc721SignedTransaction((builtInBody || body) as EthMintErc721, provider);
} else {
txData = await prepareEthMintCashbackErc721SignedTransaction((builtInBody || body) as EthMintErc721, provider);
}
}
break;
}
case Currency.MATIC: {
const builtInBody = await this.getMintBuiltInData(body as EthMintErc721)
if ((body as EthMintErc721).provenance) {
txData = await preparePolygonMintErc721ProvenanceSignedTransaction(testnet, (builtInBody || body) as EthMintErc721, provider);
} else {
if (!(body as EthMintErc721).authorAddresses) {
txData = await preparePolygonMintErc721SignedTransaction(testnet, (builtInBody || body) as EthMintErc721, provider);
} else {
txData = await preparePolygonMintCashbackErc721SignedTransaction(testnet, (builtInBody || body) as EthMintErc721, provider);
}
}
break;
}
case Currency.KCS: {
const builtInBody = await this.getMintBuiltInData(body as CoreMintErc721)
if ((body as CoreMintErc721).provenance) {
} else {
if (!(body as CoreMintErc721).authorAddresses) {
txData = await prepareKcsMintErc721SignedTransaction((builtInBody || body) as CoreMintErc721, provider);
} else {
}
}
break;
}
case Currency.ONE: {
const builtInBody = await this.getMintBuiltInData(body as OneMint721)
if ((body as OneMint721).provenance) {
txData = await prepareOneMint721ProvenanceSignedTransaction(testnet, (builtInBody || body) as OneMint721, provider);
} else {
if (!(body as OneMint721).authorAddresses) {
txData = await prepareOneMint721SignedTransaction(testnet, (builtInBody || body) as OneMint721, provider);
} else {
txData = await prepareOneMintCashback721SignedTransaction(testnet, (builtInBody || body) as OneMint721, provider);
}
}
break;
}
case Currency.BSC: {
const builtInBody = await this.getMintBuiltInData(body as EthMintErc721)
if ((body as EthMintErc721).provenance) {
txData = await prepareBscMintBep721ProvenanceSignedTransaction((builtInBody || body) as EthMintErc721, provider);
} else {
if (!(body as EthMintErc721).authorAddresses) {
txData = await prepareBscMintBep721SignedTransaction((builtInBody || body) as EthMintErc721, provider);
} else {
txData = await prepareBscMintBepCashback721SignedTransaction((builtInBody || body) as EthMintErc721, provider);
}
}
break;
}
case Currency.TRON:
await this.getClient(Currency.TRON, await this.isTestnet());
if (!(body as TronMintTrc721).authorAddresses) {
txData = await prepareTronMintTrc721SignedTransaction(testnet, body as TronMintTrc721);
} else {
txData = await prepareTronMintCashbackTrc721SignedTransaction(testnet, body as TronMintTrc721);
}
break;
case Currency.CELO: {
const builtInBody = await this.getMintBuiltInData(body as CeloMintErc721)
if ((body as CeloMintErc721).provenance) {
txData = await prepareCeloMintErc721ProvenanceSignedTransaction(testnet, (builtInBody || body) as CeloMintErc721, provider);
} else {
if (!(body as CeloMintErc721).authorAddresses) {
txData = await prepareCeloMintErc721SignedTransaction(testnet, (builtInBody || body) as CeloMintErc721, provider);
} else {
txData = await prepareCeloMintCashbackErc721SignedTransaction(testnet, (builtInBody || body) as CeloMintErc721, provider);
}
}
break;
}
case Currency.EGLD:
txData = await prepareEgldCreateNftOrSftSignedTransaction(body as EgldEsdtTransaction, provider)
break;
case Currency.SOL:
txData = await mintSolanaNft(body as SolanaMintNft, provider);
if (body.signatureId) {
txData = JSON.stringify(txData);
}
break;
case Currency.FLOW:
if (body.signatureId) {
txData = JSON.stringify({type: FlowTxType.MINT_NFT, body});
} else {
return this.wrapFlowCall(async (proposer, payer) => await sendFlowNftMintToken(testnet, body as FlowMintNft, proposer, payer));
}
break;
// case Currency.XDC:
// if (!(body as EthMintErc721).authorAddresses) {
// txData = await prepareXdcMintErc721SignedTransaction(body as EthMintErc721, provider);
// } else {
// txData = await prepareXdcMintErcCashback721SignedTransaction(body as EthMintErc721, provider);
// }
// break;
default:
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
}
if (body.signatureId) {
return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)};
} else {
return this.broadcast(chain, txData);
}
}
public async addMinter(body: AddMinter): Promise<TransactionHash | { signatureId: string } | { txId: string, tokenId: number }> {
const testnet = await this.isTestnet();
const {chain} = body;
const provider = (await this.getNodesUrl(chain, testnet))[0];
const txData = await prepareAddNFTMinter(testnet, body, provider);
if (body.signatureId) {
return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)};
} else {
return this.broadcast(chain, txData);
}
}
public async mintMultipleErc721(
body: CeloMintMultipleErc721 | EthMintMultipleErc721 | FlowMintMultipleNft | TronMintMultipleTrc721 | OneMintMultiple721
): Promise<TransactionHash | { signatureId: string } | { txId: string, tokenId: number[] }> {
const testnet = await this.isTestnet();
let txData;
const {chain} = body;
const provider = (await this.getNodesUrl(chain, testnet))[0];
switch (chain) {
case Currency.ETH:
if ((body as EthMintMultipleErc721).provenance) {
txData = await prepareEthMintMultipleErc721ProvenanceSignedTransaction(body as EthMintMultipleErc721, provider);
} else {
if (!(body as EthMintMultipleErc721).authorAddresses) {
txData = await prepareEthMintMultipleErc721SignedTransaction(body as EthMintMultipleErc721, provider);
} else {
txData = await prepareEthMintMultipleCashbackErc721SignedTransaction(body as EthMintMultipleErc721, provider);
}
}
break;
case Currency.MATIC:
if ((body as EthMintMultipleErc721).provenance) {
txData = await preparePolygonMintMultipleErc721ProvenanceSignedTransaction(testnet, body as EthMintMultipleErc721, provider);
} else {
if (!(body as EthMintMultipleErc721).authorAddresses) {
txData = await preparePolygonMintMultipleErc721SignedTransaction(testnet, body as EthMintMultipleErc721, provider);
} else {
txData = await preparePolygonMintMultipleCashbackErc721SignedTransaction(testnet, body as EthMintMultipleErc721, provider);
}
}
break;
case Currency.ONE:
if ((body as OneMintMultiple721).provenance) {
txData = await prepareOneMintMultiple721ProvenanceSignedTransaction(testnet, body as OneMintMultiple721, provider);
} else {
if (!(body as OneMintMultiple721).authorAddresses) {
txData = await prepareOneMintMultiple721SignedTransaction(testnet, body as OneMintMultiple721, provider);
} else {
txData = await prepareOneMintMultipleCashback721SignedTransaction(testnet, body as OneMintMultiple721, provider);
}
}
break;
case Currency.TRON:
await this.getClient(chain, await this.isTestnet());
if (!(body as TronMintMultipleTrc721).authorAddresses) {
txData = await prepareTronMintMultipleTrc721SignedTransaction(testnet, body as TronMintMultipleTrc721);
} else {
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
}
break;
case Currency.BSC:
if ((body as EthMintMultipleErc721).provenance) {
txData = await prepareBscMintMultipleBep721ProvenanceSignedTransaction(body as EthMintMultipleErc721, provider);
} else {
if (!(body as EthMintMultipleErc721).authorAddresses) {
txData = await prepareBscMintMultipleBep721SignedTransaction(body as EthMintMultipleErc721, provider);
} else {
txData = await prepareBscMintMultipleCashbackBep721SignedTransaction(body as EthMintMultipleErc721, provider);
}
}
break;
case Currency.CELO:
if ((body as CeloMintMultipleErc721).provenance) {
txData = await prepareCeloMintMultipleErc721ProvenanceSignedTransaction(testnet, body as CeloMintMultipleErc721, provider);
} else {
if (!(body as CeloMintMultipleErc721).authorAddresses) {
txData = await prepareCeloMintMultipleErc721SignedTransaction(testnet, body as CeloMintMultipleErc721, provider);
} else {
txData = await prepareCeloMintMultipleCashbackErc721SignedTransaction(testnet, body as CeloMintMultipleErc721, provider);
}
}
break;
case Currency.EGLD:
// txData = await prepareEgldCreateNftOrSftSignedTransaction(body as EgldEsdtTransaction, provider)
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
case Currency.FLOW:
if (body.signatureId) {
txData = JSON.stringify({type: FlowTxType.MINT_MULTIPLE_NFT, body});
} else {
return this.wrapFlowCall(async (proposer, payer) => await sendFlowNftMintMultipleToken(testnet, body as FlowMintMultipleNft, proposer, payer));
}
break;
// case Currency.XDC:
// if (!(body as EthMintMultipleErc721).authorAddresses) {
// txData = await prepareXdcMintMultipleErc721SignedTransaction(body as EthMintMultipleErc721, provider);
// } else {
// txData = await prepareXdcMintMultipleCashbackErc721SignedTransaction(body as EthMintMultipleErc721, provider);
// }
// break;
default:
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
}
if (body.signatureId) {
return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)};
} else {
return this.broadcast(chain, txData);
}
}
public async updateCashbackForAuthor(body: CeloUpdateCashbackErc721 | UpdateCashbackErc721 | TronUpdateCashbackTrc721 | OneUpdateCashback721): Promise<TransactionHash | { signatureId: string }> {
const testnet = await this.isTestnet();
let txData;
const {chain} = body;
switch (chain) {
case Currency.ETH:
txData = await prepareEthUpdateCashbackForAuthorErc721SignedTransaction(body, (await this.getNodesUrl(chain, testnet))[0]);
break;
case Currency.MATIC:
txData = await preparePolygonUpdateCashbackForAuthorErc721SignedTransaction(testnet, body, (await this.getNodesUrl(chain, testnet))[0]);
break;
case Currency.KCS:
txData = await prepareKcsUpdateCashbackForAuthorErc721SignedTransaction(body, (await this.getNodesUrl(chain, testnet))[0]);
break;
case Currency.ONE:
txData = await prepareOneUpdateCashbackForAuthor721SignedTransaction(testnet, body as OneUpdateCashback721, (await this.getNodesUrl(chain, testnet))[0]);
break;
case Currency.TRON:
await this.getClient(chain, await this.isTestnet());
txData = await prepareTronUpdateCashbackForAuthorTrc721SignedTransaction(testnet, body as TronUpdateCashbackTrc721);
break;
case Currency.BSC:
txData = await prepareBscUpdateCashbackForAuthorErc721SignedTransaction(body, (await this.getNodesUrl(chain, testnet))[0]);
break;
case Currency.CELO:
txData = await prepareCeloUpdateCashbackForAuthorErc721SignedTransaction(testnet, body as CeloUpdateCashbackErc721, (await this.getNodesUrl(chain, testnet))[0]);
break;
case Currency.EGLD:
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
// case Currency.XDC:
// txData = await prepareXdcUpdateCashbackForAuthorErc721SignedTransaction(body, (await this.getNodesUrl(chain, testnet))[0]);
// break;
default:
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
}
if (body.signatureId) {
return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)};
} else {
return this.broadcast(chain, txData);
}
}
public async burnErc721(
body: CeloBurnErc721 | EthBurnErc721 | FlowBurnNft | TronBurnTrc721 | OneBurn721 | ChainEgldEsdtTransaction | BurnErc721 | CoreBurnErc721
): Promise<TransactionHash | { signatureId: string }> {
const testnet = await this.isTestnet();
let txData;
const {chain} = body;
const provider = (await this.getNodesUrl(chain, testnet))[0];
switch (chain) {
case Currency.ETH:
txData = await prepareEthBurnErc721SignedTransaction(body as EthBurnErc721, provider);
break;
case Currency.MATIC:
txData = await preparePolygonBurnErc721SignedTransaction(testnet, body as EthBurnErc721, provider);
break;
case Currency.KCS:
txData = await prepareKcsBurnErc721SignedTransaction(body as CoreBurnErc721, provider);
break;
case Currency.ONE:
txData = await prepareOneBurn721SignedTransaction(testnet, body as OneBurn721, provider);
break;
case Currency.TRON:
await this.getClient(chain, await this.isTestnet());
txData = await prepareTronBurnTrc721SignedTransaction(testnet, body as TronBurnTrc721);
break;
case Currency.BSC:
txData = await prepareBscBurnBep721SignedTransaction(body as EthBurnErc721, provider);
break;
case Currency.CELO:
txData = await prepareCeloBurnErc721SignedTransaction(testnet, body as CeloBurnErc721, provider);
break;
case Currency.EGLD:
txData = await prepareEgldAddOrBurnNftQuantitySignedTransaction(body as EgldEsdtTransaction, provider)
break;
case Currency.FLOW:
if (body.signatureId) {
txData = JSON.stringify({type: FlowTxType.BURN_NFT, body});
} else {
return this.wrapFlowCall(async (proposer, payer) => await sendFlowNftBurnToken(testnet, body as FlowBurnNft, proposer, payer));
}
break;
case Currency.ALGO:
txData = await prepareAlgoBurnNFTSignedTransaction(testnet, body as BurnErc721, provider);
break;
// case Currency.XDC:
// txData = await prepareXdcBurnErc721SignedTransaction(body, (await this.getNodesUrl(chain, testnet))[0]);
// break;
default:
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
}
if (body.signatureId) {
return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)};
} else {
return this.broadcast(chain, txData);
}
}
public async deployErc721(
body: CeloDeployErc721 | EthDeployErc721 | FlowDeployNft | TronDeployTrc721 | OneDeploy721 | ChainEgldEsdtTransaction | DeployErc721 | CoreDeployErc721
): Promise<TransactionHash | { signatureId: string }> {
const testnet = await this.isTestnet();
let txData;
const {chain} = body;
const provider = (await this.getNodesUrl(chain, testnet))[0];
switch (chain) {
case Currency.ETH:
txData = await prepareEthDeployErc721SignedTransaction(body as EthDeployErc721, provider);
break;
case Currency.MATIC:
txData = await preparePolygonDeployErc721SignedTransaction(testnet, body as EthDeployErc721, provider);
break;
case Currency.KCS:
txData = await prepareKcsDeployErc721SignedTransaction(body as CoreDeployErc721, provider);
break;
case Currency.ONE:
txData = await prepareOneDeploy721SignedTransaction(testnet, body as OneDeploy721, provider);
break;
case Currency.BSC:
txData = await prepareBscDeployBep721SignedTransaction(body as EthDeployErc721, provider);
break;
case Currency.TRON:
await this.getClient(chain, await this.isTestnet());
txData = await prepareTronDeployTrc721SignedTransaction(testnet, body as TronDeployTrc721);
break;
case Currency.CELO:
txData = await prepareCeloDeployErc721SignedTransaction(testnet, body as CeloDeployErc721, provider);
break;
case Currency.EGLD:
txData = await prepareEgldDeployNftOrSftSignedTransaction(body as EgldEsdtTransaction, provider)
break;
case Currency.FLOW:
return await this.deployFlowNft(testnet, body as FlowDeployNft);
break;
case Currency.ALGO:
txData = await prepareAlgoCreateNFTSignedTransaction(testnet, body as DeployErc721, provider)
break;
// case Currency.XDC:
// txData = await prepareXdcDeployErc721SignedTransaction(body as EthDeployErc721, (await this.getNodesUrl(chain, testnet))[0]);
// break;
default:
throw new NftError(`Unsupported chain ${chain}.`, 'unsupported.chain');
}
if (body.signatureId) {
return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)};
} else {
return await this.broadcast(chain, txData);
}
}
private async getElrondNftDataForAddress(
chain: Currency, address: string, contractAddress: string, nonce: string | undefined, testnet: boolean
): Promise<any> {
const provider = (await this.getNodesUrl(chain, testnet))[0];
try {
const {tokenData} = (await axios.get(`${provider}/address/${address}/nft/${contractAddress}/nonce/${nonce}`,
{headers: {'Content-Type': 'application/json'}})).data.data;
return {data: tokenData};
} catch (e) {
this.logger.error(e);
throw new NftError('Get NFT data for an address not found.', 'nft.not.found');
}
}
private async getClient(chain: Currency, testnet: boolean): Promise<any> {
const url = (await this.getNodesUrl(chain, testnet))[0];
if (chain === Currency.FLOW) {
fcl.config().put('accessNode.api', url);
return;
} else if (chain === Currency.TRON) {
return this.getTronClient(testnet);
} else if (chain === Currency.ALGO) {
return await getAlgoClient(await this.isTestnet(), (await this.getNodesUrl(chain, testnet))[0]);
}
return new Web3(url);
}
}