import Web3 from "web3";
import { VaultForMintableERC721 } from "../..";
import { IMyriaClient } from "../clients/MyriaClient";
import { AssetMarketpAPI, CommonAPI } from "../core/apis";
import { TransactionAPI } from "../core/apis/transaction.api";
import { TokenType, VaultForERC20, VaultForETH } from "../types";
import { APIResponseType } from "../types/APIResponseType";
import {
BulkTransferTokenRequestAPIParams,
BulkTransferTokenResponse,
TransactionPagingDetails,
ItemSignableTransferParams,
SignableBulkTransferParams,
SignableBulkTransferResponse,
TransactionCompleteParams,
TransactionCompleteResponse,
TransactionData,
TransferAPIInput,
TransferCommonParams,
TransferERC20Params,
TransferERC721Params,
TransferResponse,
TransferTokenParams,
TransactionPagingData,
ItemSignableBurnParams,
BurnTokenParams,
BurnTokenResponse,
BurnTokensRequestAPIParams,
SignableBurnTokensParams,
WhitelistTokensResponse,
TransferETHParams,
ICommonError,
} from "../types/TransactionTypes";
import { CommonModule } from "./CommonModule";
const QUANTUM_ERC20 = "10000000000";
/**
* Create TransactionManager module
* @class TransactionManager
* @param {IMyriaClient} IMyriaClient Interface of Myria Client
* @example <caption>TransactionManage instance.</caption>
* // + Approach 1:
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const moduleFactory = ModuleFactory.getInstance(mClient);
const transactionManager = moduleFactory.getTransactionManager();
// + Approach 2:
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const transactionManager = new TransactionManager(mClient);
*/
export class TransactionManager {
private transactionAPI: TransactionAPI;
private assetMarketplaceAPI: AssetMarketpAPI;
private commonModule: CommonModule;
private commonAPI: CommonAPI;
constructor(mClient: IMyriaClient) {
this.transactionAPI = new TransactionAPI(mClient.env);
this.commonModule = new CommonModule(mClient);
this.commonAPI = new CommonAPI(mClient.env);
this.assetMarketplaceAPI = new AssetMarketpAPI(mClient.env);
}
/**
* @summary Get transaction history list by stark key with paging options. This is designed for the purposes of small history reports sorted by latest date.
* @description Paging can be shown one after another (you cannot request for page 3 without first seeing page 1 and 2, for example, as you need details of last transaction of previous page to query for next page).
* @param {TransactionPagingDetails} TransactionPagingDetails Request params to query the list of transactions
* @returns {TransactionData[]} List of transaction details
*/
public async getTransactionList(
payload: TransactionPagingDetails
): Promise<any> {
const transactionList = await this.transactionAPI.getTransactionList(
payload
);
return transactionList;
}
/**
* @summary Get transaction details by transaction ID
* @param {number} transactionId Unique ID of transaction
* @returns {TransactionData} Transaction details information (including transactionStatus and createdAt, updatedAt...)
* @throws {string} Exception: Transaction ID should be valided and greater than 0
* @throws {string} Exception: Get transaction details failed with internal server error
*/
public async getTransactionDetails(
transactionId: number
): Promise<TransactionData> {
if (!transactionId || transactionId === 0) {
throw new Error("Transaction ID should be valided and greater than 0");
}
const transactionResponseData =
await this.transactionAPI.getTransactionDetails(transactionId);
if (transactionResponseData.status !== "success") {
throw new Error(
"Get transaction details failed with internal server error"
);
}
return transactionResponseData.data;
}
/**
* @summary Single Transfer ERC-721 (MINTABLE NFT) Token
* + The function is just supported for MINTABLE_ERC721 only
* @description After transfer was triggered, we can query the status of the transaction with the following functions:
* + getTransactionDetails(transactionId: number) {return TransactionData}
* + getTransactionsByPartnerRefID(partnerRefID: string) {return []TransactionData}
* @param {TransferERC721Params} transferParams Transfer ERC-721 token params (including sender and receiver's information)
* @throws {string} Exception: Sender vault is not found
* @throws {string} Exception: Receiver vault is not found
* @throws {string} Http Status 400 - Sender/Receiver vaults does not exist
* @throws {string} Http Status 400 - Signature is invalid
* @throws {string} Http Status 400 - Vault IDs does not have enough funds
* @returns {TransferResponse} Transaction details (such as transactionID, transactionStatus...)
*/
public async transferERC721Token(
transferParams: TransferERC721Params
): Promise<TransferResponse> {
const requestSenderVaultERC721: VaultForMintableERC721 = {
starkKey: transferParams.senderPublicKey,
tokenId: transferParams.tokenId,
tokenAddress: transferParams.tokenAddress,
};
const requestReceiverVaultERC721: VaultForMintableERC721 = {
starkKey: transferParams.receiverPublicKey,
tokenId: transferParams.tokenId,
tokenAddress: transferParams.tokenAddress,
};
const senderVault = await this.commonAPI.createVaultForMintableERC721(
requestSenderVaultERC721
);
if (senderVault.status !== "success") {
const error: ICommonError = {
message: "Retrieve vaults ERC721 for sender has failed",
code: "",
error: requestReceiverVaultERC721
}
throw Error(JSON.stringify(error));
}
const receiverVault = await this.commonAPI.createVaultForMintableERC721(
requestReceiverVaultERC721
);
if (receiverVault.status !== "success") {
const error: ICommonError = {
message: "Retrieve vaults ERC721 for receiver has failed",
code: "",
error: JSON.stringify(requestReceiverVaultERC721)
}
throw Error(JSON.stringify(error));
}
const transferCommonParams: TransferCommonParams = {
senderVaultId: senderVault.data?.vaultId,
senderPublicKey: transferParams.senderPublicKey,
senderWalletAddress: transferParams.senderWalletAddress,
receiverVaultId: receiverVault.data?.vaultId,
receiverPublicKey: transferParams.receiverPublicKey,
assetId: senderVault.data?.assetId,
quantizedAmount: transferParams.quantizedAmount,
tokenType: TokenType.MINTABLE_ERC721,
groupRequestId: transferParams.groupRequestId,
partnerRefId: transferParams.partnerRefId,
myriaPrivateStarkKey: transferParams.myriaPrivateKey,
path: "/v1/transactions/transfer",
};
const transferResult = await this.transferTokenCommon(transferCommonParams);
return transferResult;
}
/**
* @summary Asynchronous bulk transfer for NFT Tokens (such as: ERC-721 Tokens, Marketplace NFTs)
* - Function only supports MINTABLE_ERC721 and NFTs which are minted on Myria System
* @param {TransferTokenParams} transferTokenParams Data regarding sender and receivers relevant for the transfer.
* @description After bulk transfer was triggered, we can query the status of the batch with the following functions:
* + getTransactionsByGroupRequestIDAndPartnerRefID(groupRequestID: string, partnerRefID: string)
* + getTransactionsByPartnerRefID(partnerRefID: string)
* @returns {BulkTransferTokenResponse} Transaction data list which have been captured and validated
* - Response structure consist of 3 group of transactions failed[] / success[] / validationFailed[]
* - All transactions in failed[], relate to failures due to not enough funds or other internal server errors. These transactions cannot be processed.
* - All transactions in validationFailed[], relate to failures due to validation such as L2's signature. These can be retried with amended data.
* - All transactions in success[], indicate that they have been recorded and will be processed by the system.
* @throws {string} Exception: Sender wallet address is required
* @throws {string} Exception: Bulk transfer should include at least one transfer
* @throws {string} Exception: Receiver wallet address is required
* @throws {string} Exception: Only MINTABLE_ERC-721 tokens are valid for this type of bulk transfer
* @throws {string} Exception: Token address is required
* @throws {string} Error code 409 - Request-ID/Group-Request-ID is already exists
* @throws {string} Http error code 400 - User wallet (sender or receiver) is not registered
* @throws {string} Http error code 400 - Vault ID does not have enough funds
* @throws {string} Http error code 400 - Signature is invalid
* @example <caption>Sample code on Testnet (Staging) env</caption>
*
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const YOUR_NFT_CONTRACT_ADDRESS = "0xA06116D9....";
const RECEIVER_WALLET_ADDRESS = '0xd0D8A467E....'; // Your receiver/users wallet address
const SENDER_WALLET_ADDRESS = '0x724f337bF0F....'; // Must be the owner of tokens, sender wallet address
const moduleFactory = ModuleFactory.getInstance(mClient);
const transactionManager = moduleFactory.getTransactionManager();
const transferredItems: ItemSignableTransferParams[] = [
{
quantizedAmount: 1, // Should be 1 as always
receiverWalletAddress: RECEIVER_WALLET_ADDRESS,
tokenType: TokenType.MINTABLE_ERC721,
tokenData: {
tokenAddress: YOUR_NFT_CONTRACT_ADDRESS,
tokenId: '1' // Your minted token ID
},
},
{
quantizedAmount: 1,
receiverWalletAddress: RECEIVER_WALLET_ADDRESS,
tokenType: TokenType.MINTABLE_ERC721,
tokenData: {
tokenAddress: YOUR_NFT_CONTRACT_ADDRESS,
tokenId: '2' // Your minted token ID
},
},
{
quantizedAmount: 1,
receiverWalletAddress: RECEIVER_WALLET_ADDRESS,
tokenType: TokenType.MINTABLE_ERC721,
tokenData: {
tokenAddress: YOUR_NFT_CONTRACT_ADDRESS,
tokenId: '3' // Your minted token ID
},
},
];
const transferTokenParams: TransferTokenParams = {
senderWalletAddress: SENDER_WALLET_ADDRESS,
groupRequestId: '7257d29c-c96a-4302-8eaf-368a0d62b977', // Can use random UUID to generate groupRequestID
requestId: '7257d29c-c96a-4302-8eaf-368a0d62b977', // Can use random UUID to generate requestID
partnerRefId: 'Project-ID', // Project-ID on Myria System
description: 'Test-Test Bulk Transfer',
items: transferredItems,
};
const transferResult = await transactionManager.bulkTransferNfts(
transferTokenParams,
);
*
*/
public async bulkTransferNfts(
transferTokenParams: TransferTokenParams
): Promise<APIResponseType<BulkTransferTokenResponse>> {
if (!transferTokenParams.senderWalletAddress) {
throw new Error("Sender wallet address is required");
}
if (!transferTokenParams.items || transferTokenParams.items.length === 0) {
throw new Error("Bulk transfer should include at least one transfer.");
}
const transferredItems: ItemSignableTransferParams[] = [];
transferTokenParams.items.forEach((item) => {
if (!item.receiverWalletAddress) {
throw new Error("Receiver wallet address is required");
}
if (item.tokenType !== (TokenType.ERC721 && TokenType.MINTABLE_ERC721)) {
throw new Error(
"Only MINTABLE_ERC-721 tokens are valid for this type of bulk transfer"
);
}
if (!item.tokenData?.tokenAddress) {
throw new Error("Token address is required");
}
if (!item.tokenData?.tokenId) {
throw new Error("Token ID is required for transfer ERC-721 tokens ");
}
const transferredItem: ItemSignableTransferParams = {
quantizedAmount: item.quantizedAmount,
receiverWalletAddress: item.receiverWalletAddress,
tokenType: item.tokenType,
tokenData: item.tokenData,
};
transferredItems.push(transferredItem);
});
// Call signable API endpoint
const signableBulkTransferredParams: SignableBulkTransferParams = {
senderWalletAddress: transferTokenParams.senderWalletAddress,
items: transferredItems,
};
const fullPayloadTransferData =
await this.transactionAPI.signableBulkTransfer(
signableBulkTransferredParams
);
if (!fullPayloadTransferData) {
throw new Error("Transfer payload data is required");
}
// Create generateFullPayloadForBulkTransfer list of signature
const fullPayloadTransferred =
await this.commonModule.generateFullPayloadForBulkTransfer(
transferTokenParams.senderWalletAddress,
TokenType.MINTABLE_ERC721,
fullPayloadTransferData,
transferTokenParams.myriaPrivateKey
);
console.log("Full transfer payload -> ", fullPayloadTransferred);
// Trigger transfer
const bulkTransferRequestApi: BulkTransferTokenRequestAPIParams = {
senderWalletAddress: transferTokenParams.senderWalletAddress,
requestId: transferTokenParams.requestId,
groupRequestId: transferTokenParams.groupRequestId,
partnerRefId: transferTokenParams.partnerRefId,
description: transferTokenParams.description,
items: fullPayloadTransferred,
isWaitingForValidation: transferTokenParams.isWaitingForValidation
};
const bulkTransferResult =
await this.assetMarketplaceAPI.bulkTransferERC721Token(
bulkTransferRequestApi
);
console.log(
"Bulk Transfer Response Nft API -> ",
JSON.stringify(bulkTransferResult)
);
return bulkTransferResult;
}
public async bulkTransferNftsV2(
transferTokenParams: TransferTokenParams
): Promise<APIResponseType<BulkTransferTokenResponse>> {
if (!transferTokenParams.senderWalletAddress) {
throw new Error("Sender wallet address is required");
}
if (!transferTokenParams.items || transferTokenParams.items.length === 0) {
throw new Error("Bulk transfer should include at least one transfer.");
}
const transferredItems: ItemSignableTransferParams[] = [];
transferTokenParams.items.forEach((item) => {
if (!item.receiverWalletAddress) {
throw new Error("Receiver wallet address is required");
}
if (item.tokenType !== (TokenType.ERC721 && TokenType.MINTABLE_ERC721)) {
throw new Error(
"Only MINTABLE_ERC-721 tokens are valid for this type of bulk transfer"
);
}
if (!item.tokenData?.tokenAddress) {
throw new Error("Token address is required");
}
if (!item.tokenData?.tokenId) {
throw new Error("Token ID is required for transfer ERC-721 tokens ");
}
const transferredItem: ItemSignableTransferParams = {
quantizedAmount: item.quantizedAmount,
receiverWalletAddress: item.receiverWalletAddress,
tokenType: item.tokenType,
tokenData: item.tokenData,
};
transferredItems.push(transferredItem);
});
// Call signable API endpoint
const signableBulkTransferredParams: SignableBulkTransferParams = {
senderWalletAddress: transferTokenParams.senderWalletAddress,
items: transferredItems,
};
const fullPayloadTransferData =
await this.transactionAPI.signableBulkTransfer(
signableBulkTransferredParams
);
if (!fullPayloadTransferData) {
throw new Error("Transfer payload data is required");
}
// Create generateFullPayloadForBulkTransfer list of signature
const fullPayloadTransferred =
await this.commonModule.generateFullPayloadForBulkTransfer(
transferTokenParams.senderWalletAddress,
TokenType.MINTABLE_ERC721,
fullPayloadTransferData,
transferTokenParams.myriaPrivateKey
);
console.log("Full transfer payload -> ", fullPayloadTransferred);
// Trigger transfer
const bulkTransferRequestApi: BulkTransferTokenRequestAPIParams = {
senderWalletAddress: transferTokenParams.senderWalletAddress,
requestId: transferTokenParams.requestId,
groupRequestId: transferTokenParams.groupRequestId,
partnerRefId: transferTokenParams.partnerRefId,
description: transferTokenParams.description,
items: fullPayloadTransferred,
isWaitingForValidation: transferTokenParams.isWaitingForValidation
};
const bulkTransferResult =
await this.assetMarketplaceAPI.bulkTransferNfts(
bulkTransferRequestApi
);
console.log(
"Bulk Transfer Response Nft API -> ",
JSON.stringify(bulkTransferResult)
);
return bulkTransferResult;
}
public async getSignableDetailsTransferERC20(
transferTokenParams: TransferTokenParams
): Promise<BulkTransferTokenRequestAPIParams> {
if (!transferTokenParams.senderWalletAddress) {
throw new Error("Sender wallet address is required");
}
if (!transferTokenParams.items || transferTokenParams.items.length === 0) {
throw new Error("Bulk transfer should include at least one transfer");
}
const transferredItems: ItemSignableTransferParams[] = [];
transferTokenParams.items.forEach((item) => {
if (!item.receiverWalletAddress) {
throw new Error("Receiver wallet address is required");
}
if (
item.tokenType !== TokenType.ERC20 &&
item.tokenType !== TokenType.MINTABLE_ERC20
) {
throw new Error(
"Only ERC20 Tokens are valid for this type of bulk transfer"
);
}
if (!item.tokenData?.tokenAddress) {
throw new Error("Token address is required");
}
const transferredItem: ItemSignableTransferParams = {
quantizedAmount: item.quantizedAmount,
receiverWalletAddress: item.receiverWalletAddress,
tokenType: item.tokenType,
tokenData: item.tokenData,
};
transferredItems.push(transferredItem);
});
// Call signable API endpoint
const signableBulkTransferredParams: SignableBulkTransferParams = {
senderWalletAddress: transferTokenParams.senderWalletAddress,
items: transferredItems,
};
console.time("Signable_Transfer_ERC20");
const fullPayloadTransferData =
await this.transactionAPI.signableBulkTransfer(
signableBulkTransferredParams
);
console.timeEnd("Signable_Transfer_ERC20");
// console.log("Full signable transfer payload", fullPayloadTransferData);
if (!fullPayloadTransferData) {
throw new Error("Transfer payload data is required");
}
// Create generateFullPayloadForBulkTransfer list of signature
console.time("Generate_FullPayloadTransfer_ERC20");
const fullPayloadTransferred =
await this.commonModule.generateFullPayloadForBulkTransfer(
transferTokenParams.senderWalletAddress,
TokenType.ERC20,
fullPayloadTransferData,
transferTokenParams.myriaPrivateKey
);
console.timeEnd("Generate_FullPayloadTransfer_ERC20");
// Trigger transfer
const payloadTransferDetails: BulkTransferTokenRequestAPIParams = {
senderWalletAddress: transferTokenParams.senderWalletAddress,
requestId: transferTokenParams.requestId,
groupRequestId: transferTokenParams.groupRequestId,
partnerRefId: transferTokenParams.partnerRefId,
description: transferTokenParams.description,
items: fullPayloadTransferred,
isWaitingForValidation: transferTokenParams.isWaitingForValidation,
};
return payloadTransferDetails;
}
/**
* @summary Async bulk transfer for ERC-20 Tokens (such as: Myria Tokens, ...)
* - Function only supports ERC20 and Myria Tokens (ERC20) which are registered in Myria System already (i.e. via a deposit).
* @param {TransferTokenParams} transferTokenParams Data regarding sender and receivers relevant for the transfer.
* @description After bulk transfer was triggered, we can query the status of the batch with the following functions:
* + getTransactionsByGroupRequestIDAndPartnerRefID(groupRequestID: string, partnerRefID: string)
* + getTransactionsByPartnerRefID(partnerRefID: string)
* @example <caption>Sample code on Testnet (Staging) env</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const MYR_TOKEN_ADDRESS_EXAMPLE = "0xA06116D9...."; // ERC-20 token address - and make sure it is registered in Myria System already
const RECEIVER_WALLET_ADDRESS = '0xd0D8A467E....'; // Your receiver/users wallet address
const SENDER_WALLET_ADDRESS = '0x724f337bF0F....'; // Must be the owner of tokens, sender wallet address
const moduleFactory = ModuleFactory.getInstance(mClient);
const transactionManager = moduleFactory.getTransactionManager();
const transferredItems: ItemSignableTransferParams[] = [
{
quantizedAmount: String(convertAmountToQuantizedAmount(1)),
receiverWalletAddress: RECEIVER_WALLET_ADDRESS,
tokenType: TokenType.ERC20,
tokenData: {
tokenAddress: MYR_TOKEN_ADDRESS_EXAMPLE,
},
},
{
quantizedAmount: String(convertAmountToQuantizedAmount(2)),
receiverWalletAddress: RECEIVER_WALLET_ADDRESS,
tokenType: TokenType.ERC20,
tokenData: {
tokenAddress: MYR_TOKEN_ADDRESS_EXAMPLE,
},
},
{
quantizedAmount: String(convertAmountToQuantizedAmount(3)),
receiverWalletAddress: RECEIVER_WALLET_ADDRESS,
tokenType: TokenType.ERC20,
tokenData: {
tokenAddress: MYR_TOKEN_ADDRESS_EXAMPLE,
},
},
];
const transferTokenParams: TransferTokenParams = {
senderWalletAddress: SENDER_WALLET_ADDRESS,
groupRequestId: '7257d29c-c96a-4302-8eaf-368a0d62b977', // Can use random UUID to generate groupRequestID
requestId: '7257d29c-c96a-4302-8eaf-368a0d62b977', // Can use random UUID to generate requestID
partnerRefId: 'Project-ID', // Partner project ID
description: 'Test-Test Bulk Transfer',
items: transferredItems,
};
const transferResult = await transactionManager.bulkTransferERC20Token(
transferTokenParams,
);
* @returns {BulkTransferTokenResponse} Transaction data list which have been captured and validated
* - Response structure consist of 3 group of transactions: failed[] / success[] / validationFailed[]
* - All transactions in failed[], relate to failures due to not enough funds or other internal server errors. These transactions cannot be processed.
* - All transactions in validationFailed[], relate to failures due to validation such as L2's signature. These can be retried with amended data.
* - All transactions in success[], indicate that they have been recorded and will be processed by the system.
* @throws {string} Exception: Sender wallet address is required
* @throws {string} Exception: Bulk transfer should include at least one transfer
* @throws {string} Exception: Receiver wallet address is required
* @throws {string} Exception: Only ERC20 Tokens are valid for this type of bulk transfer
* @throws {string} Exception: Token address is required
* @throws {string} Http error code 409 - Request-ID/Group-Request-ID already exists
* @throws {string} Http error code 400 - User wallet (sender or receiver) is not registered
* @throws {string} Http error code 400 - Vault ID does not have enough funds
* @throws {string} Http error code 400 - Signature is invalid
*/
public async bulkTransferERC20Token(
transferTokenParams: TransferTokenParams
): Promise<APIResponseType<BulkTransferTokenResponse>> {
if (!transferTokenParams.senderWalletAddress) {
throw new Error("Sender wallet address is required");
}
if (!transferTokenParams.items || transferTokenParams.items.length === 0) {
throw new Error("Bulk transfer should include at least one transfer");
}
const transferredItems: ItemSignableTransferParams[] = [];
transferTokenParams.items.forEach((item) => {
if (!item.receiverWalletAddress) {
throw new Error("Receiver wallet address is required");
}
if (
item.tokenType !== TokenType.ERC20 &&
item.tokenType !== TokenType.MINTABLE_ERC20
) {
throw new Error(
"Only ERC20 Tokens are valid for this type of bulk transfer"
);
}
if (!item.tokenData?.tokenAddress) {
throw new Error("Token address is required");
}
const transferredItem: ItemSignableTransferParams = {
quantizedAmount: item.quantizedAmount,
receiverWalletAddress: item.receiverWalletAddress,
tokenType: item.tokenType,
tokenData: item.tokenData,
};
transferredItems.push(transferredItem);
});
// Call signable API endpoint
const signableBulkTransferredParams: SignableBulkTransferParams = {
senderWalletAddress: transferTokenParams.senderWalletAddress,
items: transferredItems,
};
console.time("Signable_Transfer_ERC20");
const fullPayloadTransferData =
await this.transactionAPI.signableBulkTransfer(
signableBulkTransferredParams
);
console.timeEnd("Signable_Transfer_ERC20");
// console.log("Full signable transfer payload", fullPayloadTransferData);
if (!fullPayloadTransferData) {
throw new Error("Transfer payload data is required");
}
// Create generateFullPayloadForBulkTransfer list of signature
console.time("Generate_FullPayloadTransfer_ERC20");
const fullPayloadTransferred =
await this.commonModule.generateFullPayloadForBulkTransfer(
transferTokenParams.senderWalletAddress,
TokenType.ERC20,
fullPayloadTransferData,
transferTokenParams.myriaPrivateKey
);
console.timeEnd("Generate_FullPayloadTransfer_ERC20");
// Trigger transfer
const bulkTransferRequestApi: BulkTransferTokenRequestAPIParams = {
senderWalletAddress: transferTokenParams.senderWalletAddress,
requestId: transferTokenParams.requestId,
groupRequestId: transferTokenParams.groupRequestId,
partnerRefId: transferTokenParams.partnerRefId,
description: transferTokenParams.description,
items: fullPayloadTransferred,
isWaitingForValidation: transferTokenParams.isWaitingForValidation,
};
console.time("BulkTransfer_ERC20");
const bulkTransferResult = await this.transactionAPI.bulkTransferERC20Token(
bulkTransferRequestApi
);
console.timeEnd("BulkTransfer_ERC20");
console.log(
"Bulk Transfer Response ERC-20 API -> ",
JSON.stringify(bulkTransferResult)
);
return bulkTransferResult;
}
// /**
// * @description Query the list of the transaction based on request ID
// * @param {string} requestID The unique request ID of the transaction
// * @throws {string} Exception: RequestID is required
// * @returns {TransactionData[]} Transaction data list (such as transactionID, transactionStatus...)
// * @example <caption>Sample code on Testnet (Staging) env</caption>
// const mClient: IMyriaClient = {
// networkId: Network.SEPOLIA,
// provider: web3Instance.currentProvider,
// web3: web3Instance,
// env: EnvTypes.STAGING,
// };
// const requestID = "923a78a2-49a2-4eb9-8163-20dddd524a8c";
// const moduleFactory = ModuleFactory.getInstance(mClient);
// const transactionManager = moduleFactory.getTransactionManager();
// const result = await transactionManager.getTransactionsByRequestID(requestID);
// console.log('Transaction result -> ', result);
// */
public async getTransactionsByRequestID(
requestID: string
): Promise<APIResponseType<TransactionData[]>> {
if (!requestID) {
throw new Error("RequestID is required");
}
return this.transactionAPI.getTransactionsByRequestID(requestID);
}
/**
* @description Query a list of transactions based on group request ID and Partner Ref ID
* @param {string} groupReqID The unique group request ID of the transaction batch
* @param {string} partnerRefID The unique partner reference ID as Project ID
* @param {TransactionPagingDetails=} transactionPaging The pagination params (which included starkKey, limit, createdAt, transactionCategory for query next page)
* @throws {string} Exception: Partner Reference ID is required
* @throws {string} Exception: Group Request ID is required
* @returns {TransactionData[]} List of transactions data which indicate the status of batch, transaction results, transaction details information
* (such as transactionID, transactionStatus...)
* @example <caption>Sample code on Testnet (Staging) env</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const groupRequestID = "e2fb1ef6-680b-4515-9ca6-0c46bc026ecd";
const partnerRefId = "10"; // Unique ItemSignableTransferParamsProject ID in Myria System
const moduleFactory = ModuleFactory.getInstance(mClient);
const transactionManager = moduleFactory.getTransactionManager();
const result = await transactionManager.getTransactionsByGroupRequestIDAndPartnerRefID(
groupRequestID,
partnerRefId
);
console.log('Transaction result -> ', result);
*/
public async getTransactionsByGroupRequestIDAndPartnerRefID(
groupReqID: string,
partnerRefID: string,
transactionPaging?: TransactionPagingDetails
): Promise<APIResponseType<TransactionPagingData>> {
if (!partnerRefID) {
throw new Error("Partner Reference ID is required");
}
if (!groupReqID) {
throw new Error("Group Request ID is required");
}
return this.transactionAPI.getTransactionsByGroupReqIDAndPartnerRefID(
groupReqID,
partnerRefID,
transactionPaging
);
}
/**
* @description Query a list of transactions based on partner reference ID (which should be project ID)
* @param partnerRefID The unique partner reference ID (Project ID)
* @throws {string} Exception: Partner reference ID is required
* @returns {TransactionData[]} List of transactions data which indicate the status of batch, transaction results, transaction details information
* (such as transactionID, transactionStatus...)
* @example <caption>Sample code on Testnet (Staging) env</caption>
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const partnerRefId = "Project-ID"; // Unique ID of the project on Myria System
const moduleFactory = ModuleFactory.getInstance(mClient);
const transactionManager = moduleFactory.getTransactionManager();
const result = await transactionManager.getTransactionsByPartnerRefID(
partnerRefId
);
console.log('Transaction result -> ', result);
*/
public async getTransactionsByPartnerRefID(
partnerRefID: string
): Promise<APIResponseType<TransactionData[]>> {
if (!partnerRefID) {
throw new Error("Partner reference ID");
}
return this.transactionAPI.getTransactionsByPartnerRefID(partnerRefID);
}
public async signableBulkTransferDetail(
params: SignableBulkTransferParams
): Promise<SignableBulkTransferResponse> {
if (!params) {
throw new Error("Transfer params is required");
}
if (!params?.senderWalletAddress) {
throw new Error("Sender wallet address is required");
}
if (
params.senderWalletAddress &&
!Web3.utils.isAddress(params.senderWalletAddress)
) {
throw new Error("Sender Wallet Address is Invalid");
}
if (params?.items.length === 0) {
throw new Error("Transfer params items is required");
} else {
params.items.forEach((paramItemValue: ItemSignableTransferParams) => {
if (!paramItemValue.receiverWalletAddress) {
throw new Error("Receive wallet address is required");
}
if (
paramItemValue.receiverWalletAddress &&
!Web3.utils.isAddress(paramItemValue.receiverWalletAddress)
) {
throw new Error("Receive wallet address is Invalid");
}
if (!paramItemValue.tokenType) {
throw new Error("Token type is required");
}
if (!paramItemValue.quantizedAmount) {
throw new Error("Quantized amount is required");
}
if (paramItemValue.tokenType) {
switch (paramItemValue.tokenType) {
case TokenType.MINTABLE_ERC20:
case TokenType.ERC20:
if (!paramItemValue.tokenData?.tokenAddress) {
throw new Error("Token Address is required");
}
break;
case TokenType.MINTABLE_ERC721:
case TokenType.ERC721:
if (
!paramItemValue.tokenData?.tokenAddress ||
!paramItemValue.tokenData?.tokenId
) {
throw new Error("Token Address and Token Id are required");
}
break;
default:
break;
}
}
});
}
try {
const result = await this.transactionAPI.signableBulkTransfer(params);
return result;
} catch (err) {
throw new Error(`Bulk Transfer failed: ${err}`);
}
}
/**
* @summary Single Transfer ERC-20 Token
* @param {TransferERC20Params} transferParams Transfer ERC-20 Tokens params (include information for Sender/Receiver)
* @description After transfer was triggered, we can query the status of the transaction with the following functions:
* + getTransactionDetails(transactionId: number) {return TransactionData}
* + getTransactionsByPartnerRefID(partnerRefID: string) {return []TransactionData}
* @returns {TransferResponse} Transactions data which indicate the status of batch, transaction results, transaction details information
* (such as transactionID, transactionStatus...)
* @throws {string} Exception: Sender vault is not found
* @throws {string} Exception: Receiver vault is not found
* @throws {string} Http Status 400 - Sender/Receiver vaults do not exist
* @throws {string} Http Status 400 - Signature is invalid
* @throws {string} Http Status 400 - Vault IDs does not have enough funds
*/
public async transferERC20Token(
transferParams: TransferERC20Params
): Promise<TransferResponse> {
const requestSenderVaultERC20: VaultForERC20 = {
starkKey: transferParams.senderPublicKey,
tokenAddress: transferParams.tokenAddress,
quantum: QUANTUM_ERC20,
};
const requestReceiverVaultERC20: VaultForERC20 = {
starkKey: transferParams.receiverPublicKey,
tokenAddress: transferParams.tokenAddress,
quantum: QUANTUM_ERC20,
};
const senderVault = await this.commonAPI.retrieveERC20Vault(
requestSenderVaultERC20
);
if (senderVault.status !== "success") {
throw Error(
'"Request sender vault failed => ' +
JSON.stringify(requestSenderVaultERC20)
);
}
const receiverVault = await this.commonAPI.retrieveERC20Vault(
requestReceiverVaultERC20
);
if (receiverVault.status !== "success") {
throw Error(
'"Request receiver vault failed => ' + JSON.stringify(receiverVault)
);
}
const transferCommonParams: TransferCommonParams = {
senderVaultId: senderVault.data?.vaultId,
senderPublicKey: transferParams.senderPublicKey,
senderWalletAddress: transferParams.senderWalletAddress,
receiverVaultId: receiverVault.data?.vaultId,
receiverPublicKey: transferParams.receiverPublicKey,
assetId: senderVault.data?.assetId,
quantizedAmount: transferParams.quantizedAmount,
tokenType: TokenType.ERC20,
groupRequestId: transferParams.groupRequestId,
partnerRefId: transferParams.partnerRefId,
myriaPrivateStarkKey: transferParams.myriaPrivateKey,
path: "/v1/transactions/transfer",
};
const transferResult = await this.transferTokenCommon(transferCommonParams);
return transferResult;
}
/**
* @summary Single Transfer ERC-20 Token
* @param {TransferERC20Params} transferParams Transfer ERC-20 Tokens params (include information for Sender/Receiver)
* @description After transfer was triggered, we can query the status of the transaction with the following functions:
* + getTransactionDetails(transactionId: number) {return TransactionData}
* + getTransactionsByPartnerRefID(partnerRefID: string) {return []TransactionData}
* @returns {TransferResponse} Transactions data which indicate the status of batch, transaction results, transaction details information
* (such as transactionID, transactionStatus...)
* @throws {string} Exception: Sender vault is not found
* @throws {string} Exception: Receiver vault is not found
* @throws {string} Http Status 400 - Sender/Receiver vaults do not exist
* @throws {string} Http Status 400 - Signature is invalid
* @throws {string} Http Status 400 - Vault IDs does not have enough funds
*/
public async transferETHToken(
transferParams: TransferETHParams
): Promise<TransferResponse> {
const requestSenderVaultERC20: VaultForETH = {
starkKey: transferParams.senderPublicKey,
};
const requestReceiverVaultERC20: VaultForETH = {
starkKey: transferParams.receiverPublicKey,
};
const senderVault = await this.commonAPI.retrieveETHVault(
requestSenderVaultERC20
);
if (senderVault.status !== "success") {
throw Error(
'"Request sender vault failed => ' +
JSON.stringify(requestSenderVaultERC20)
);
}
const receiverVault = await this.commonAPI.retrieveETHVault(
requestReceiverVaultERC20
);
if (receiverVault.status !== "success") {
throw Error(
'"Request receiver vault failed => ' + JSON.stringify(receiverVault)
);
}
const transferCommonParams: TransferCommonParams = {
senderVaultId: senderVault.data?.vaultId,
senderPublicKey: transferParams.senderPublicKey,
senderWalletAddress: transferParams.senderWalletAddress,
receiverVaultId: receiverVault.data?.vaultId,
receiverPublicKey: transferParams.receiverPublicKey,
assetId: senderVault.data?.assetId,
quantizedAmount: transferParams.quantizedAmount,
tokenType: TokenType.ETH,
groupRequestId: transferParams.groupRequestId,
partnerRefId: transferParams.partnerRefId,
myriaPrivateStarkKey: transferParams.myriaPrivateKey,
path: '/v1/transactions/transfer'
};
const transferResult = await this.transferTokenCommon(transferCommonParams);
return transferResult;
}
public async transferTokenCommon(
transferParams: TransferCommonParams
): Promise<TransferResponse> {
if (!transferParams.senderPublicKey) {
throw new Error("Sender public key is required.");
}
if (!transferParams.senderVaultId) {
throw new Error("Sender vault Id is required.");
}
if (!transferParams.senderWalletAddress) {
throw new Error("Sender wallet address is required!");
}
if (!transferParams.receiverPublicKey) {
throw new Error("Receiver public key is required!");
}
if (!transferParams.receiverVaultId) {
throw new Error("Receiver vault Id is required!");
}
if (!transferParams.assetId) {
throw new Error("Asset id is required!");
}
if (!transferParams.quantizedAmount) {
throw new Error("Amount is required!");
}
// if (!transferParams.myriaPrivateStarkKey) {
// throw new Error('Myria private stark key is required!');
// }
const currentTimestamp = new Date();
// const nonce = transferParams.nonce || currentTimestamp.getDate() * Math.floor(Math.random() * 10);
let nonce: number;
try {
const result = await this.commonAPI.getNonceByStarkKey(
transferParams.senderPublicKey
);
if (result.status === "success") {
nonce = result.data;
} else {
throw new Error("Getting nonce value failed!");
}
} catch (err) {
throw new Error(`Getting nonce value failed: ${err}`);
}
const expirationTimestamp =
transferParams.expirationTimestamp ||
Math.floor(
currentTimestamp.setFullYear(currentTimestamp.getFullYear() + 20) /
3600 /
1000
);
if (!transferParams.nonce) {
transferParams = {
...transferParams,
nonce,
};
}
if (!transferParams.expirationTimestamp) {
transferParams = {
...transferParams,
expirationTimestamp,
};
}
const starkSignature =
await this.commonModule.generateStarkSignatureForTransfer(transferParams);
if (!starkSignature) {
throw new Error("Signing message failed!");
}
const currentTimestampSignatureHeader = Math.floor(Date.now() / 1000);
let generateSignatureHeader = undefined;
if (transferParams.myriaPrivateStarkKey) {
generateSignatureHeader =
await this.commonModule.generateHeaderSignatureWithSecretKey(
transferParams.myriaPrivateStarkKey || "",
transferParams.senderPublicKey,
currentTimestampSignatureHeader,
transferParams.path || ""
);
}
const transferRequest: TransferAPIInput = {
senderVaultId: transferParams.senderVaultId,
senderPublicKey: transferParams.senderPublicKey,
receiverVaultId: transferParams.receiverVaultId,
receiverPublicKey: transferParams.receiverPublicKey,
token: transferParams.assetId,
quantizedAmount: transferParams.quantizedAmount,
nonce: Number(transferParams.nonce),
expirationTimestamp: Number(transferParams.expirationTimestamp),
signature: starkSignature,
signatureHeader: generateSignatureHeader,
};
let transferResult: TransferResponse;
try {
let transferResponse = undefined;
if (
transferParams.tokenType === TokenType.ERC20 ||
transferParams.tokenType === TokenType.MINTABLE_ERC20 ||
transferParams.tokenType === TokenType.ETH
) {
transferResponse = await this.transactionAPI.transferToken(
transferRequest
);
} else if (
transferParams.tokenType === TokenType.ERC721 ||
transferParams.tokenType === TokenType.MINTABLE_ERC721
) {
transferResponse = await this.assetMarketplaceAPI.transferERC721Token(
transferRequest
);
}
if (!transferResponse) {
throw Error(
"Please check token type, the transfer response is undefined"
);
}
if (transferResponse?.status === "success") {
transferResult = transferResponse?.data;
} else {
const error: ICommonError = {
message: "Transfer failed with server error",
code: "",
error: undefined
}
throw new Error(JSON.stringify(error));
}
} catch (err) {
const error: ICommonError = {
message: "Transfer failed with server error",
code: "",
error: err
}
throw new Error(JSON.stringify(error));
}
return transferResult;
}
public async updateTransactionComplete(
payload: TransactionCompleteParams
): Promise<APIResponseType<TransactionCompleteResponse>> {
if (!payload.starkKey) {
throw new Error("Stark key is required");
}
if (!payload.transactionHash) {
throw new Error("Transaction hash is required");
}
if (!payload.transactionId) {
throw new Error("Transaction id is required");
}
let response: APIResponseType<TransactionCompleteResponse>;
try {
response = await this.transactionAPI.updateTransactionComplete(payload);
} catch (err) {
throw new Error(`Error api called ${err}`);
}
return response;
}
/**
* @summary Asynchronous burn for NFT Tokens (such as: ERC-721 Tokens, Marketplace NFTs)
* - Function only supports MINTABLE_ERC721 and NFTs which are minted on Myria System
* @param {BurnTokenParams} burnTokenParams Data regarding sender and receivers relevant for the burn transfer.
* @description After burn transfer was triggered, we can query the status of the batch with the following functions:
* + getTransactionsByGroupRequestIDAndPartnerRefID(groupRequestID: string, partnerRefID: string)
* + getTransactionsByPartnerRefID(partnerRefID: string)
* @returns {BurnTokenResponse} Transaction data list which have been captured and validated
* - Response structure consist of 3 group of transactions failed[] / success[] / validationFailed[]
* - All transactions in failed[], relate to failures due to not enough funds or other internal server errors. These transactions cannot be processed.
* - All transactions in validationFailed[], relate to failures due to validation such as L2's signature. These can be retried with amended data.
* - All transactions in success[], indicate that they have been recorded and will be processed by the system.
* @throws {string} Exception: Sender wallet address is required
* @throws {string} Exception: Burn transfer should include at least one transfer
* @throws {string} Exception: Only MINTABLE_ERC-721 tokens are valid for this type of bulk transfer
* @throws {string} Exception: Token address is required
* @throws {string} Error code 409 - Request-ID/Group-Request-ID is already exists
* @throws {string} Http error code 400 - User wallet (sender or receiver) is not registered
* @throws {string} Http error code 400 - Vault ID does not have enough funds
* @throws {string} Http error code 400 - Signature is invalid
* @example <caption>Sample code on Testnet (Staging) env</caption>
*
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const YOUR_NFT_CONTRACT_ADDRESS = "0xA06116D9....";
const SENDER_WALLET_ADDRESS = '0x724f337bF0F....'; // Must be the owner of tokens, sender wallet address
const moduleFactory = ModuleFactory.getInstance(mClient);
const transactionManager = moduleFactory.getTransactionManager();
const burnTransferredItems: ItemSignableBurnTransferParams[] = [
{
quantizedAmount: 1, // Should be 1 as always
tokenType: TokenType.MINTABLE_ERC721,
tokenData: {
tokenAddress: YOUR_NFT_CONTRACT_ADDRESS,
tokenId: '1' // Your minted token ID,
quantum: '1'
},
},
{
quantizedAmount: 1,
tokenType: TokenType.MINTABLE_ERC721,
tokenData: {
tokenAddress: YOUR_NFT_CONTRACT_ADDRESS,
tokenId: '2' // Your minted token ID,
},
},
{
quantizedAmount: 1,
tokenType: TokenType.MINTABLE_ERC721,
tokenData: {
tokenAddress: YOUR_NFT_CONTRACT_ADDRESS,
tokenId: '3' // Your minted token ID
},
},
];
const burnTransferTokenParams: BurnTokenParams = {
senderWalletAddress: SENDER_WALLET_ADDRESS,
groupRequestId: '7257d29c-c96a-4302-8eaf-368a0d62b977', // Can use random UUID to generate groupRequestID
requestId: '7257d29c-c96a-4302-8eaf-368a0d62b977', // Can use random UUID to generate requestID
partnerRefId: 'Project-ID', // Project-ID on Myria System
description: 'Test-Test Burn Transfer',
items: burnTransferredItems,
};
const burnTransferResult = await transactionManager.burnNfts(
burnTransferTokenParams,
);
*
*/
public async burnNfts(
burnTokenParams: BurnTokenParams
): Promise<APIResponseType<BurnTokenResponse>> {
if (!burnTokenParams.senderWalletAddress) {
throw new Error("Sender wallet address is required");
}
if (!burnTokenParams.items || burnTokenParams.items.length === 0) {
throw new Error("Burn transfer should include at least one transfer.");
}
const transferredItems: ItemSignableBurnParams[] = [];
burnTokenParams.items.forEach((item) => {
if (item.tokenType !== (TokenType.ERC721 && TokenType.MINTABLE_ERC721)) {
throw new Error(
"Only MINTABLE_ERC-721 tokens are valid for this type of burn transfer"
);
}
if (!item.tokenData?.tokenAddress) {
throw new Error("Token address is required");
}
if (!item.tokenData?.tokenId) {
throw new Error("Token ID is required for transfer ERC-721 tokens ");
}
const transferredItem: ItemSignableBurnParams = {
quantizedAmount: item.quantizedAmount,
tokenType: item.tokenType,
tokenData: item.tokenData,
};
transferredItems.push(transferredItem);
});
// Call signable API endpoint
const signableBurnTransferredParams: SignableBurnTokensParams = {
senderWalletAddress: burnTokenParams.senderWalletAddress,
items: transferredItems,
};
const fullPayloadBurnTransferData =
await this.transactionAPI.signableBurnTokens(
signableBurnTransferredParams
);
if (!fullPayloadBurnTransferData) {
throw new Error("Burn Transfer payload data is required");
}
// Create generateFullPayloadForBurnTransfer list of signature
const fullPayloadBurnTransferred =
await this.commonModule.generateFullPayloadForBulkTransfer(
burnTokenParams.senderWalletAddress,
TokenType.MINTABLE_ERC721,
fullPayloadBurnTransferData,
burnTokenParams.myriaPrivateKey
);
console.log("Full transfer payload -> ", fullPayloadBurnTransferred);
// Trigger transfer
const burnRequestApi: BurnTokensRequestAPIParams = {
requestId: burnTokenParams.requestId,
groupRequestId: burnTokenParams.groupRequestId,
partnerRefId: burnTokenParams.partnerRefId,
description: burnTokenParams.description,
isWaitingForValidation: burnTokenParams.isWaitingForValidation,
items: fullPayloadBurnTransferred,
};
const burnResult = await this.assetMarketplaceAPI.burnNfts(burnRequestApi);
console.log(
"Burn Transfer Response Nft API -> ",
JSON.stringify(burnResult)
);
return burnResult;
}
/**
* @summary Asynchronous burn for ERC-20 Tokens or Ethers Tokens (such as: ERC-20, Myria Tokens, Eth)
* - Function only supports ERC-20 standard tokens and Eth on Myria System
* @param {BurnTokenParams} burnTransferTokenParams Data regarding sender and receivers relevant for the burn.
* @description After burn transfer was triggered, we can query the status of the batch with the following functions:
* + getTransactionsByGroupRequestIDAndPartnerRefID(groupRequestID: string, partnerRefID: string)
* + getTransactionsByPartnerRefID(partnerRefID: string)
* @returns {BurnTokenResponse} Transaction data list which have been captured and validated
* - Response structure consist of 3 group of transactions failed[] / success[] / validationFailed[]
* - All transactions in failed[], relate to failures due to not enough funds or other internal server errors. These transactions cannot be processed.
* - All transactions in validationFailed[], relate to failures due to validation such as L2's signature. These can be retried with amended data.
* - All transactions in success[], indicate that they have been recorded and will be processed by the system.
* @throws {string} Exception: Sender wallet address is required
* @throws {string} Exception: Burn transfer should include at least one transfer
* @throws {string} Exception: Only ERC-20 or Eth tokens are valided for this burn action
* @throws {string} Exception: Token address is required
* @throws {string} Error code 409 - Request-ID/Group-Request-ID is already exists
* @throws {string} Http error code 400 - User wallet (sender or receiver) is not registered
* @throws {string} Http error code 400 - Vault ID does not have enough funds
* @throws {string} Http error code 400 - Signature is invalid
* @example <caption>Sample code on Testnet (Staging) env</caption>
*
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const YOUR_TOKEN_CONTRACT_ADDRESS = "0xA06116D9....";
const SENDER_WALLET_ADDRESS = '0x724f337bF0F....'; // Must be the owner of tokens, sender wallet address
const moduleFactory = ModuleFactory.getInstance(mClient);
const transactionManager = moduleFactory.getTransactionManager();
const QUANTUM = 10000000000;
const burnTransferredItems: ItemSignableBurnParams[] = [
{
quantizedAmount: 1, // Should be 1 as always
tokenType: TokenType.ERC20,
tokenData: {
tokenAddress: YOUR_TOKEN_CONTRACT_ADDRESS,
quantum: QUANTUM
},
},
{
quantizedAmount: 1,
tokenType: TokenType.ERC20,
tokenData: {
tokenAddress: YOUR_TOKEN_CONTRACT_ADDRESS,
quantum: QUANTUM
},
},
{
quantizedAmount: 1,
tokenType: TokenType.ERC20,
tokenData: {
tokenAddress: YOUR_TOKEN_CONTRACT_ADDRESS,
quantum: QUANTUM
},
},
];
const burnTokensParams: BurnTokenParams = {
senderWalletAddress: SENDER_WALLET_ADDRESS,
groupRequestId: '7257d29c-c96a-4302-8eaf-368a0d62b977', // Can use random UUID to generate groupRequestID
requestId: '7257d29c-c96a-4302-8eaf-368a0d62b977', // Can use random UUID to generate requestID
partnerRefId: 'Project-ID', // Project-ID on Myria System
description: 'Test-Test Burn Transfer',
items: burnTransferredItems,
};
const burnTransferResult = await transactionManager.burnERC20Tokens(
burnTransferTokenParams,
);
*
*/
public async burnERC20Tokens(
burnTransferTokenParams: BurnTokenParams
): Promise<APIResponseType<BurnTokenResponse>> {
if (!burnTransferTokenParams.senderWalletAddress) {
throw new Error("Sender wallet address is required");
}
if (
!burnTransferTokenParams.items ||
burnTransferTokenParams.items.length === 0
) {
throw new Error("Burn transfer should include at least one transfer.");
}
const burnedItems: ItemSignableBurnParams[] = [];
burnTransferTokenParams.items.forEach((item) => {
if (
item.tokenType !== TokenType.ERC20 &&
item.tokenType !== TokenType.MINTABLE_ERC20
) {
throw new Error(
"Only ERC-20 or MINTABLE_ERC20 tokens are valided for this burn action"
);
}
if (!item.tokenData?.tokenAddress) {
throw new Error("Token address is required");
}
const transferredItem: ItemSignableBurnParams = {
quantizedAmount: item?.quantizedAmount,
tokenType: item.tokenType,
tokenData: item.tokenData,
};
burnedItems.push(transferredItem);
});
// Call signable API endpoint
const signableBurnTransferredParams: SignableBurnTokensParams = {
senderWalletAddress: burnTransferTokenParams.senderWalletAddress,
items: burnedItems,
};
const fullPayloadBurnTransferData =
await this.transactionAPI.signableBurnTokens(
signableBurnTransferredParams
);
if (!fullPayloadBurnTransferData) {
throw new Error("Burn Transfer payload data is required");
}
// Create generateFullPayloadForBurnTransfer list of signature
const fullPayloadBurnTransferred =
await this.commonModule.generateFullPayloadForBulkTransfer(
burnTransferTokenParams.senderWalletAddress,
TokenType.ERC20,
fullPayloadBurnTransferData,
burnTransferTokenParams.myriaPrivateKey
);
console.log("Full transfer payload -> ", fullPayloadBurnTransferred);
// Trigger transfer
const burnRequestApi: BurnTokensRequestAPIParams = {
requestId: burnTransferTokenParams.requestId,
groupRequestId: burnTransferTokenParams.groupRequestId,
partnerRefId: burnTransferTokenParams.partnerRefId,
description: burnTransferTokenParams.description,
isWaitingForValidation: burnTransferTokenParams.isWaitingForValidation,
items: fullPayloadBurnTransferred,
};
const burnedResult = await this.transactionAPI.burnTokens(burnRequestApi);
console.log(
"Burn Transfer Response Nft API -> ",
JSON.stringify(burnedResult)
);
return burnedResult;
}
/**
* @summary Get list of tokens supported in Myria
* @description Get details tokens list data which is supported in Myria including TokenHex, TokenQuantum...
* @returns {WhitelistTokensResponse} Whitelist tokens data
**/
public async getSupportedTokens(): Promise<WhitelistTokensResponse> {
const whitelistTokens = await this.transactionAPI.getWhitelistTokens();
return whitelistTokens;
}
}
Source