diff --git a/CHANGELOG.md b/CHANGELOG.md index 17ba7a0e..edbc3152 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # CHANGELOG +## v0.9.8 + +#### Added + +- Mnemonic Wallets can be initialized as different accounts +- Network changes emit an event, wallets subscribe to these events +- Wallet `destroy` method to clean memory + +#### Changed + +- Switch to `isomorphic-dompurify` +- History module rewritten and refactored. + ## v0.9.7 #### Added diff --git a/package.json b/package.json index 8d97df21..d528d7e0 100644 --- a/package.json +++ b/package.json @@ -81,10 +81,10 @@ "bip39": "^3.0.4", "bn.js": "5.1.1", "create-hash": "1.2.0", - "dompurify": "^2.3.1", "ethereumjs-util": "^7.0.7", "ethers": "^5.1.4", "hdkey": "2.0.1", + "isomorphic-dompurify": "^0.15.0", "moment": "^2.29.1", "rollup-plugin-commonjs": "^10.1.0", "sockette": "^2.0.6", diff --git a/scripts/walletAccountsMnemonic.ts b/scripts/walletAccountsMnemonic.ts new file mode 100644 index 00000000..677ea430 --- /dev/null +++ b/scripts/walletAccountsMnemonic.ts @@ -0,0 +1,22 @@ +import { MnemonicWallet } from '../dist'; + +const mnemonic = `state usage height lumber ski federal silly axis train sustain pizza try embark giraffe motion account loud actress blood chapter blame network blossom hat`; +// or generate new mnemonic +// const mnemonic = MnemonicWallet.generateMnemonicPhrase() + +let account0 = new MnemonicWallet(mnemonic); +let account1 = new MnemonicWallet(mnemonic, 1); +let account2 = new MnemonicWallet(mnemonic, 2); + +// Account 0 +console.log('Account 0'); +console.log('X:', account0.getAddressX()); +console.log('C:', account0.getAddressC()); +// Account 1 +console.log('Account 1'); +console.log('X:', account1.getAddressX()); +console.log('C:', account1.getAddressC()); +// Account 2 +console.log('Account 2'); +console.log('X:', account2.getAddressX()); +console.log('C:', account2.getAddressC()); diff --git a/src/Asset/Assets.ts b/src/Asset/Assets.ts index eadca8c1..a2aebd63 100644 --- a/src/Asset/Assets.ts +++ b/src/Asset/Assets.ts @@ -1,7 +1,7 @@ import { xChain } from '@/Network/network'; import { iAssetCache, iAssetDescriptionClean } from '@/Asset/types'; -import DOMPurify from 'dompurify'; +import DOMPurify from 'isomorphic-dompurify'; let assetCache: iAssetCache = {}; diff --git a/src/Asset/Erc20Token.ts b/src/Asset/Erc20Token.ts index 160347d6..794ce05f 100644 --- a/src/Asset/Erc20Token.ts +++ b/src/Asset/Erc20Token.ts @@ -4,7 +4,7 @@ import { Erc20TokenData } from '@/Asset/types'; import { NO_NETWORK } from '@/errors'; import { BN } from 'avalanche'; import { Contract } from 'web3-eth-contract'; -import DOMPurify from 'dompurify'; +import DOMPurify from 'isomorphic-dompurify'; export default class Erc20Token { contract: Contract; diff --git a/src/History/api_helpers.ts b/src/History/api_helpers.ts new file mode 100644 index 00000000..4dabcc85 --- /dev/null +++ b/src/History/api_helpers.ts @@ -0,0 +1,116 @@ +import { ITransactionData, ITransactionDataEVM } from '@/History/raw_types'; +import { explorer_api } from '@/Network/network'; +import { NO_EXPLORER_API } from '@/errors'; +import { ChainIdType } from '@/types'; + +/** + * Returns transactions FROM and TO the address given + * @param addr The address to get historic transactions for. + */ +export async function getAddressHistoryEVM(addr: string): Promise { + if (!explorer_api) { + throw NO_EXPLORER_API; + } + + let endpoint = `v2/ctransactions?address=${addr}`; + let data: ITransactionDataEVM[] = (await explorer_api.get(endpoint)).data.Transactions; + + data.sort((a, b) => { + let dateA = new Date(a.createdAt); + let dateB = new Date(b.createdAt); + + return dateB.getTime() - dateA.getTime(); + }); + + return data; +} + +export async function getAddressHistory( + addrs: string[], + limit = 20, + chainID: string, + endTime?: string +): Promise { + if (!explorer_api) { + throw NO_EXPLORER_API; + } + + const ADDR_SIZE = 1024; + let selection = addrs.slice(0, ADDR_SIZE); + let remaining = addrs.slice(ADDR_SIZE); + + let addrsRaw = selection.map((addr) => { + return addr.split('-')[1]; + }); + + let rootUrl = 'v2/transactions'; + + let req = { + address: addrsRaw, + sort: ['timestamp-desc'], + disableCount: ['1'], + chainID: [chainID], + disableGenesis: ['false'], + }; + + if (limit > 0) { + //@ts-ignore + req.limit = [limit.toString()]; + } + + if (endTime) { + //@ts-ignore + req.endTime = [endTime]; + } + + let res = await explorer_api.post(rootUrl, req); + let txs = res.data.transactions; + let next: string | undefined = res.data.next; + + if (txs === null) txs = []; + + // If we need to fetch more for this address + if (next && !limit) { + let endTime = next.split('&')[0].split('=')[1]; + let nextRes = await getAddressHistory(selection, limit, chainID, endTime); + txs.push(...nextRes); + } + + // If there are addresses left, fetch them too + // TODO: Do this in parallel, not recursive + if (remaining.length > 0) { + let nextRes = await getAddressHistory(remaining, limit, chainID); + txs.push(...nextRes); + } + + return txs; +} + +/** + * Returns the ortelius data from the given tx id. + * @param txID + */ +export async function getTx(txID: string): Promise { + if (!explorer_api) { + throw NO_EXPLORER_API; + } + + let url = `v2/transactions/${txID}`; + let res = await explorer_api.get(url); + return res.data; +} + +/** + * Returns ortelius data for a transaction hash on C chain EVM, + * @param txHash + */ +export async function getTxEvm(txHash: string): Promise { + if (!explorer_api) { + throw NO_EXPLORER_API; + } + + let endpoint = `v2/ctransactions?hash=${txHash}`; + let data: ITransactionDataEVM = (await explorer_api.get(endpoint)).data.Transactions[0]; + + return data; +} diff --git a/src/History/base_tx_parser.ts b/src/History/base_tx_parser.ts new file mode 100644 index 00000000..e17a01e6 --- /dev/null +++ b/src/History/base_tx_parser.ts @@ -0,0 +1,174 @@ +import { + iHistoryBaseTx, + iHistoryBaseTxNFTsReceived, + iHistoryBaseTxNFTsReceivedRaw, + iHistoryBaseTxNFTsSent, + iHistoryBaseTxNFTsSentRaw, + iHistoryBaseTxToken, + iHistoryBaseTxTokenLossGain, + iHistoryBaseTxTokenOwners, + ITransactionData, + UTXO, +} from '@/History'; +import * as Assets from '@/Asset/Assets'; +import { bnToLocaleString, getTxFeeX } from '@/utils'; +import { AVMConstants } from 'avalanche/dist/apis/avm'; +import { BN } from 'avalanche'; +import { getAssetBalanceFromUTXOs, getNFTBalanceFromUTXOs, parseMemo } from '@/History/history_helpers'; +import { + filterDuplicateStrings, + getAssetOutputs, + getNotOwnedOutputs, + getOutputsAssetIDs, + getOutputsAssetOwners, + getOutputsOfType, + getOutputTotals, + getOwnedOutputs, +} from '@/History/utxo_helpers'; +import { getAvaxAssetID } from '@/Network'; + +export async function getBaseTxSummary(tx: ITransactionData, ownerAddrs: string[]): Promise { + let ins = tx.inputs?.map((input) => input.output) || []; + let outs = tx.outputs || []; + + // Calculate losses from inputs + let losses = getOwnedTokens(ins, ownerAddrs); + let gains = getOwnedTokens(outs, ownerAddrs); + + let nowOwnedIns = getNotOwnedOutputs(ins, ownerAddrs); + let nowOwnedOuts = getNotOwnedOutputs(outs, ownerAddrs); + + let froms = getOutputsAssetOwners(nowOwnedIns); + let tos = getOutputsAssetOwners(nowOwnedOuts); + + let tokens = await getBaseTxTokensSummary(gains, losses, froms, tos); + + return { + id: tx.id, + fee: getTxFeeX(), + type: 'transaction', + timestamp: new Date(tx.timestamp), + memo: parseMemo(tx.memo), + tokens: tokens, + }; +} + +function getBaseTxNFTLosses(tx: ITransactionData, ownerAddrs: string[]): iHistoryBaseTxNFTsSentRaw { + let ins = tx.inputs || []; + let inUTXOs = ins.map((input) => input.output); + let nftUTXOs = inUTXOs.filter((utxo) => { + return utxo.outputType === AVMConstants.NFTXFEROUTPUTID; + }); + + let res: iHistoryBaseTxNFTsSentRaw = {}; + for (let assetID in tx.inputTotals) { + let nftBal = getNFTBalanceFromUTXOs(nftUTXOs, ownerAddrs, assetID); + + // If empty dictionary pass + if (Object.keys(nftBal).length === 0) continue; + + res[assetID] = nftBal; + } + return res; +} + +function getBaseTxNFTGains(tx: ITransactionData, ownerAddrs: string[]): iHistoryBaseTxNFTsReceivedRaw { + let outs = tx.outputs || []; + let nftUTXOs = outs.filter((utxo) => { + return utxo.outputType === AVMConstants.NFTXFEROUTPUTID; + }); + let res: iHistoryBaseTxNFTsReceivedRaw = {}; + + for (let assetID in tx.inputTotals) { + let nftBal = getNFTBalanceFromUTXOs(nftUTXOs, ownerAddrs, assetID); + // If empty dictionary pass + if (Object.keys(nftBal).length === 0) continue; + + res[assetID] = nftBal; + } + return res; +} + +/** + * Returns a dictionary of asset totals belonging to the owner + * @param utxos + * @param ownerAddrs + */ +function getOwnedTokens(utxos: UTXO[], ownerAddrs: string[]): iHistoryBaseTxTokenLossGain { + let tokenUTXOs = getOutputsOfType(utxos, AVMConstants.SECPXFEROUTPUTID); + // Owned inputs + let myUTXOs = getOwnedOutputs(tokenUTXOs, ownerAddrs); + + // Asset IDs received + let assetIDs = getOutputsAssetIDs(myUTXOs); + + let res: iHistoryBaseTxTokenLossGain = {}; + + for (let i = 0; i < assetIDs.length; i++) { + let assetID = assetIDs[i]; + let assetUTXOs = getAssetOutputs(myUTXOs, assetID); + let tot = getOutputTotals(assetUTXOs); + res[assetID] = tot; + } + + return res; +} + +async function getBaseTxTokensSummary( + gains: iHistoryBaseTxTokenLossGain, + losses: iHistoryBaseTxTokenLossGain, + froms: iHistoryBaseTxTokenOwners, + tos: iHistoryBaseTxTokenOwners +): Promise { + let res: iHistoryBaseTxToken[] = []; + + let assetIDs = filterDuplicateStrings([...Object.keys(gains), ...Object.keys(losses)]); + + // Fetch asset descriptions + let calls = assetIDs.map((id) => Assets.getAssetDescription(id)); + let descs = await Promise.all(calls); + let descsDict: any = {}; + + // Convert array to dict + for (let i = 0; i < descs.length; i++) { + let desc = descs[i]; + descsDict[desc.assetID] = desc; + } + + for (let i = 0; i < assetIDs.length; i++) { + let id = assetIDs[i]; + let tokenGain = gains[id] || new BN(0); + let tokenLost = losses[id] || new BN(0); + let tokenDesc = descsDict[id]; + + // If we sent avax, deduct the fee + if (id === getAvaxAssetID() && !tokenLost.isZero()) { + tokenLost = tokenLost.sub(getTxFeeX()); + } + + // How much we gained/lost of this token + let diff = tokenGain.sub(tokenLost); + let diffClean = bnToLocaleString(diff, tokenDesc.denomination); + + // If we didnt gain or lose anything, ignore this token + if (diff.isZero()) continue; + + if (diff.isNeg()) { + res.push({ + amount: diff, + amountDisplayValue: diffClean, + addresses: tos[id], + asset: tokenDesc, + }); + } else { + res.push({ + amount: diff, + amountDisplayValue: diffClean, + addresses: froms[id], + asset: tokenDesc, + }); + } + } + + return res; +} diff --git a/src/History/evmParser.ts b/src/History/evmParser.ts new file mode 100644 index 00000000..c966f5df --- /dev/null +++ b/src/History/evmParser.ts @@ -0,0 +1,33 @@ +import { ITransactionDataEVM } from '@/History/raw_types'; +import { iHistoryEVMTx } from '@/History/parsed_types'; +import { bnToAvaxC } from '@/utils'; +import { BN } from 'avalanche'; + +export function getTransactionSummaryEVM(tx: ITransactionDataEVM, walletAddress: string): iHistoryEVMTx { + let isSender = tx.fromAddr.toUpperCase() === walletAddress.toUpperCase(); + + let amt = new BN(tx.value); + let amtClean = bnToAvaxC(amt); + let date = new Date(tx.createdAt); + + let gasLimit = new BN(tx.gasLimit); + let gasPrice = new BN(tx.gasPrice); + let feeBN = gasLimit.mul(gasPrice); // in gwei + + return { + id: tx.hash, + fee: feeBN, + memo: '', + block: tx.block, + isSender, + type: 'transaction_evm', + amount: amt, + amountDisplayValue: amtClean, + gasLimit: tx.gasLimit, + gasPrice: tx.gasPrice, + from: tx.fromAddr, + to: tx.toAddr, + timestamp: date, + input: tx.input, + }; +} diff --git a/src/History/history.ts b/src/History/history.ts deleted file mode 100644 index 99b94ea6..00000000 --- a/src/History/history.ts +++ /dev/null @@ -1,641 +0,0 @@ -import { - AVMHistoryItemType, - iHistoryAddDelegator, - iHistoryBaseTx, - iHistoryBaseTxNFTsReceived, - iHistoryBaseTxNFTsReceivedRaw, - iHistoryBaseTxNFTsSent, - iHistoryBaseTxNFTsSentRaw, - iHistoryBaseTxTokensReceived, - iHistoryBaseTxTokensReceivedRaw, - iHistoryBaseTxTokensSent, - iHistoryBaseTxTokensSentRaw, - iHistoryEVMTx, - iHistoryImportExport, - iHistoryNftFamilyBalance, - ITransactionData, - ITransactionDataEVM, - UTXO, -} from '@/History/types'; -import { activeNetwork, explorer_api, xChain } from '@/Network/network'; -import { BN } from 'avalanche'; -import { ChainIdType } from '@/types'; -import { AVMConstants } from 'avalanche/dist/apis/avm'; -import { bnToAvaxC, bnToAvaxP, bnToAvaxX, bnToLocaleString, parseNftPayload } from '@/utils'; -import * as Assets from '@/Asset/Assets'; -import { NO_EXPLORER_API } from '@/errors'; - -/** - * Returns transactions FROM and TO the address given - * @param addr The address to get historic transactions for. - */ -export async function getAddressHistoryEVM(addr: string): Promise { - if (!explorer_api) { - throw NO_EXPLORER_API; - } - - let endpoint = `v2/ctransactions?address=${addr}`; - let data: ITransactionDataEVM[] = (await explorer_api.get(endpoint)).data.Transactions; - - data.sort((a, b) => { - let dateA = new Date(a.createdAt); - let dateB = new Date(b.createdAt); - - return dateB.getTime() - dateA.getTime(); - }); - - return data; -} - -export async function getAddressHistory( - addrs: string[], - limit = 20, - chainID: string, - endTime?: string -): Promise { - if (!explorer_api) { - throw NO_EXPLORER_API; - } - - const ADDR_SIZE = 1024; - let selection = addrs.slice(0, ADDR_SIZE); - let remaining = addrs.slice(ADDR_SIZE); - - let addrsRaw = selection.map((addr) => { - return addr.split('-')[1]; - }); - - let rootUrl = 'v2/transactions'; - - let req = { - address: addrsRaw, - sort: ['timestamp-desc'], - disableCount: ['1'], - chainID: [chainID], - disableGenesis: ['false'], - }; - - if (limit > 0) { - //@ts-ignore - req.limit = [limit.toString()]; - } - - if (endTime) { - //@ts-ignore - req.endTime = [endTime]; - } - - let res = await explorer_api.post(rootUrl, req); - let txs = res.data.transactions; - let next: string | undefined = res.data.next; - - if (txs === null) txs = []; - - // If we need to fetch more for this address - if (next && !limit) { - let endTime = next.split('&')[0].split('=')[1]; - let nextRes = await getAddressHistory(selection, limit, chainID, endTime); - txs.push(...nextRes); - } - - // If there are addresses left, fetch them too - // TODO: Do this in parallel, not recursive - if (remaining.length > 0) { - let nextRes = await getAddressHistory(remaining, limit, chainID); - txs.push(...nextRes); - } - - return txs; -} - -export async function getTransactionSummary( - tx: ITransactionData, - walletAddrs: string[], - evmAddress: string -): Promise { - let sum; - - let cleanAddressesXP = walletAddrs.map((addr) => addr.split('-')[1]); - - switch (tx.type) { - case 'import': - case 'pvm_import': - sum = getImportSummary(tx, cleanAddressesXP); - break; - case 'export': - case 'pvm_export': - case 'atomic_export_tx': - sum = getExportSummary(tx, cleanAddressesXP); - break; - case 'add_validator': - sum = getValidatorSummary(tx, cleanAddressesXP); - break; - case 'add_delegator': - sum = getValidatorSummary(tx, cleanAddressesXP); - break; - case 'atomic_import_tx': - sum = getImportSummaryC(tx, evmAddress); - break; - case 'operation': - case 'base': - sum = await getBaseTxSummary(tx, cleanAddressesXP); - break; - default: - throw new Error(`Unsupported history transaction type. (${tx.type})`); - } - return sum; -} - -export function getTransactionSummaryEVM(tx: ITransactionDataEVM, walletAddress: string): iHistoryEVMTx { - let isSender = tx.fromAddr.toUpperCase() === walletAddress.toUpperCase(); - - let amt = new BN(tx.value); - let amtClean = bnToAvaxC(amt); - let date = new Date(tx.createdAt); - - let gasLimit = new BN(tx.gasLimit); - let gasPrice = new BN(tx.gasPrice); - let feeBN = gasLimit.mul(gasPrice); // in gwei - - return { - id: tx.hash, - fee: feeBN, - memo: '', - hash: tx.hash, - block: tx.block, - isSender, - type: 'transaction_evm', - amount: amt, - amountClean: amtClean, - gasLimit: tx.gasLimit, - gasPrice: tx.gasPrice, - from: tx.fromAddr, - to: tx.toAddr, - timestamp: date, - }; -} - -function idToChainAlias(id: string): ChainIdType { - if (id === activeNetwork.xChainID) { - return 'X'; - } else if (id === activeNetwork.pChainID) { - return 'P'; - } else if (id === activeNetwork.cChainID) { - return 'C'; - } - throw new Error('Unknown chain ID.'); -} - -// If any of the outputs has a different chain ID, thats the destination chain -// else return current chain -function findDestinationChain(tx: ITransactionData): string { - let baseChain = tx.chainID; - let outs = tx.outputs || []; - - for (let i = 0; i < outs.length; i++) { - let outChainId = outs[i].outChainID; - - if (outChainId !== baseChain) return outChainId; - } - return baseChain; -} - -// If any of the inputs has a different chain ID, thats the source chain -// else return current chain -function findSourceChain(tx: ITransactionData): string { - let baseChain = tx.chainID; - let ins = tx.inputs; - - for (let i = 0; i < ins.length; i++) { - let inChainId = ins[i].output.inChainID; - if (inChainId !== baseChain) return inChainId; - } - return baseChain; -} - -function isOutputOwner(ownerAddrs: string[], output: UTXO): boolean { - let outAddrs = output.addresses; - if (!outAddrs) return false; - - let totAddrs = outAddrs.filter((addr) => { - return ownerAddrs.includes(addr); - }); - - return totAddrs.length > 0; -} - -function isOutputOwnerC(ownerAddr: string, output: UTXO): boolean { - let outAddrs = output.caddresses; - if (!outAddrs) return false; - return outAddrs.includes(ownerAddr); -} - -/** - * Returns the total amount of `assetID` in the given `utxos` owned by `address`. Checks for X/P addresses. - * @param utxos UTXOs to calculate balance from. - * @param addresses The wallet's addresses. - * @param assetID Only count outputs of this asset ID. - * @param chainID Only count the outputs on this chain. - * @param isStake Set to `true` if looking for staking utxos. - */ -function getAssetBalanceFromUTXOs( - utxos: UTXO[], - addresses: string[], - assetID: string, - chainID: string, - isStake = false -) { - let myOuts = utxos.filter((utxo) => { - if ( - assetID === utxo.assetID && - isOutputOwner(addresses, utxo) && - chainID === utxo.chainID && - utxo.stake === isStake - ) { - return true; - } - return false; - }); - - let tot = myOuts.reduce((acc, utxo) => { - return acc.add(new BN(utxo.amount)); - }, new BN(0)); - - return tot; -} - -function getNFTBalanceFromUTXOs(utxos: UTXO[], addresses: string[], assetID: string): iHistoryNftFamilyBalance { - let nftUTXOs = utxos.filter((utxo) => { - if ( - utxo.outputType === AVMConstants.NFTXFEROUTPUTID && - utxo.assetID === assetID && - isOutputOwner(addresses, utxo) - ) { - return true; - } - return false; - }); - - let res: iHistoryNftFamilyBalance = {}; - for (let i = 0; i < nftUTXOs.length; i++) { - let utxo = nftUTXOs[i]; - let groupID = utxo.groupID; - - let content; - if (utxo.payload) { - let parsedPayload = parseNftPayload(utxo.payload); - content = parsedPayload.getContent().toString(); - } - - if (res[groupID]) { - res[groupID].amount++; - } else { - res[groupID] = { - payload: content || '', - amount: 1, - }; - } - } - return res; -} - -/** - * Returns the total amount of `assetID` in the given `utxos` owned by `address`. Checks for EVM address. - * @param utxos UTXOs to calculate balance from. - * @param address The wallet's evm address `0x...`. - * @param assetID Only count outputs of this asset ID. - * @param chainID Only count the outputs on this chain. - * @param isStake Set to `true` if looking for staking utxos. - */ -function getEvmAssetBalanceFromUTXOs( - utxos: UTXO[], - address: string, - assetID: string, - chainID: string, - isStake = false -) { - let myOuts = utxos.filter((utxo) => { - if ( - assetID === utxo.assetID && - isOutputOwnerC(address, utxo) && - chainID === utxo.chainID && - utxo.stake === isStake - ) { - return true; - } - return false; - }); - - let tot = myOuts.reduce((acc, utxo) => { - return acc.add(new BN(utxo.amount)); - }, new BN(0)); - - return tot; -} - -function getImportSummary(tx: ITransactionData, addresses: string[]): iHistoryImportExport { - let sourceChain = findSourceChain(tx); - let chainAliasFrom = idToChainAlias(sourceChain); - let chainAliasTo = idToChainAlias(tx.chainID); - - let avaxID = activeNetwork.avaxID; - - let outs = tx.outputs || []; - let amtOut = getAssetBalanceFromUTXOs(outs, addresses, avaxID, tx.chainID); - - let time = new Date(tx.timestamp); - let fee = xChain.getTxFee(); - - let res: iHistoryImportExport = { - id: tx.id, - memo: parseMemo(tx.memo), - source: chainAliasFrom, - destination: chainAliasTo, - amount: amtOut, - amountClean: bnToAvaxX(amtOut), - timestamp: time, - type: 'import', - fee: fee, - }; - - return res; -} - -function getExportSummary(tx: ITransactionData, addresses: string[]): iHistoryImportExport { - let inputs = tx.inputs; - let sourceChain = inputs[0].output.chainID; - let chainAliasFrom = idToChainAlias(sourceChain); - - let destinationChain = findDestinationChain(tx); - let chainAliasTo = idToChainAlias(destinationChain); - - let avaxID = activeNetwork.avaxID; - - let outs = tx.outputs || []; - let amtOut = getAssetBalanceFromUTXOs(outs, addresses, avaxID, destinationChain); - // let amtIn = getAssetBalanceFromUTXOs(inUtxos, addresses, avaxID); - - let time = new Date(tx.timestamp); - let fee = xChain.getTxFee(); - - let res: iHistoryImportExport = { - id: tx.id, - memo: parseMemo(tx.memo), - source: chainAliasFrom, - destination: chainAliasTo, - amount: amtOut, - amountClean: bnToAvaxX(amtOut), - timestamp: time, - type: 'export', - fee: fee, - }; - - return res; -} - -function getValidatorSummary(tx: ITransactionData, ownerAddrs: string[]): iHistoryAddDelegator { - let time = new Date(tx.timestamp); - - let pChainID = activeNetwork.pChainID; - let avaxID = activeNetwork.avaxID; - - let outs = tx.outputs || []; - let stakeAmt = getAssetBalanceFromUTXOs(outs, ownerAddrs, avaxID, pChainID, true); - - return { - id: tx.id, - nodeID: tx.validatorNodeID, - stakeStart: new Date(tx.validatorStart * 1000), - stakeEnd: new Date(tx.validatorEnd * 1000), - timestamp: time, - type: 'add_validator', - fee: new BN(0), - amount: stakeAmt, - amountClean: bnToAvaxP(stakeAmt), - memo: parseMemo(tx.memo), - isRewarded: tx.rewarded, - }; -} - -// Returns the summary for a C chain import TX -function getImportSummaryC(tx: ITransactionData, ownerAddr: string) { - let sourceChain = findSourceChain(tx); - let chainAliasFrom = idToChainAlias(sourceChain); - let chainAliasTo = idToChainAlias(tx.chainID); - - let avaxID = activeNetwork.avaxID; - - let outs = tx.outputs || []; - let amtOut = getEvmAssetBalanceFromUTXOs(outs, ownerAddr, avaxID, tx.chainID); - - let time = new Date(tx.timestamp); - let fee = xChain.getTxFee(); - - let res: iHistoryImportExport = { - id: tx.id, - source: chainAliasFrom, - destination: chainAliasTo, - amount: amtOut, - amountClean: bnToAvaxX(amtOut), - timestamp: time, - type: 'import', - fee: fee, - memo: parseMemo(tx.memo), - }; - - return res; -} - -async function getBaseTxSummary(tx: ITransactionData, ownerAddrs: string[]): Promise { - // Calculate losses from inputs - let losses = getBaseTxTokenLosses(tx, ownerAddrs); - let lossesNFT = getBaseTxNFTLosses(tx, ownerAddrs); - - // Calculate gains from inputs - let gains = getBaseTxTokenGains(tx, ownerAddrs); - let gainsNFT = getBaseTxNFTGains(tx, ownerAddrs); - - // TODO: Calculate absolutes - // gains - losses - - let received: iHistoryBaseTxTokensReceived = {}; - let receivedNFTs: iHistoryBaseTxNFTsReceived = {}; - - // Process Received Tokens - for (let assetID in gains) { - let fromAddrs = getBaseTxSenders(tx, assetID); - let tokenDesc = await Assets.getAssetDescription(assetID); - let amtBN = gains[assetID]; - received[assetID] = { - amount: amtBN, - amountClean: bnToLocaleString(amtBN, tokenDesc.denomination), - from: fromAddrs, - asset: tokenDesc, - }; - } - - // Process Received NFTs - for (let assetID in gainsNFT) { - let fromAddrs = getBaseTxSenders(tx, assetID); - let tokenDesc = await Assets.getAssetDescription(assetID); - let groups = gainsNFT[assetID]; - receivedNFTs[assetID] = { - groups: groups, - from: fromAddrs, - asset: tokenDesc, - }; - } - - // Process Sent Tokens - let sent: iHistoryBaseTxTokensSent = {}; - let sentNFTs: iHistoryBaseTxNFTsSent = {}; - - // Process sent tokens - for (let assetID in losses) { - let toAddrs = getBaseTxReceivers(tx, assetID); - let tokenDesc = await Assets.getAssetDescription(assetID); - let amtBN = losses[assetID]; - - sent[assetID] = { - amount: amtBN, - amountClean: bnToLocaleString(amtBN, tokenDesc.denomination), - to: toAddrs, - asset: tokenDesc, - }; - } - - // Process Received NFTs - for (let assetID in lossesNFT) { - let fromAddrs = getBaseTxSenders(tx, assetID); - let tokenDesc = await Assets.getAssetDescription(assetID); - let groups = lossesNFT[assetID]; - sentNFTs[assetID] = { - groups: groups, - to: fromAddrs, - asset: tokenDesc, - }; - } - - return { - id: tx.id, - fee: xChain.getTxFee(), - type: 'transaction', - timestamp: new Date(tx.timestamp), - memo: parseMemo(tx.memo), - tokens: { - sent, - received, - }, - nfts: { - sent: sentNFTs, - received: receivedNFTs, - }, - }; -} - -function getBaseTxNFTLosses(tx: ITransactionData, ownerAddrs: string[]): iHistoryBaseTxNFTsSentRaw { - let inUTXOs = tx.inputs.map((input) => input.output); - let nftUTXOs = inUTXOs.filter((utxo) => { - return utxo.outputType === AVMConstants.NFTXFEROUTPUTID; - }); - - let res: iHistoryBaseTxNFTsSentRaw = {}; - for (let assetID in tx.inputTotals) { - let nftBal = getNFTBalanceFromUTXOs(nftUTXOs, ownerAddrs, assetID); - - // If empty dictionary pass - if (Object.keys(nftBal).length === 0) continue; - - res[assetID] = nftBal; - } - return res; -} - -function getBaseTxNFTGains(tx: ITransactionData, ownerAddrs: string[]): iHistoryBaseTxNFTsReceivedRaw { - let outs = tx.outputs || []; - let nftUTXOs = outs.filter((utxo) => { - return utxo.outputType === AVMConstants.NFTXFEROUTPUTID; - }); - let res: iHistoryBaseTxNFTsReceivedRaw = {}; - - for (let assetID in tx.inputTotals) { - let nftBal = getNFTBalanceFromUTXOs(nftUTXOs, ownerAddrs, assetID); - // If empty dictionary pass - if (Object.keys(nftBal).length === 0) continue; - - res[assetID] = nftBal; - } - return res; -} - -function getBaseTxTokenLosses(tx: ITransactionData, ownerAddrs: string[]): iHistoryBaseTxTokensSentRaw { - let inUTXOs = tx.inputs.map((input) => input.output); - let tokenUTXOs = inUTXOs.filter((utxo) => { - return utxo.outputType === AVMConstants.SECPXFEROUTPUTID; - }); - - let chainID = xChain.getBlockchainID(); - let res: iHistoryBaseTxTokensSentRaw = {}; - for (let assetID in tx.inputTotals) { - let bal = getAssetBalanceFromUTXOs(tokenUTXOs, ownerAddrs, assetID, chainID); - if (bal.isZero()) continue; - res[assetID] = bal; - } - return res; -} - -function getBaseTxTokenGains(tx: ITransactionData, ownerAddrs: string[]): iHistoryBaseTxTokensReceivedRaw { - let chainID = xChain.getBlockchainID(); - let outs = tx.outputs || []; - let tokenUTXOs = outs.filter((utxo) => { - return utxo.outputType === AVMConstants.SECPXFEROUTPUTID; - }); - - let res: iHistoryBaseTxTokensReceivedRaw = {}; - for (let assetID in tx.outputTotals) { - let bal = getAssetBalanceFromUTXOs(tokenUTXOs, ownerAddrs, assetID, chainID); - if (bal.isZero()) continue; - res[assetID] = bal; - } - return res; -} - -// Look at the inputs and check where the assetID came from. -function getBaseTxSenders(tx: ITransactionData, assetID: string): string[] { - let inUTXOs = tx.inputs.map((input) => input.output); - let res: string[] = []; - for (let i = 0; i < inUTXOs.length; i++) { - let utxo = inUTXOs[i]; - if (utxo.assetID === assetID && utxo.addresses) { - res.push(...utxo.addresses); - } - } - // Eliminate Duplicates - return res.filter((addr, i) => { - return res.indexOf(addr) === i; - }); -} - -// Look at the inputs and check where the assetID came from. -function getBaseTxReceivers(tx: ITransactionData, assetID: string): string[] { - let res: string[] = []; - let outs = tx.outputs || []; - for (let i = 0; i < outs.length; i++) { - let utxo = outs[i]; - if (utxo.assetID === assetID && utxo.addresses) { - res.push(...utxo.addresses); - } - } - // Eliminate Duplicates - return res.filter((addr, i) => { - return res.indexOf(addr) === i; - }); -} - -function parseMemo(raw: string): string { - const memoText = new Buffer(raw, 'base64').toString('utf8'); - - // Bug that sets memo to empty string (AAAAAA==) for some tx types - if (!memoText.length || raw === 'AAAAAA==') return ''; - return memoText; -} diff --git a/src/History/history_helpers.ts b/src/History/history_helpers.ts new file mode 100644 index 00000000..19bb73d5 --- /dev/null +++ b/src/History/history_helpers.ts @@ -0,0 +1,199 @@ +// If any of the outputs has a different chain ID, that's the destination chain +// else return current chain +import { iHistoryNftFamilyBalance, ITransactionData, UTXO } from '@/History'; +import { BN } from 'avalanche'; +import { AVMConstants } from 'avalanche/dist/apis/avm'; +import { parseNftPayload } from '@/utils'; + +/** + * Returns the destination chain id. + * @param tx Tx data from the explorer. + */ +export function findDestinationChain(tx: ITransactionData): string { + let baseChain = tx.chainID; + let outs = tx.outputs || []; + + for (let i = 0; i < outs.length; i++) { + let outChainId = outs[i].outChainID; + if (!outChainId) continue; + if (outChainId !== baseChain) return outChainId; + } + return baseChain; +} + +// If any of the inputs has a different chain ID, thats the source chain +// else return current chain +/** + * Returns the source chain id. + * @param tx Tx data from the explorer. + */ +export function findSourceChain(tx: ITransactionData): string { + let baseChain = tx.chainID; + let ins = tx.inputs || []; + + for (let i = 0; i < ins.length; i++) { + let inChainId = ins[i].output.inChainID; + if (!inChainId) continue; + if (inChainId !== baseChain) return inChainId; + } + return baseChain; +} + +/** + * Returns true if this utxo is owned by any of the given addresses + * @param ownerAddrs Addresses to check against + * @param output The UTXO + */ +export function isOutputOwner(ownerAddrs: string[], output: UTXO): boolean { + let outAddrs = output.addresses; + if (!outAddrs) return false; + + let totAddrs = outAddrs.filter((addr) => { + return ownerAddrs.includes(addr); + }); + + return totAddrs.length > 0; +} + +export function isOutputOwnerC(ownerAddr: string, output: UTXO): boolean { + let outAddrs = output.caddresses; + if (!outAddrs) return false; + return outAddrs.includes(ownerAddr); +} + +/** + * Given an array of transactions from the explorer, filter out duplicate transactions + * @param txs + */ +export function filterDuplicateTransactions(txs: ITransactionData[]) { + let txsIds: string[] = []; + let filtered: ITransactionData[] = []; + + for (let i = 0; i < txs.length; i++) { + let tx = txs[i]; + let txId = tx.id; + + if (txsIds.includes(txId)) { + continue; + } else { + txsIds.push(txId); + filtered.push(tx); + } + } + return filtered; +} + +/** + * Returns the total amount of `assetID` in the given `utxos` owned by `address`. Checks for X/P addresses. + * @param utxos UTXOs to calculate balance from. + * @param addresses The wallet's addresses. + * @param assetID Only count outputs of this asset ID. + * @param chainID Only count the outputs on this chain. + * @param isStake Set to `true` if looking for staking utxos. + */ +export function getAssetBalanceFromUTXOs( + utxos: UTXO[], + addresses: string[], + assetID: string, + chainID: string, + isStake = false +) { + let myOuts = utxos.filter((utxo) => { + if ( + assetID === utxo.assetID && + isOutputOwner(addresses, utxo) && + chainID === utxo.chainID && + utxo.stake === isStake + ) { + return true; + } + return false; + }); + + let tot = myOuts.reduce((acc, utxo) => { + return acc.add(new BN(utxo.amount)); + }, new BN(0)); + + return tot; +} + +export function getNFTBalanceFromUTXOs(utxos: UTXO[], addresses: string[], assetID: string): iHistoryNftFamilyBalance { + let nftUTXOs = utxos.filter((utxo) => { + if ( + utxo.outputType === AVMConstants.NFTXFEROUTPUTID && + utxo.assetID === assetID && + isOutputOwner(addresses, utxo) + ) { + return true; + } + return false; + }); + + let res: iHistoryNftFamilyBalance = {}; + for (let i = 0; i < nftUTXOs.length; i++) { + let utxo = nftUTXOs[i]; + let groupID = utxo.groupID; + + let content; + if (utxo.payload) { + let parsedPayload = parseNftPayload(utxo.payload); + content = parsedPayload.getContent().toString(); + } + + if (res[groupID]) { + res[groupID].amount++; + } else { + res[groupID] = { + payload: content || '', + amount: 1, + }; + } + } + return res; +} + +/** + * Returns the total amount of `assetID` in the given `utxos` owned by `address`. Checks for EVM address. + * @param utxos UTXOs to calculate balance from. + * @param address The wallet's evm address `0x...`. + * @param assetID Only count outputs of this asset ID. + * @param chainID Only count the outputs on this chain. + * @param isStake Set to `true` if looking for staking utxos. + */ +export function getEvmAssetBalanceFromUTXOs( + utxos: UTXO[], + address: string, + assetID: string, + chainID: string, + isStake = false +) { + let myOuts = utxos.filter((utxo) => { + if ( + assetID === utxo.assetID && + isOutputOwnerC(address, utxo) && + chainID === utxo.chainID && + utxo.stake === isStake + ) { + return true; + } + return false; + }); + + let tot = myOuts.reduce((acc, utxo) => { + return acc.add(new BN(utxo.amount)); + }, new BN(0)); + + return tot; +} + +/** + * Parse the raw memo field to readable text. + * @param raw + */ +export function parseMemo(raw: string): string { + const memoText = new Buffer(raw, 'base64').toString('utf8'); + + // Bug that sets memo to empty string (AAAAAA==) for some tx types + if (!memoText.length || raw === 'AAAAAA==') return ''; + return memoText; +} diff --git a/src/History/importExportParser.ts b/src/History/importExportParser.ts new file mode 100644 index 00000000..a6f099a6 --- /dev/null +++ b/src/History/importExportParser.ts @@ -0,0 +1,64 @@ +import { ITransactionData } from '@/History/raw_types'; +import { iHistoryImportExport } from '@/History/parsed_types'; +import { findDestinationChain, findSourceChain, getAssetBalanceFromUTXOs, parseMemo } from '@/History/history_helpers'; +import { idToChainAlias } from '@/Network/helpers/aliasFromNetworkID'; +import { activeNetwork, xChain } from '@/Network/network'; +import { bnToAvaxX } from '@/utils'; +import { getOutputsOfChain, getOutputTotals, getOwnedOutputs } from '@/History/utxo_helpers'; + +export function getImportSummary(tx: ITransactionData, addresses: string[]): iHistoryImportExport { + let sourceChain = findSourceChain(tx); + let chainAliasFrom = idToChainAlias(sourceChain); + let chainAliasTo = idToChainAlias(tx.chainID); + + let outs = tx.outputs || []; + let myOuts = getOwnedOutputs(outs, addresses); + let amtOut = getOutputTotals(myOuts); + + let time = new Date(tx.timestamp); + let fee = xChain.getTxFee(); + + let res: iHistoryImportExport = { + id: tx.id, + memo: parseMemo(tx.memo), + source: chainAliasFrom, + destination: chainAliasTo, + amount: amtOut, + amountDisplayValue: bnToAvaxX(amtOut), + timestamp: time, + type: 'import', + fee: fee, + }; + + return res; +} + +export function getExportSummary(tx: ITransactionData, addresses: string[]): iHistoryImportExport { + let sourceChain = findSourceChain(tx); + let chainAliasFrom = idToChainAlias(sourceChain); + + let destinationChain = findDestinationChain(tx); + let chainAliasTo = idToChainAlias(destinationChain); + + let outs = tx.outputs || []; + let myOuts = getOwnedOutputs(outs, addresses); + let chainOuts = getOutputsOfChain(myOuts, destinationChain); + let amtOut = getOutputTotals(chainOuts); + + let time = new Date(tx.timestamp); + let fee = xChain.getTxFee(); + + let res: iHistoryImportExport = { + id: tx.id, + memo: parseMemo(tx.memo), + source: chainAliasFrom, + destination: chainAliasTo, + amount: amtOut, + amountDisplayValue: bnToAvaxX(amtOut), + timestamp: time, + type: 'export', + fee: fee, + }; + + return res; +} diff --git a/src/History/index.ts b/src/History/index.ts new file mode 100644 index 00000000..6b392baa --- /dev/null +++ b/src/History/index.ts @@ -0,0 +1,6 @@ +export * from './api_helpers'; +export * from './history_helpers'; +export * from './parsers'; +export * from './evmParser'; +export * from './raw_types'; +export * from './parsed_types'; diff --git a/src/History/parsed_types.ts b/src/History/parsed_types.ts new file mode 100644 index 00000000..54be75fc --- /dev/null +++ b/src/History/parsed_types.ts @@ -0,0 +1,155 @@ +import { BN } from 'avalanche'; +import { ChainIdType } from '@/types'; +import { iAssetDescriptionClean } from '@/Asset/types'; + +export type HistoryItemType = AVMHistoryItemType | PVMHistoryItemType | EVMHistoryITemType | iHistoryItem; + +export type AVMHistoryItemType = iHistoryBaseTx | iHistoryImportExport; +export type PVMHistoryItemType = iHistoryStaking; +export type EVMHistoryITemType = iHistoryEVMTx; + +export type HistoryImportExportTypeName = 'import' | 'export'; +export type HistoryItemTypeName = + | HistoryImportExportTypeName + | 'transaction' + | 'transaction_evm' + | 'add_delegator' + | 'add_validator' + | 'delegation_fee' + | 'validation_fee' + | 'not_supported'; + +export interface iHistoryItem { + id: string; + type: HistoryItemTypeName; + timestamp: Date; + fee: BN; + memo?: string; +} + +/** + * Parsed interface for Import and Export transactions. + */ +export interface iHistoryImportExport extends iHistoryItem { + amount: BN; + type: HistoryImportExportTypeName; + amountDisplayValue: string; + destination: ChainIdType; + source: ChainIdType; +} + +/** + * Typeguard for `iHistoryImportExport` interface + * @param tx The parsed history object + */ +export function isHistoryImportExportTx(tx: HistoryItemType): tx is iHistoryImportExport { + return tx.type === 'export' || tx.type === 'import'; +} + +/** + * Parsed interface for Validation, Validation Fee, Delegation and Delegation Fee transactions. + */ +export interface iHistoryStaking extends iHistoryItem { + nodeID: string; + stakeStart: Date; + stakeEnd: Date; + amount: BN; + amountDisplayValue: string; + isRewarded: boolean; + rewardAmount?: BN; + rewardAmountDisplayValue?: string; +} + +/** + * Typeguard for `iHistoryStaking` interface + * @param tx The parsed history object + */ +export function isHistoryStakingTx(tx: HistoryItemType): tx is iHistoryStaking { + let types: HistoryItemTypeName[] = ['add_validator', 'add_delegator', 'validation_fee', 'delegation_fee']; + return types.includes(tx.type); +} + +/** + * Interface for parsed X chain base transactions. + */ +export interface iHistoryBaseTx extends iHistoryItem { + tokens: iHistoryBaseTxToken[]; + // nfts: iHistoryBaseTxNFTs; +} + +/** + * Typeguard for `iHistoryBaseTx` interface + * @param tx The parsed history object + */ +export function isHistoryBaseTx(tx: HistoryItemType): tx is iHistoryBaseTx { + return tx.type === 'transaction'; +} + +/** + * Interface for parsed EVM transactions. + */ +export interface iHistoryEVMTx extends iHistoryItem { + block: string; + gasLimit: number; + gasPrice: string; + from: string; + to: string; + amount: BN; + amountDisplayValue: string; + isSender: boolean; + input?: string; +} + +export function isHistoryEVMTx(tx: HistoryItemType): tx is iHistoryEVMTx { + return tx.type === 'transaction_evm'; +} + +export interface iHistoryBaseTxToken { + amount: BN; + amountDisplayValue: string; + addresses: string[]; + asset: iAssetDescriptionClean; +} + +export interface iHistoryBaseTxNFTs { + sent: iHistoryBaseTxNFTsSent; + received: iHistoryBaseTxNFTsReceived; +} + +export interface iHistoryBaseTxTokenLossGain { + [assetId: string]: BN; +} + +export interface iHistoryBaseTxTokenOwners { + [assetId: string]: string[]; +} + +export interface iHistoryNftFamilyBalance { + [groupNum: number]: { + payload: string; + amount: number; + }; +} + +export interface iHistoryBaseTxNFTsReceivedRaw { + [assetID: string]: iHistoryNftFamilyBalance; +} +export interface iHistoryBaseTxNFTsSentRaw { + [assetID: string]: iHistoryNftFamilyBalance; +} + +export interface iHistoryBaseTxNFTsSent { + [assetID: string]: { + groups: iHistoryNftFamilyBalance; + to: string[]; + asset: iAssetDescriptionClean; + }; +} + +export interface iHistoryBaseTxNFTsReceived { + [assetID: string]: { + groups: iHistoryNftFamilyBalance; + from: string[]; + asset: iAssetDescriptionClean; + }; +} diff --git a/src/History/parsers.ts b/src/History/parsers.ts new file mode 100644 index 00000000..4085cf74 --- /dev/null +++ b/src/History/parsers.ts @@ -0,0 +1,131 @@ +import { + HistoryItemType, + HistoryItemTypeName, + iHistoryEVMTx, + iHistoryImportExport, + iHistoryItem, + iHistoryStaking, + ITransactionData, + ITransactionDataEVM, +} from '@/History'; +import { findSourceChain, getEvmAssetBalanceFromUTXOs, parseMemo } from '@/History/history_helpers'; +import { activeNetwork, xChain } from '@/Network/network'; +import { bnToAvaxC, bnToAvaxP, bnToAvaxX } from '@/utils'; +import { BN } from 'avalanche'; +import { getBaseTxSummary } from '@/History/base_tx_parser'; +import { idToChainAlias } from '@/Network/helpers/aliasFromNetworkID'; +import { getExportSummary, getImportSummary } from '@/History/importExportParser'; +import { getOutputTotals, getOwnedOutputs, getRewardOuts, getStakeAmount } from '@/History/utxo_helpers'; + +export async function getTransactionSummary( + tx: ITransactionData, + walletAddrs: string[], + evmAddress: string +): Promise { + let cleanAddressesXP = walletAddrs.map((addr) => addr.split('-')[1]); + + switch (tx.type) { + case 'import': + case 'pvm_import': + return getImportSummary(tx, cleanAddressesXP); + case 'export': + case 'pvm_export': + case 'atomic_export_tx': + return getExportSummary(tx, cleanAddressesXP); + case 'add_validator': + case 'add_delegator': + return getStakingSummary(tx, cleanAddressesXP); + case 'atomic_import_tx': + return getImportSummaryC(tx, evmAddress); + case 'operation': + case 'base': + return await getBaseTxSummary(tx, cleanAddressesXP); + default: + return getUnsupportedSummary(tx); + } +} + +function getUnsupportedSummary(tx: ITransactionData): iHistoryItem { + return { + id: tx.id, + type: 'not_supported', + timestamp: new Date(tx.timestamp), + fee: new BN(0), + }; +} + +function getStakingSummary(tx: ITransactionData, ownerAddrs: string[]): iHistoryStaking { + let time = new Date(tx.timestamp); + + // let pChainID = activeNetwork.pChainID; + // let avaxID = activeNetwork.avaxID; + let ins = tx.inputs?.map((tx) => tx.output) || []; + let myIns = getOwnedOutputs(ins, ownerAddrs); + + let outs = tx.outputs || []; + let myOuts = getOwnedOutputs(outs, ownerAddrs); + + let stakeAmount = getStakeAmount(tx); + + // Assign the type + let type: HistoryItemTypeName = tx.type === 'add_validator' ? 'add_validator' : 'add_delegator'; + // If this wallet only received the fee + if (myIns.length === 0 && type === 'add_delegator') { + type = 'delegation_fee'; + } else if (myIns.length === 0 && type === 'add_validator') { + type = 'validation_fee'; + } + + let rewardAmount; + let rewardAmountClean; + if (tx.rewarded) { + let rewardOuts = getRewardOuts(myOuts); + rewardAmount = getOutputTotals(rewardOuts); + rewardAmountClean = bnToAvaxP(rewardAmount); + } + + return { + id: tx.id, + nodeID: tx.validatorNodeID, + stakeStart: new Date(tx.validatorStart * 1000), + stakeEnd: new Date(tx.validatorEnd * 1000), + timestamp: time, + type: type, + fee: new BN(0), + amount: stakeAmount, + amountDisplayValue: bnToAvaxP(stakeAmount), + memo: parseMemo(tx.memo), + isRewarded: tx.rewarded, + rewardAmount: rewardAmount, + rewardAmountDisplayValue: rewardAmountClean, + }; +} + +// Returns the summary for a C chain import TX +function getImportSummaryC(tx: ITransactionData, ownerAddr: string) { + let sourceChain = findSourceChain(tx); + let chainAliasFrom = idToChainAlias(sourceChain); + let chainAliasTo = idToChainAlias(tx.chainID); + + let avaxID = activeNetwork.avaxID; + + let outs = tx.outputs || []; + let amtOut = getEvmAssetBalanceFromUTXOs(outs, ownerAddr, avaxID, tx.chainID); + + let time = new Date(tx.timestamp); + let fee = xChain.getTxFee(); + + let res: iHistoryImportExport = { + id: tx.id, + source: chainAliasFrom, + destination: chainAliasTo, + amount: amtOut, + amountDisplayValue: bnToAvaxX(amtOut), + timestamp: time, + type: 'import', + fee: fee, + memo: parseMemo(tx.memo), + }; + + return res; +} diff --git a/src/History/raw_types.ts b/src/History/raw_types.ts new file mode 100644 index 00000000..95ebe6e3 --- /dev/null +++ b/src/History/raw_types.ts @@ -0,0 +1,112 @@ +/** + * Data coming from explorer for C chain + */ +export interface ITransactionDataEVM { + block: string; + hash: string; + createdAt: string; + nonce: number; + gasPrice: string; + gasLimit: number; + blockGasUsed: number; + blockGasLimit: number; + blockNonce: number; + blockHash: string; + recipient: string; + value: string; + toAddr: string; + fromAddr: string; + input?: string; + v: string; + r: string; + s: string; + traces: [ + { + callType: string; + to: string; + from: string; + type: string; + gasUsed: string; + gas: string; + value: string; + } + ]; +} + +/** + * Data coming from the explorer for X,P chain + */ +export interface ITransactionData { + chainID: string; + id: string; + inputTotals: { + [key: string]: string; + }; + inputs: TransactionInput[] | null; + memo: string; + outputTotals: { + [key: string]: string; + }; + outputs: UTXO[] | null; + + reusedAddressTotals: null; + rewarded: boolean; + rewardedTime: string; + timestamp: string; + txFee: number; + type: TransactionType; + validatorStart: number; + validatorEnd: number; + validatorNodeID: string; +} + +interface TransactionInput { + credentials: TransactionCredential[]; + output: UTXO; +} + +interface TransactionCredential { + address: string; + public_key: string; + signature: string; +} + +export interface UTXO { + addresses: string[] | null; + caddresses?: string[]; + amount: string; + assetID: string; + chainID: string; + groupID: number; + id: string; + locktime: number; + payload?: string; + outputIndex: number; + outputType: number; + redeemingTransactionID: string; + stake?: boolean; + inChainID: string; + outChainID: string; + threshold: number; + timestamp: string; + transactionID: string; + rewardUtxo: boolean; +} + +export type TransactionType = + | 'base' + | 'create_asset' + | 'operation' + | 'import' + | 'export' + | 'add_validator' + | 'add_subnet_validator' + | 'add_delegator' + | 'create_chain' + | 'create_subnet' + | 'pvm_import' + | 'pvm_export' + | 'atomic_import_tx' // for c chain imports? + | 'atomic_export_tx' // for c chain exports? + | 'advance_time' + | 'reward_validator'; diff --git a/src/History/types.ts b/src/History/types.ts deleted file mode 100644 index 575cef47..00000000 --- a/src/History/types.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { BN } from 'avalanche'; -import { ChainIdType } from '@/types'; -import { iAssetDescriptionClean } from '@/Asset/types'; - -export interface ITransactionDataEVM { - block: string; - hash: string; - createdAt: string; - nonce: number; - gasPrice: string; - gasLimit: number; - blockGasUsed: number; - blockGasLimit: number; - blockNonce: number; - blockHash: string; - recipient: string; - value: string; - toAddr: string; - fromAddr: string; - v: string; - r: string; - s: string; - traces: [ - { - callType: string; - to: string; - from: string; - type: string; - gasUsed: string; - gas: string; - value: string; - } - ]; -} - -export interface ITransactionData { - chainID: string; - id: string; - inputTotals: { - [key: string]: string; - }; - inputs: TransactionInput[]; - memo: string; - outputTotals: { - [key: string]: string; - }; - outputs: UTXO[] | null; - - reusedAddressTotals: null; - rewarded: boolean; - rewardedTime: string; - timestamp: string; - txFee: number; - type: TransactionType; - validatorStart: number; - validatorEnd: number; - validatorNodeID: string; -} - -interface TransactionInput { - credentials: TransactionCredential[]; - output: UTXO; -} - -interface TransactionCredential { - address: string; - public_key: string; - signature: string; -} - -export interface UTXO { - addresses: string[] | null; - caddresses?: string[]; - amount: string; - assetID: string; - chainID: string; - groupID: number; - id: string; - locktime: number; - payload?: string; - outputIndex: number; - outputType: number; - redeemingTransactionID: string; - stake?: boolean; - inChainID: string; - outChainID: string; - threshold: number; - timestamp: string; - transactionID: string; -} - -export type TransactionType = - | 'base' - | 'create_asset' - | 'operation' - | 'import' - | 'export' - | 'add_validator' - | 'add_subnet_validator' - | 'add_delegator' - | 'create_chain' - | 'create_subnet' - | 'pvm_import' - | 'pvm_export' - | 'atomic_import_tx' // for c chain imports? - | 'atomic_export_tx' // for c chain exports? - | 'advance_time' - | 'reward_validator'; - -export type HistoryItemType = AVMHistoryItemType | EVMHistoryITemType; - -export type AVMHistoryItemType = iHistoryBaseTx | iHistoryImportExport | iHistoryAddDelegator; -export type EVMHistoryITemType = iHistoryEVMTx; - -export type HistoryImportExportTypeName = 'import' | 'export'; -export type HistoryItemTypeName = - | HistoryImportExportTypeName - | 'transaction' - | 'transaction_evm' - | 'add_delegator' - | 'add_validator'; - -export interface iHistoryItem { - id: string; - type: HistoryItemTypeName; - timestamp: Date; - fee: BN; - memo: string; -} - -export interface iHistoryImportExport extends iHistoryItem { - amount: BN; - type: HistoryImportExportTypeName; - amountClean: string; - destination: ChainIdType; - source: ChainIdType; -} - -// export interface iHistoryImport extends iHistoryItem { -// amount: BN; -// amountClean: string; -// destination: ChainIdType; -// source: ChainIdType; -// } - -export interface iHistoryAddDelegator extends iHistoryItem { - nodeID: string; - stakeStart: Date; - stakeEnd: Date; - amount: BN; - amountClean: string; - isRewarded: boolean; -} - -/** - * Interface for parsed X chain base/operation transactions. - */ -export interface iHistoryBaseTx extends iHistoryItem { - tokens: iHistoryBaseTxTokens; - nfts: iHistoryBaseTxNFTs; -} - -/** - * Interface for parsed EVM transactions. - */ -export interface iHistoryEVMTx extends iHistoryItem { - hash: string; - block: string; - gasLimit: number; - gasPrice: string; - from: string; - to: string; - amount: BN; - amountClean: string; - isSender: boolean; -} - -export interface iHistoryBaseTxTokens { - sent: iHistoryBaseTxTokensSent; - received: iHistoryBaseTxTokensReceived; -} - -export interface iHistoryBaseTxNFTs { - sent: iHistoryBaseTxNFTsSent; - received: iHistoryBaseTxNFTsReceived; -} - -export interface iHistoryBaseTxTokensReceived { - [assetId: string]: { - amount: BN; - amountClean: string; - from: string[]; - asset: iAssetDescriptionClean; - }; -} - -export interface iHistoryBaseTxTokensReceivedRaw { - [assetId: string]: BN; -} -export interface iHistoryBaseTxTokensSentRaw { - [assetId: string]: BN; -} - -export interface iHistoryBaseTxTokensSent { - [assetId: string]: { - amount: BN; - amountClean: string; - to: string[]; - asset: iAssetDescriptionClean; - }; -} - -export interface iHistoryNftFamilyBalance { - [groupNum: number]: { - payload: string; - amount: number; - }; -} - -export interface iHistoryBaseTxNFTsReceivedRaw { - [assetID: string]: iHistoryNftFamilyBalance; -} -export interface iHistoryBaseTxNFTsSentRaw { - [assetID: string]: iHistoryNftFamilyBalance; -} - -export interface iHistoryBaseTxNFTsSent { - [assetID: string]: { - groups: iHistoryNftFamilyBalance; - to: string[]; - asset: iAssetDescriptionClean; - }; -} - -export interface iHistoryBaseTxNFTsReceived { - [assetID: string]: { - groups: iHistoryNftFamilyBalance; - from: string[]; - asset: iAssetDescriptionClean; - }; -} diff --git a/src/History/utxo_helpers.ts b/src/History/utxo_helpers.ts new file mode 100644 index 00000000..44133e3b --- /dev/null +++ b/src/History/utxo_helpers.ts @@ -0,0 +1,131 @@ +import { ITransactionData, UTXO } from '@/History/raw_types'; +import { BN } from 'avalanche'; +import { iHistoryBaseTxTokenOwners } from '@/History/parsed_types'; + +export function filterDuplicateStrings(vals: string[]) { + return vals.filter((val, i) => vals.indexOf(val) === i); +} + +export function isArraysOverlap(arr1: any[], arr2: any[]): boolean { + let overlaps = arr1.filter((item) => arr2.includes(item)); + return overlaps.length > 0; +} + +// To get the stake amount, sum the non-reward output utxos. +export function getStakeAmount(tx: ITransactionData): BN { + let outs = tx.outputs || []; + let nonRewardUtxos = outs.filter((utxo) => !utxo.rewardUtxo && utxo.stake); + + let tot = getOutputTotals(nonRewardUtxos); + return tot; +} + +/** + * Returns UTXOs owned by the given addresses + * @param outs UTXOs to filter + * @param myAddrs Addresses to filter by + */ +export function getOwnedOutputs(outs: UTXO[], myAddrs: string[]) { + return outs.filter((out) => { + let outAddrs = out.addresses || []; + return isArraysOverlap(myAddrs, outAddrs); + }); +} + +/** + * Returns addresses of the given UTXOs + * @param outs UTXOs to get the addresses of. + */ +export function getAddresses(outs: UTXO[]): string[] { + let allAddrs: string[] = []; + + for (let i = 0; i < outs.length; i++) { + let out = outs[i]; + let addrs = out.addresses || []; + allAddrs.push(...addrs); + } + + // Remove duplicated + return allAddrs.filter((addr, i) => allAddrs.indexOf(addr) === i); +} + +/** + * Returns only the UTXOs of the given asset id. + * @param outs + * @param assetID + */ +export function getAssetOutputs(outs: UTXO[], assetID: string) { + return outs.filter((out) => out.assetID === assetID); +} + +/** + * Returns UTXOs not owned by the given addresses + * @param outs UTXOs to filter + * @param myAddrs Addresses to filter by + */ +export function getNotOwnedOutputs(outs: UTXO[], myAddrs: string[]) { + return outs.filter((out) => { + let outAddrs = out.addresses || []; + return !isArraysOverlap(myAddrs, outAddrs); + }); +} + +export function getOutputTotals(outs: UTXO[]) { + return outs.reduce((acc, out) => { + return acc.add(new BN(out.amount)); + }, new BN(0)); +} + +export function getRewardOuts(outs: UTXO[]) { + return outs.filter((out) => out.rewardUtxo); +} + +/** + * Returns outputs belonging to the given chain ID + * @param outs UTXOs to filter + * @param chainID Chain ID to filter by + */ +export function getOutputsOfChain(outs: UTXO[], chainID: string) { + return outs.filter((out) => out.chainID === chainID); +} + +/** + * Filters the UTXOs of a certain output type + * @param outs UTXOs to filter + * @param type Output type to filter by + */ +export function getOutputsOfType(outs: UTXO[], type: number) { + return outs.filter((out) => out.outputType === type); +} + +/** + * Returns an array of Asset IDs from the given UTXOs + * @param outs Array of UTXOs + */ +export function getOutputsAssetIDs(outs: UTXO[]): string[] { + let res = []; + + for (let i = 0; i < outs.length; i++) { + let out = outs[i]; + res.push(out.assetID); + } + return filterDuplicateStrings(res); +} + +/** + * Returns a map of asset id to owner addresses + * @param outs + */ +export function getOutputsAssetOwners(outs: UTXO[]): iHistoryBaseTxTokenOwners { + let assetIDs = getOutputsAssetIDs(outs); + let res: iHistoryBaseTxTokenOwners = {}; + + for (let i = 0; i < assetIDs.length; i++) { + let id = assetIDs[i]; + let assetUTXOs = getAssetOutputs(outs, id); + let addrs = getAddresses(assetUTXOs); + res[id] = addrs; + } + + return res; +} diff --git a/src/Network/eventEmitter.ts b/src/Network/eventEmitter.ts new file mode 100644 index 00000000..6a1476ef --- /dev/null +++ b/src/Network/eventEmitter.ts @@ -0,0 +1,12 @@ +import { NetworkConfig } from '@/Network/types'; +import EventEmitter from 'events'; + +/** + * Fire network change event + * @param newNetwork The newly connected network config + */ +export function emitNetworkChange(newNetwork: NetworkConfig) { + networkEvents.emit('network_change', newNetwork); +} + +export const networkEvents: EventEmitter = new EventEmitter(); diff --git a/src/Network/helpers/aliasFromNetworkID.ts b/src/Network/helpers/aliasFromNetworkID.ts new file mode 100644 index 00000000..3a6b0360 --- /dev/null +++ b/src/Network/helpers/aliasFromNetworkID.ts @@ -0,0 +1,17 @@ +import { ChainIdType } from '@/types'; +import { activeNetwork } from '@/Network/network'; + +/** + * Given the chain ID returns the chain alias + * @param id Chain id + */ +export function idToChainAlias(id: string): ChainIdType { + if (id === activeNetwork.xChainID) { + return 'X'; + } else if (id === activeNetwork.pChainID) { + return 'P'; + } else if (id === activeNetwork.cChainID) { + return 'C'; + } + throw new Error('Unknown chain ID.'); +} diff --git a/src/Network/index.ts b/src/Network/index.ts index 22616ae4..846b834d 100644 --- a/src/Network/index.ts +++ b/src/Network/index.ts @@ -3,9 +3,11 @@ import { MainnetConfig, TestnetConfig, LocalnetConfig } from '@/Network/constant import { activeNetwork, setRpcNetwork, getEvmChainID, getConfigFromUrl, setRpcNetworkAsync } from '@/Network/network'; import WebsocketProvider from '@/Network/providers/WebsocketProvider'; import { bustErc20Cache } from '@/Asset/Erc20'; +import { emitNetworkChange } from '@/Network/eventEmitter'; export function setNetwork(conf: NetworkConfig) { setRpcNetwork(conf); + emitNetworkChange(conf); bustErc20Cache(); } @@ -15,6 +17,7 @@ export function setNetwork(conf: NetworkConfig) { */ export async function setNetworkAsync(conf: NetworkConfig) { await setRpcNetworkAsync(conf); + emitNetworkChange(conf); bustErc20Cache(); } diff --git a/src/Wallet/HDWalletAbstract.ts b/src/Wallet/HDWalletAbstract.ts index cc389031..afcbac8c 100644 --- a/src/Wallet/HDWalletAbstract.ts +++ b/src/Wallet/HDWalletAbstract.ts @@ -6,11 +6,14 @@ import { avalanche } from '@/Network/network'; import { UTXOSet as PlatformUTXOSet } from 'avalanche/dist/apis/platformvm'; import { iHDWalletIndex } from '@/Wallet/types'; import { bintools } from '@/common'; +import { networkEvents } from '@/Network/eventEmitter'; +import { NetworkConfig } from '@/Network'; export abstract class HDWalletAbstract extends WalletProvider { protected internalScan: HdScanner; protected externalScan: HdScanner; protected accountKey: HDKey; + public isHdReady = false; protected constructor(accountKey: HDKey) { super(); @@ -20,6 +23,12 @@ export abstract class HDWalletAbstract extends WalletProvider { this.accountKey = accountKey; } + protected onNetworkChange(config: NetworkConfig) { + super.onNetworkChange(config); + + this.isHdReady = false; + } + /** * Returns current index used for external address derivation. */ @@ -96,26 +105,39 @@ export abstract class HDWalletAbstract extends WalletProvider { * - If explorer is not available it will use the connected node. This may result in invalid balances. */ public async resetHdIndices(externalStart = 0, internalStart = 0): Promise { - let indexExt = await this.externalScan.resetIndex(externalStart); - let indexInt = await this.internalScan.resetIndex(internalStart); + let promiseExt = this.externalScan.resetIndex(externalStart); + let promiseInt = this.internalScan.resetIndex(internalStart); + + const [indexExt, indexInt] = await Promise.all([promiseExt, promiseInt]); + + this.emitAddressChange(); + this.isHdReady = true; + this.emitHdReady(); - let indices = { + return { internal: indexInt, external: indexExt, }; + } - this.emitAddressChange(); - this.emitHdReady(indices); + public async setHdIndices(external: number, internal: number) { + this.externalScan.setIndex(external); + this.internalScan.setIndex(internal); - return indices; + this.emitAddressChange(); + this.isHdReady = true; + this.emitHdReady(); } /** * Emits an event to indicate the wallet has finishing calculating its last use address * @protected */ - protected emitHdReady(indices: iHDWalletIndex): void { - this.emit('hd_ready', indices); + protected emitHdReady(): void { + this.emit('hd_ready', { + external: this.getExternalIndex(), + internal: this.getInternalIndex(), + }); } public async updateUtxosX(): Promise { diff --git a/src/Wallet/HdScanner.ts b/src/Wallet/HdScanner.ts index 2b8041ec..6212d181 100644 --- a/src/Wallet/HdScanner.ts +++ b/src/Wallet/HdScanner.ts @@ -40,6 +40,12 @@ export default class HdScanner { return this.index; } + setIndex(index: number) { + let round = Math.floor(index); + if (round < 0) throw new Error('A derivation index can not be less than 0.'); + this.index = round; + } + public increment(): number { return this.index++; } diff --git a/src/Wallet/MnemonicWallet.ts b/src/Wallet/MnemonicWallet.ts index 0a49855f..e7bb4094 100644 --- a/src/Wallet/MnemonicWallet.ts +++ b/src/Wallet/MnemonicWallet.ts @@ -19,18 +19,20 @@ import { avalanche } from '@/Network/network'; import { digestMessage } from '@/utils'; import { HDWalletAbstract } from '@/Wallet/HDWalletAbstract'; import { bintools } from '@/common'; +import { getAccountPathAvalanche, getAccountPathEVM } from '@/Wallet/helpers/derivationHelper'; export default class MnemonicWallet extends HDWalletAbstract implements UnsafeWallet { evmWallet: EvmWallet; type: WalletNameType; mnemonic: string; + accountIndex: number; private ethAccountKey: HDKey; - constructor(mnemonic: string) { + constructor(mnemonic: string, account = 0) { let seed: globalThis.Buffer = bip39.mnemonicToSeedSync(mnemonic); let masterHdKey: HDKey = HDKey.fromMasterSeed(seed); - let accountKey = masterHdKey.derive(AVAX_ACCOUNT_PATH); + let accountKey = masterHdKey.derive(getAccountPathAvalanche(account)); super(accountKey); @@ -39,11 +41,12 @@ export default class MnemonicWallet extends HDWalletAbstract implements UnsafeWa throw new Error('Invalid mnemonic phrase.'); } - let ethAccountKey = masterHdKey.derive(ETH_ACCOUNT_PATH + '/0/0'); + let ethAccountKey = masterHdKey.derive(getAccountPathEVM(account)); this.ethAccountKey = ethAccountKey; let ethKey = ethAccountKey.privateKey; let evmWallet = new EvmWallet(ethKey); + this.accountIndex = account; this.mnemonic = mnemonic; this.evmWallet = evmWallet; } diff --git a/src/Wallet/Wallet.ts b/src/Wallet/Wallet.ts index 5c096a9d..bef251b7 100644 --- a/src/Wallet/Wallet.ts +++ b/src/Wallet/Wallet.ts @@ -61,12 +61,16 @@ import { avaxCtoX, bnToLocaleString, waitTxC, waitTxEvm, waitTxP, waitTxX } from import EvmWalletReadonly from '@/Wallet/EvmWalletReadonly'; import EventEmitter from 'events'; import { + filterDuplicateTransactions, getAddressHistory, getAddressHistoryEVM, getTransactionSummary, getTransactionSummaryEVM, -} from '@/History/history'; -import { HistoryItemType, ITransactionData } from '@/History/types'; + getTx, + getTxEvm, + HistoryItemType, + ITransactionData, +} from '@/History'; import moment from 'moment'; import { bintools } from '@/common'; import { ChainIdType } from '@/types'; @@ -81,6 +85,8 @@ import { } from '@/helpers/universal_tx_helper'; import { UniversalNode } from '@/helpers/UniversalNode'; import { GetStakeResponse } from 'avalanche/dist/common'; +import { networkEvents } from '@/Network/eventEmitter'; +import { NetworkConfig } from '@/Network'; export abstract class WalletProvider { abstract type: WalletNameType; @@ -116,6 +122,25 @@ export abstract class WalletProvider { abstract getAllAddressesX(): string[]; abstract getAllAddressesP(): string[]; + protected constructor() { + networkEvents.on('network_change', this.onNetworkChange); + } + + /** + * Call after getting done with the wallet to avoi memory leaks and remove event listeners + */ + public destroy() { + networkEvents.off('network_change', this.onNetworkChange); + } + + /** + * Fired when the network changes + * @param config + * @protected + */ + //@ts-ignore + protected onNetworkChange(config: NetworkConfig) {} + /*** * Used to get an identifier string that is consistent across different network connections. * Currently returns the C address of this wallet. @@ -461,12 +486,16 @@ export abstract class WalletProvider { private async updateUnknownAssetsX() { let utxos = this.utxosX.getAllUTXOs(); - for (let i = 0; i < utxos.length; i++) { - let utxo = utxos[i]; - let assetIdBuff = utxo.getAssetID(); - let assetId = bintools.cb58Encode(assetIdBuff); - await getAssetDescription(assetId); - } + let assetIds = utxos.map((utxo) => { + let idBuff = utxo.getAssetID(); + return bintools.cb58Encode(idBuff); + }); + let uniqueIds = assetIds.filter((id, index) => { + return assetIds.indexOf(id) === index; + }); + + let promises = uniqueIds.map((id) => getAssetDescription(id)); + await Promise.all(promises); } /** @@ -1052,7 +1081,7 @@ export abstract class WalletProvider { } async getHistoryC(limit = 0): Promise { - let addrs = [this.getEvmAddressBech()]; + let addrs = [this.getEvmAddressBech(), ...this.getAllAddressesX()]; return await getAddressHistory(addrs, limit, cChain.getBlockchainID()); } @@ -1062,15 +1091,20 @@ export abstract class WalletProvider { } async getHistory(limit: number = 0): Promise { - let txsX = await this.getHistoryX(limit); - let txsP = await this.getHistoryP(limit); - let txsC = await this.getHistoryC(limit); + let [txsX, txsP, txsC] = await Promise.all([ + this.getHistoryX(limit), + this.getHistoryP(limit), + this.getHistoryC(limit), + ]); - let txsXPC = txsX.concat(txsP, txsC); + let txsXPC = filterDuplicateTransactions(txsX.concat(txsP, txsC)); let txsEVM = await this.getHistoryEVM(); - let addrs = this.getAllAddressesX(); + let addrsX = this.getAllAddressesX(); + let addrBechC = this.getEvmAddressBech(); + let addrs = [...addrsX, addrBechC]; + let addrC = this.getAddressC(); // Parse X,P,C transactions @@ -1099,4 +1133,27 @@ export abstract class WalletProvider { } return txsSorted; } + + /** + * Fetches information about the given txId and parses it from the wallet's perspective + * @param txId + */ + async getHistoryTx(txId: string): Promise { + let addrs = this.getAllAddressesX(); + let addrC = this.getAddressC(); + + let rawData = await getTx(txId); + return await getTransactionSummary(rawData, addrs, addrC); + } + + /** + * Fetches information about the given txId and parses it from the wallet's perspective + * @param txHash + */ + async getHistoryTxEvm(txHash: string): Promise { + let addrC = this.getAddressC(); + + let rawData = await getTxEvm(txHash); + return getTransactionSummaryEVM(rawData, addrC); + } } diff --git a/src/Wallet/constants.ts b/src/Wallet/constants.ts index 503f2b44..b40cc409 100644 --- a/src/Wallet/constants.ts +++ b/src/Wallet/constants.ts @@ -3,6 +3,7 @@ // m / purpose' / coin_type' / account' / change / address_index export const AVAX_TOKEN_INDEX: string = '9000'; +export const AVAX_TOKEN_PATH = `m/44'/${AVAX_TOKEN_INDEX}'`; export const AVAX_ACCOUNT_PATH: string = `m/44'/${AVAX_TOKEN_INDEX}'/0'`; // Change and index left out export const ETH_ACCOUNT_PATH: string = `m/44'/60'/0'`; export const LEDGER_ETH_ACCOUNT_PATH = ETH_ACCOUNT_PATH + '/0/0'; diff --git a/src/Wallet/helpers/derivationHelper.ts b/src/Wallet/helpers/derivationHelper.ts new file mode 100644 index 00000000..2c7cd393 --- /dev/null +++ b/src/Wallet/helpers/derivationHelper.ts @@ -0,0 +1,15 @@ +import { AVAX_TOKEN_PATH, ETH_ACCOUNT_PATH } from '@/Wallet/constants'; + +/** + * Given an account number, returns the Avalanche account derivation path as a string + * @param accountIndex + */ +export function getAccountPathAvalanche(accountIndex: number) { + if (accountIndex < 0) throw new Error('Account index can not be less than 0.'); + return `${AVAX_TOKEN_PATH}/${accountIndex}'`; +} + +export function getAccountPathEVM(accountIndex: number) { + if (accountIndex < 0) throw new Error('Account index can not be less than 0.'); + return `${ETH_ACCOUNT_PATH}/0/${accountIndex}`; +} diff --git a/src/index.ts b/src/index.ts index d52c698e..c7267233 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ -export * as Network from '@/Network/index'; -export * as Assets from '@/Asset/index'; +export * as Network from '@/Network'; +export * as Assets from '@/Asset'; export * as Common from './common'; +export * as History from '@/History'; import MnemonicWallet from '@/Wallet/MnemonicWallet'; import SingletonWallet from '@/Wallet/SingletonWallet'; diff --git a/src/utils/fee_utils.ts b/src/utils/fee_utils.ts new file mode 100644 index 00000000..9ac277ba --- /dev/null +++ b/src/utils/fee_utils.ts @@ -0,0 +1,15 @@ +import { pChain, xChain } from '@/Network/network'; + +/** + * Returns the transaction fee for X chain. + */ +export function getTxFeeX() { + return xChain.getTxFee(); +} + +/** + * Returns the transaction fee for P chain. + */ +export function getTxFeeP() { + return pChain.getTxFee(); +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 05f4666d..14dbb9cb 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,2 +1,5 @@ export * from './utils'; export * from './number_utils'; +export * from './fee_utils'; +export * from './price_utils'; +export * from './waitTxUtils'; diff --git a/src/utils/price_utils.ts b/src/utils/price_utils.ts new file mode 100644 index 00000000..d5d9dffb --- /dev/null +++ b/src/utils/price_utils.ts @@ -0,0 +1,16 @@ +import axios from 'axios'; + +const COINGECKO_URL = 'https://api.coingecko.com/api/v3/simple/price?ids=avalanche-2&vs_currencies=usd'; + +/** + * Fetches the current AVAX price using Coin Gecko. + * @remarks + * You might get rate limited if you use this function frequently. + * + * @return + * Current USD price of 1 AVAX + */ +export async function getAvaxPrice(): Promise { + const res = await axios.get(COINGECKO_URL); + return res.data['avalanche-2'].usd; +} diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 89057a37..19657df5 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,33 +1,8 @@ import { Buffer as BufferAvalanche } from 'avalanche'; import { validateAddress } from '@/helpers/address_helper'; import createHash from 'create-hash'; -import axios from 'axios'; -import { cChain, pChain, web3, xChain } from '@/Network/network'; -import { - AvmStatusResponseType, - AvmStatusType, - ChainStatusResponseTypeC, - ChainStatusTypeC, - PlatformStatusResponseType, - PlatformStatusType, -} from '@/utils/types'; import { PayloadBase, PayloadTypes } from 'avalanche/dist/utils'; -const COINGECKO_URL = 'https://api.coingecko.com/api/v3/simple/price?ids=avalanche-2&vs_currencies=usd'; - -/** - * Fetches the current AVAX price using Coin Gecko. - * @remarks - * You might get rate limited if you use this function frequently. - * - * @return - * Current USD price of 1 AVAX - */ -export async function getAvaxPrice(): Promise { - const res = await axios.get(COINGECKO_URL); - return res.data['avalanche-2'].usd; -} - /** * Checks if address is valid. * @@ -46,145 +21,6 @@ export function digestMessage(msgStr: string): Buffer { return createHash('sha256').update(msgBuf).digest(); } -export async function waitTxX(txId: string, tryCount = 10): Promise { - if (tryCount <= 0) { - throw new Error('Timeout'); - } - let resp: AvmStatusResponseType; - - try { - resp = (await xChain.getTxStatus(txId)) as AvmStatusResponseType; - } catch (e) { - throw new Error('Unable to get transaction status.'); - } - - let status: AvmStatusType; - let reason; - if (typeof resp === 'string') { - status = resp as AvmStatusType; - } else { - status = resp.status as AvmStatusType; - reason = resp.reason; - } - - if (status === 'Unknown' || status === 'Processing') { - return await new Promise((resolve) => { - setTimeout(async () => { - resolve(await waitTxX(txId, tryCount - 1)); - }, 1000); - }); - // return await waitTxX(txId, tryCount - 1); - } else if (status === 'Rejected') { - throw new Error(reason); - } else if (status === 'Accepted') { - return txId; - } - - return txId; -} - -export async function waitTxP(txId: string, tryCount = 10): Promise { - if (tryCount <= 0) { - throw new Error('Timeout'); - } - let resp: PlatformStatusResponseType; - - try { - resp = (await pChain.getTxStatus(txId)) as PlatformStatusResponseType; - } catch (e) { - throw new Error('Unable to get transaction status.'); - } - - let status: PlatformStatusType; - let reason; - if (typeof resp === 'string') { - status = resp as PlatformStatusType; - } else { - status = resp.status as PlatformStatusType; - reason = resp.reason; - } - - if (status === 'Unknown' || status === 'Processing') { - return await new Promise((resolve) => { - setTimeout(async () => { - resolve(await waitTxP(txId, tryCount - 1)); - }, 1000); - }); - // return await waitTxX(txId, tryCount - 1); - } else if (status === 'Dropped') { - throw new Error(reason); - } else if (status === 'Committed') { - return txId; - } else { - throw new Error('Unknown status type.'); - } -} - -export async function waitTxEvm(txHash: string, tryCount = 10): Promise { - if (tryCount <= 0) { - throw new Error('Timeout'); - } - - let receipt; - - try { - receipt = await web3.eth.getTransactionReceipt(txHash); - } catch (e) { - throw new Error('Unable to get transaction receipt.'); - } - - if (!receipt) { - return await new Promise((resolve) => { - setTimeout(async () => { - resolve(await waitTxEvm(txHash, tryCount - 1)); - }, 1000); - }); - } else { - if (receipt.status) { - return txHash; - } else { - throw new Error('Transaction reverted.'); - } - } -} - -export async function waitTxC(txId: string, tryCount = 10): Promise { - if (tryCount <= 0) { - throw new Error('Timeout'); - } - - let resp: ChainStatusResponseTypeC; - try { - resp = (await cChain.getAtomicTxStatus(txId)) as ChainStatusResponseTypeC; - } catch (e) { - throw new Error('Unable to get transaction status.'); - } - - let status: ChainStatusTypeC; - let reason; - if (typeof resp === 'string') { - status = resp as ChainStatusTypeC; - } else { - status = resp.status as ChainStatusTypeC; - reason = resp.reason; - } - - if (status === 'Unknown' || status === 'Processing') { - return await new Promise((resolve) => { - setTimeout(async () => { - resolve(await waitTxC(txId, tryCount - 1)); - }, 1000); - }); - // return await waitTxX(txId, tryCount - 1); - } else if (status === 'Dropped') { - throw new Error(reason); - } else if (status === 'Accepted') { - return txId; - } else { - throw new Error('Unknown status type.'); - } -} - let payloadtypes = PayloadTypes.getInstance(); export function parseNftPayload(rawPayload: string): PayloadBase { @@ -197,17 +33,3 @@ export function parseNftPayload(rawPayload: string): PayloadBase { return payloadbase; } - -/** - * Returns the transaction fee for X chain. - */ -export function getTxFeeX() { - return xChain.getTxFee(); -} - -/** - * Returns the transaction fee for P chain. - */ -export function getTxFeeP() { - return pChain.getTxFee(); -} diff --git a/src/utils/waitTxUtils.ts b/src/utils/waitTxUtils.ts new file mode 100644 index 00000000..23011556 --- /dev/null +++ b/src/utils/waitTxUtils.ts @@ -0,0 +1,153 @@ +import { + AvmStatusResponseType, + AvmStatusType, + ChainStatusResponseTypeC, + ChainStatusTypeC, + PlatformStatusResponseType, + PlatformStatusType, +} from '@/utils/types'; +import { cChain, pChain, web3, xChain } from '@/Network/network'; + +/** + * Waits until the given tx id is accepted on X chain + * @param txId Tx ID to wait for + * @param tryCount Number of attempts until timeout + */ +export async function waitTxX(txId: string, tryCount = 10): Promise { + if (tryCount <= 0) { + throw new Error('Timeout'); + } + let resp: AvmStatusResponseType; + + try { + resp = (await xChain.getTxStatus(txId)) as AvmStatusResponseType; + } catch (e) { + throw new Error('Unable to get transaction status.'); + } + + let status: AvmStatusType; + let reason; + if (typeof resp === 'string') { + status = resp as AvmStatusType; + } else { + status = resp.status as AvmStatusType; + reason = resp.reason; + } + + if (status === 'Unknown' || status === 'Processing') { + return await new Promise((resolve) => { + setTimeout(async () => { + resolve(await waitTxX(txId, tryCount - 1)); + }, 1000); + }); + // return await waitTxX(txId, tryCount - 1); + } else if (status === 'Rejected') { + throw new Error(reason); + } else if (status === 'Accepted') { + return txId; + } + + return txId; +} + +export async function waitTxP(txId: string, tryCount = 10): Promise { + if (tryCount <= 0) { + throw new Error('Timeout'); + } + let resp: PlatformStatusResponseType; + + try { + resp = (await pChain.getTxStatus(txId)) as PlatformStatusResponseType; + } catch (e) { + throw new Error('Unable to get transaction status.'); + } + + let status: PlatformStatusType; + let reason; + if (typeof resp === 'string') { + status = resp as PlatformStatusType; + } else { + status = resp.status as PlatformStatusType; + reason = resp.reason; + } + + if (status === 'Unknown' || status === 'Processing') { + return await new Promise((resolve) => { + setTimeout(async () => { + resolve(await waitTxP(txId, tryCount - 1)); + }, 1000); + }); + // return await waitTxX(txId, tryCount - 1); + } else if (status === 'Dropped') { + throw new Error(reason); + } else if (status === 'Committed') { + return txId; + } else { + throw new Error('Unknown status type.'); + } +} + +export async function waitTxEvm(txHash: string, tryCount = 10): Promise { + if (tryCount <= 0) { + throw new Error('Timeout'); + } + + let receipt; + + try { + receipt = await web3.eth.getTransactionReceipt(txHash); + } catch (e) { + throw new Error('Unable to get transaction receipt.'); + } + + if (!receipt) { + return await new Promise((resolve) => { + setTimeout(async () => { + resolve(await waitTxEvm(txHash, tryCount - 1)); + }, 1000); + }); + } else { + if (receipt.status) { + return txHash; + } else { + throw new Error('Transaction reverted.'); + } + } +} + +export async function waitTxC(txId: string, tryCount = 10): Promise { + if (tryCount <= 0) { + throw new Error('Timeout'); + } + + let resp: ChainStatusResponseTypeC; + try { + resp = (await cChain.getAtomicTxStatus(txId)) as ChainStatusResponseTypeC; + } catch (e) { + throw new Error('Unable to get transaction status.'); + } + + let status: ChainStatusTypeC; + let reason; + if (typeof resp === 'string') { + status = resp as ChainStatusTypeC; + } else { + status = resp.status as ChainStatusTypeC; + reason = resp.reason; + } + + if (status === 'Unknown' || status === 'Processing') { + return await new Promise((resolve) => { + setTimeout(async () => { + resolve(await waitTxC(txId, tryCount - 1)); + }, 1000); + }); + // return await waitTxX(txId, tryCount - 1); + } else if (status === 'Dropped') { + throw new Error(reason); + } else if (status === 'Accepted') { + return txId; + } else { + throw new Error('Unknown status type.'); + } +} diff --git a/test/History/base_tx_dumps.ts b/test/History/base_tx_dumps.ts new file mode 100644 index 00000000..d4e62c67 --- /dev/null +++ b/test/History/base_tx_dumps.ts @@ -0,0 +1,1077 @@ +/** + * Simple faucet transaction to wallet + */ +export const BaseTx = `{ + "id": "2u6YndP8MRPtrk1AaVS1JoN9iEBuQxZoHxufk6vSz2bni6nxow", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "base", + "inputs": [ + { + "output": { + "id": "SaQbv8mwt5oSqAXUM3g7FXAkM9z3CeUSSvCGJw32jhLPuBJzV", + "transactionID": "W8dM33U2s2QR8Tqdi3ea9tdKPBhrMs9WKAZqUKLe7LGGzJugx", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "26605873155049800", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1xpmx0ljrpvqexrvrj26fnggvr0ax9wm32gaxmx" + ], + "caddresses": null, + "timestamp": "2021-08-18T18:27:34.845579Z", + "redeemingTransactionID": "2u6YndP8MRPtrk1AaVS1JoN9iEBuQxZoHxufk6vSz2bni6nxow", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1xpmx0ljrpvqexrvrj26fnggvr0ax9wm32gaxmx", + "public_key": "AkKuIDpfbTqIXSudVm7ci3KSzOqna7xEr5vxG2ZlDSEj", + "signature": "vCCvpfAqzq7FxB4vO/N8vM+L9HjYk1j1KHZ61C5qYoUho6xG7zrhRoc+UJTY4mPehdWM+erqM/7ZXOBlG+7S+AE=" + } + ] + } + ], + "outputs": [ + { + "id": "h7aSh7iwQ8RiDD698hAT8WsP9uke1utw5dgyMnh1PZbp5Mo9S", + "transactionID": "2u6YndP8MRPtrk1AaVS1JoN9iEBuQxZoHxufk6vSz2bni6nxow", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "2000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut" + ], + "caddresses": null, + "timestamp": "2021-08-18T18:29:05.642695Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "4cxNsuNiiBLJefyWR1U2bW1Koyt8oLXJNfo36WGzKrJg9zPZz", + "transactionID": "2u6YndP8MRPtrk1AaVS1JoN9iEBuQxZoHxufk6vSz2bni6nxow", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "26605871154049800", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1xpmx0ljrpvqexrvrj26fnggvr0ax9wm32gaxmx" + ], + "caddresses": null, + "timestamp": "2021-08-18T18:29:05.642695Z", + "redeemingTransactionID": "L4zinWPEbsEgAkR6nmGdegJjakAfWtnM1PgrvGUA6XuGncKE3", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "AAtGYXVjZXQgZHJpcA==", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "26605873155049800" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "26605873154049800" + }, + "reusedAddressTotals": null, + "timestamp": "2021-08-18T18:29:05.642695Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "2MRXL6MWXKvckrCfz6PRdf2z6dBDNYJtDnPwcmMf1yBbACWXfg", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; + +export const BaseTx1 = `{ + "id": "evrKDCGkkxVFBhA2u7eL1h91EpjePfW2ynQigSThjSoD9Q2CC", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "base", + "inputs": [ + { + "output": { + "id": "2k14aG1v32sNviQgaXKabzRmc3u3YKNwnLriA5isbZXAMMYiFx", + "transactionID": "25waaV6ATjNUAzSNgnhD5Ehu6tFuKeKHk9y26EgJoFej9FrC2n", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1qgrgzf7c0v7pdpdyucrspd45yp4t5m29plgmm0" + ], + "caddresses": null, + "timestamp": "2021-07-13T04:12:29.14534Z", + "redeemingTransactionID": "evrKDCGkkxVFBhA2u7eL1h91EpjePfW2ynQigSThjSoD9Q2CC", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1qgrgzf7c0v7pdpdyucrspd45yp4t5m29plgmm0", + "public_key": "A1AJ9EreJpoStdTY2BIBGvURS4wiEfM7JQas01b5Nh2n", + "signature": "xEZxQcuC4JSA/glCbJtKHjhyEpZOtsTfGyphsbqkYlU9yMP4xqQ7psL5yXJjJcBiBVHDcYX7quLBwHL/6dDwUgE=" + } + ] + }, + { + "output": { + "id": "cjc5a7RetUabaUg1xEBM4nnjF85ypiPxcRGQKEJaDRu1jqtv1", + "transactionID": "21LsoUj7Dn4PKxvYkWkXrJxoGdcRdHcsb7K8YsxND8QtERFSaD", + "outputIndex": 1, + "assetID": "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "10000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1jq7trjflynjghlc8fv4hktn0f3y4u23shy4cwg" + ], + "caddresses": null, + "timestamp": "2021-07-09T16:18:07.14247Z", + "redeemingTransactionID": "evrKDCGkkxVFBhA2u7eL1h91EpjePfW2ynQigSThjSoD9Q2CC", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1jq7trjflynjghlc8fv4hktn0f3y4u23shy4cwg", + "public_key": "As9AFTB/RD8gm21I3Yn9FShn7BOJFNMi8nMUFfQd2JUI", + "signature": "4LyetKWRLnmVnEpVlb0vMXZX+LrcPHMMu+EHlKvXkO9ofZVOPcII0gKSxLuL4EOLnugW7YH2s+g3hBz99GNO3gE=" + } + ] + } + ], + "outputs": [ + { + "id": "4aksosTZgkzQmcfr9jD7PFkrQHQKLW1FzV9RbHFZGJTg1JtrF", + "transactionID": "evrKDCGkkxVFBhA2u7eL1h91EpjePfW2ynQigSThjSoD9Q2CC", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "999000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1m3ucknu8shqxa2q04jetfrl6jl6j457ddffwj3" + ], + "caddresses": null, + "timestamp": "2021-07-15T07:10:01.243907Z", + "redeemingTransactionID": "iw4AiNDVFJFvTqBGRPXqkTdbJU9FBfgKbWpRXYXk1BhMa1yZS", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "xbDxu6iABUnEzQ5iw5FmkBZSn1CKbmVgigbEjCjEaRGBoTmaK", + "transactionID": "evrKDCGkkxVFBhA2u7eL1h91EpjePfW2ynQigSThjSoD9Q2CC", + "outputIndex": 1, + "assetID": "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "10000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1j4l8kt4jpcnua00m09uv4tssjwj5efv02lm04h" + ], + "caddresses": null, + "timestamp": "2021-07-15T07:10:01.243907Z", + "redeemingTransactionID": "ZxXq4dTep5ZwqN85HrA3LqZGt4KgkeC2p2HEt8JhFc69pixA4", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "1000000000", + "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK": "10000000" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "999000000", + "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK": "10000000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-07-15T07:10:01.243907Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "25YzQpYvYBLudQbgLEvRNQYQH747D2EGiwY37Z3oiME2vR9hHQ", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; + +export const BaseTx2 = `{ + "id": "s27VDftrJ1zq5oit9yqPqcxkPY5hvvCmpDQmU6usGLdjGAqo5", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "base", + "inputs": [ + { + "output": { + "id": "2FGKiLrpfstFrL8ivRjKNHtadn1kUB6yySf9odLcvjkEUTH6EM", + "transactionID": "2sT4zHJc5G3cqYL3j5BD94K88EsZ7w1zVhNZumWGFvs5TbLTFt", + "outputIndex": 1, + "assetID": "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "10000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1gzyk29gqdq95muwlfkllg5ncdwjafrg9att3gp" + ], + "caddresses": null, + "timestamp": "2021-07-09T02:25:06.783673Z", + "redeemingTransactionID": "s27VDftrJ1zq5oit9yqPqcxkPY5hvvCmpDQmU6usGLdjGAqo5", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1gzyk29gqdq95muwlfkllg5ncdwjafrg9att3gp", + "public_key": "AlRK5CopRtK4VaPXq0vyD0+8uyysD2aCiVsJ0H3+qiC5", + "signature": "5nYCDGfWUOakLCzPTUppQW/rrsqoU48bn1ZLkrLixd8YZPH/z8Oc4duwuicVlJX+RMIEfJpPeS1gDeldjuJ99QE=" + } + ] + }, + { + "output": { + "id": "2U7dguRhhZoH2ErKJVcYfoS1PsHpsdn3etQuiT7CHKJ5MYLkea", + "transactionID": "273EU2jGtKwh9897cUJRzHBodVdnhhJu7MzsohnuubVcE8vLCT", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "2000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1pg3nt5gmhu6fwrqslnf4scds675yp0mp24df6v" + ], + "caddresses": null, + "timestamp": "2021-07-09T02:27:03.344925Z", + "redeemingTransactionID": "s27VDftrJ1zq5oit9yqPqcxkPY5hvvCmpDQmU6usGLdjGAqo5", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1pg3nt5gmhu6fwrqslnf4scds675yp0mp24df6v", + "public_key": "ApITfH5stmx6bBCXssyhKTPeLAwODxeuEsfV0I39AGuT", + "signature": "fMyPxGMVt7Vh9vvhdpyx9BC4GSj/VO6ZpuwEazsOXIQTlJ+J57xb5L3zaEw/0WY32p+rOeFnhbNdFdvihzeFPgA=" + } + ] + }, + { + "output": { + "id": "HoXRoEQmJBdqMrwWsYyx4n6kR6P69dUE7bM31myJuQUjguvcQ", + "transactionID": "291jTftUySXp7N4PELQUPJPAP9QvxhTQHGtfSUU8iA42b9R8Bh", + "outputIndex": 1, + "assetID": "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "100000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1gzyk29gqdq95muwlfkllg5ncdwjafrg9att3gp" + ], + "caddresses": null, + "timestamp": "2021-07-09T02:25:34.425492Z", + "redeemingTransactionID": "s27VDftrJ1zq5oit9yqPqcxkPY5hvvCmpDQmU6usGLdjGAqo5", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1gzyk29gqdq95muwlfkllg5ncdwjafrg9att3gp", + "public_key": "AlRK5CopRtK4VaPXq0vyD0+8uyysD2aCiVsJ0H3+qiC5", + "signature": "5nYCDGfWUOakLCzPTUppQW/rrsqoU48bn1ZLkrLixd8YZPH/z8Oc4duwuicVlJX+RMIEfJpPeS1gDeldjuJ99QE=" + } + ] + }, + { + "output": { + "id": "PA6Smq2dM23z5NY6oXVWgiDVe2RbBHt6LuL8Cy3A9YQXKmLRm", + "transactionID": "217n4YewecJTCZYkeQwGSGsq2uHR3kj3sDcsqSvoJ9m4JyVQCk", + "outputIndex": 0, + "assetID": "6h9wgJto7fTCPSbbMxcaSb47pJUQmELiNfB6iAJGHDng93m8t", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1gzyk29gqdq95muwlfkllg5ncdwjafrg9att3gp" + ], + "caddresses": null, + "timestamp": "2021-07-09T02:25:50.843867Z", + "redeemingTransactionID": "s27VDftrJ1zq5oit9yqPqcxkPY5hvvCmpDQmU6usGLdjGAqo5", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1gzyk29gqdq95muwlfkllg5ncdwjafrg9att3gp", + "public_key": "AlRK5CopRtK4VaPXq0vyD0+8uyysD2aCiVsJ0H3+qiC5", + "signature": "5nYCDGfWUOakLCzPTUppQW/rrsqoU48bn1ZLkrLixd8YZPH/z8Oc4duwuicVlJX+RMIEfJpPeS1gDeldjuJ99QE=" + } + ] + } + ], + "outputs": [ + { + "id": "YX5FChTvnqy51n9U3a2HF1wwDMxKE3sZXVEHqtryCKapg4Ebx", + "transactionID": "s27VDftrJ1zq5oit9yqPqcxkPY5hvvCmpDQmU6usGLdjGAqo5", + "outputIndex": 0, + "assetID": "6h9wgJto7fTCPSbbMxcaSb47pJUQmELiNfB6iAJGHDng93m8t", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1qrpc4fdyupsc3jqytxdecw44skuggr4qq2vlpn" + ], + "caddresses": null, + "timestamp": "2021-07-09T02:27:06.906979Z", + "redeemingTransactionID": "7ftDKz7FgJdLwma9EiV9hbnbkCF7qMD7LLZtGH1oYp9rV1xre", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2u8oZuRe69cKvBG57JpRia4PSpGEZ5aEt58GpJw9CoDyeWJFtp", + "transactionID": "s27VDftrJ1zq5oit9yqPqcxkPY5hvvCmpDQmU6usGLdjGAqo5", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1999000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1r2nwwn6zddp79zt3swf9yc7lxxcjjqn9h82xqy" + ], + "caddresses": null, + "timestamp": "2021-07-09T02:27:06.906979Z", + "redeemingTransactionID": "Pr45UGkbk2GygP7UV2BxgUZmk9toY8HJq5dUNxNZzW1Tjtnby", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "Kaf6ZPigYDLEPESVNob3hxL2uQtZqVrhUjzvJ4MUauSBxJy8g", + "transactionID": "s27VDftrJ1zq5oit9yqPqcxkPY5hvvCmpDQmU6usGLdjGAqo5", + "outputIndex": 2, + "assetID": "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "10100000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1qrpc4fdyupsc3jqytxdecw44skuggr4qq2vlpn" + ], + "caddresses": null, + "timestamp": "2021-07-09T02:27:06.906979Z", + "redeemingTransactionID": "Xr1Ng1sfE1mpAX6UQs6nf8dTc5KD7WGouf1yXcEQugUSp76Zn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "YmFjayBhdCB5b3U=", + "inputTotals": { + "6h9wgJto7fTCPSbbMxcaSb47pJUQmELiNfB6iAJGHDng93m8t": "1", + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "2000000000", + "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK": "10100000" + }, + "outputTotals": { + "6h9wgJto7fTCPSbbMxcaSb47pJUQmELiNfB6iAJGHDng93m8t": "1", + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "1999000000", + "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK": "10100000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-07-09T02:27:06.906979Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "2p3FvvSizvwmi1Mazx3fyd3VMZPg91EdQgnMxGBYvFHGWLtSAH", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; + +export const BaseTxSend0 = `{ + "id": "2Ac5CkA7AMYQ8JQve4Wcczppn17LSqfftjLwqxbdNpJiKHXDT2", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "base", + "inputs": [ + { + "output": { + "id": "2kuw6JdsLR1GngQmGx6eNTJTYohwUgFqHCV67hasYbZkWi9jSS", + "transactionID": "GMyMbfHW6bsnGohNN62HAYhWeiHD4GaaPF6LhMg9TDqCoVLgU", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1001000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1euwa0uxz7fcm8edj5fy490fvdj6e3s2mnmxh6p" + ], + "caddresses": null, + "timestamp": "2021-08-16T21:43:02.644735Z", + "redeemingTransactionID": "2Ac5CkA7AMYQ8JQve4Wcczppn17LSqfftjLwqxbdNpJiKHXDT2", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1euwa0uxz7fcm8edj5fy490fvdj6e3s2mnmxh6p", + "public_key": "A139I1I10os1X4TtbPaEiINIxSO2hjPNBHF4+TW7kP5L", + "signature": "2N5lfFv68d3NaK01gJzHhEbgXYcMA3yxZ5EzF62JNw4lDMZ9yopAKJZwh+wxOvis0uAzpZwImTej5QzDV7sCIQE=" + } + ] + } + ], + "outputs": [ + { + "id": "2eAjMJVYqQkzxHFa8xKz8xKf84JTckU2jFeS2pJGz8MRTD8nRY", + "transactionID": "2Ac5CkA7AMYQ8JQve4Wcczppn17LSqfftjLwqxbdNpJiKHXDT2", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1n8vmuvxudfkr7u6vy307jlyuk84nke0nr769zd" + ], + "caddresses": null, + "timestamp": "2021-08-16T21:43:12.614234Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "1001000000" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "1000000000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-08-16T21:43:12.614234Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "28LRvwvSeUATwQotxfYMwhz9EcUm8gKsX8G8ZPKXvk4ber6hCz", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; + +export const BaseTxSend1 = `{ + "id": "UGWnqJQqeyZXEYthEeRgcwVrvMLyPgN6uxMY2cE3eU1YQy6ie", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "base", + "inputs": [ + { + "output": { + "id": "2vi7sgafXoce5w5zCzivZ7jmn74uJwVSoApUPGfF2zgjWosvDL", + "transactionID": "2DYe1mKYfYnXRiF9Npu4hEthMHmsAysWmPNzdRUMbs2dahQh9t", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "5001762000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ysxw3923qapq43pukde9vud4wn84exyzdqletm" + ], + "caddresses": null, + "timestamp": "2021-09-06T08:43:29.217327Z", + "redeemingTransactionID": "UGWnqJQqeyZXEYthEeRgcwVrvMLyPgN6uxMY2cE3eU1YQy6ie", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1ysxw3923qapq43pukde9vud4wn84exyzdqletm", + "public_key": "AsLi0E0HcSFHlZAojEzf0dgaSpyU4jiqefHbSatzxSf9", + "signature": "5Hbi1cp3B295geAVC7KaNQFcF5WcF3YIC3puMHzxS8tHB2VkZ8BXZdcUM91s6CkqpRXvf2iwJkrfUpr8tJ6ZjAA=" + } + ] + } + ], + "outputs": [ + { + "id": "mzkykZH5HxAsJzeNhbgkvAQvmxo8uHc3rbpbUbESdSHsAASwr", + "transactionID": "UGWnqJQqeyZXEYthEeRgcwVrvMLyPgN6uxMY2cE3eU1YQy6ie", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1000000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji17mqelzf3w2l64pmqpxr84na9wmkknn3p3yf0kk" + ], + "caddresses": null, + "timestamp": "2021-09-15T13:50:08.071847Z", + "redeemingTransactionID": "24quLgZ8fNQnYQsn5iTfZbPbLYazKKTFcDhvPwZ2V4HZSG1rEA", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "F3UXVQZYuZ9RWmnCNKP4FBG9DjPjskUg6s624PdyV4PSfyK9s", + "transactionID": "UGWnqJQqeyZXEYthEeRgcwVrvMLyPgN6uxMY2cE3eU1YQy6ie", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "4001761000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1lcx7plqaajp6730hh7pvyk9l3urjm6auxc3fx5" + ], + "caddresses": null, + "timestamp": "2021-09-15T13:50:08.071847Z", + "redeemingTransactionID": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "aGVyZSB5b3UgZ28h", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "5001762000000" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "5001761000000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-09-15T13:50:08.071847Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "2K1bQmwi5YdjyX3e6YR79pbEL6Zqzhq6WJCuv55JqaYP5c4FkJ", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; + +export const BaseTxSend2 = `{ + "id": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "base", + "inputs": [ + { + "output": { + "id": "F3UXVQZYuZ9RWmnCNKP4FBG9DjPjskUg6s624PdyV4PSfyK9s", + "transactionID": "UGWnqJQqeyZXEYthEeRgcwVrvMLyPgN6uxMY2cE3eU1YQy6ie", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "4001761000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1lcx7plqaajp6730hh7pvyk9l3urjm6auxc3fx5" + ], + "caddresses": null, + "timestamp": "2021-09-15T13:50:08.071847Z", + "redeemingTransactionID": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1lcx7plqaajp6730hh7pvyk9l3urjm6auxc3fx5", + "public_key": "A0rs4f4BNQ1QfZWiUQnBTc/+Vmbi2vaFIwZRGeHmF0ax", + "signature": "nxZlfVsj8dzF0amo4Mt/oamCa1ULgcn7OEIhWiRidGYObG5uSaMV05ooA6Vhd2ohTN/AVWFAzIwXIMg1YNBDigA=" + } + ] + }, + { + "output": { + "id": "ReuWvvQB2nXf17ZXtZz1h8ug7FN9uiCo5kEhDTfGMdzWsNjvJ", + "transactionID": "2DYe1mKYfYnXRiF9Npu4hEthMHmsAysWmPNzdRUMbs2dahQh9t", + "outputIndex": 2, + "assetID": "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "3817541", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ysxw3923qapq43pukde9vud4wn84exyzdqletm" + ], + "caddresses": null, + "timestamp": "2021-09-06T08:43:29.217327Z", + "redeemingTransactionID": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1ysxw3923qapq43pukde9vud4wn84exyzdqletm", + "public_key": "AsLi0E0HcSFHlZAojEzf0dgaSpyU4jiqefHbSatzxSf9", + "signature": "BOsV32S/Rd4mf3UzNkWYAZA4LelBL0ri0JElfUdrhHU1l5keKHj5mR6xUwx3kRi/1RY2bzDQp96uZ6lwEAjHMgE=" + } + ] + }, + { + "output": { + "id": "sh9WLURqBHVGAPc5hfLYgxufZaAjTT5E1W5gGMxfWJNK14ujH", + "transactionID": "2Lcf2wiYbha8t4QeF4EJAPnVNePLbVrnbWrvMXDeicR9eKPbeB", + "outputIndex": 0, + "assetID": "LqfL9CxJxSkKS5Ci2zWxs76i3mVYaeUDvwJgxAenVjXYkhZ9W", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "9000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji19p54jf6y50yn3e8c5lvuuwkumx3yjx762q6t6w" + ], + "caddresses": null, + "timestamp": "2021-08-12T17:35:48.042127Z", + "redeemingTransactionID": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji19p54jf6y50yn3e8c5lvuuwkumx3yjx762q6t6w", + "public_key": "A+1GgB8XYZE3/1kx5hBZky/6tfB5LLUWBhAlslm7r7Cp", + "signature": "sC4QRqd1vPqyJ0NBNDhD1l9ie598D+kvbnG5nGHnsrs1J0hxEL+YxXKL9N8FXVxSOAG2G5Af4J14sRsidLLwTAA=" + } + ] + } + ], + "outputs": [ + { + "id": "4b6FQJujB6FBHqJ9zzeQRyhSKMWDTHRTfak5mgVi4ueMjB6Ts", + "transactionID": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "outputIndex": 1, + "assetID": "LqfL9CxJxSkKS5Ci2zWxs76i3mVYaeUDvwJgxAenVjXYkhZ9W", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "8000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji17g00lgxz4a0s8z5jn9t36pqapmrqnkn9f8hjh5" + ], + "caddresses": null, + "timestamp": "2021-09-21T14:52:56.720829Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2hRy3WYCtGxr4JARVkJ66LcyhA26enrN6h4Hr1E9Ku1HTASkf5", + "transactionID": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "4001760000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji17g00lgxz4a0s8z5jn9t36pqapmrqnkn9f8hjh5" + ], + "caddresses": null, + "timestamp": "2021-09-21T14:52:56.720829Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2tk8vNpvFym1M7BaF5WggHxvWZbVc3U3qudRZrmE8A3espTe9m", + "transactionID": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "outputIndex": 3, + "assetID": "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1x2qdqnkq5tt2j23c3569zffula30h5e0qxklu6" + ], + "caddresses": null, + "timestamp": "2021-09-21T14:52:56.720829Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2Z3ViuoGX7z5SM9BTYSdq9gHk5B4RsUF7hyeW3AfLDHhRE7MZc", + "transactionID": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "outputIndex": 4, + "assetID": "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "2817541", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji17g00lgxz4a0s8z5jn9t36pqapmrqnkn9f8hjh5" + ], + "caddresses": null, + "timestamp": "2021-09-21T14:52:56.720829Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "756rMW7C42LPEsurbzcrpUdEufHdwJwFqXvQcwWoBwUExQ63T", + "transactionID": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "outputIndex": 0, + "assetID": "LqfL9CxJxSkKS5Ci2zWxs76i3mVYaeUDvwJgxAenVjXYkhZ9W", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1x2qdqnkq5tt2j23c3569zffula30h5e0qxklu6" + ], + "caddresses": null, + "timestamp": "2021-09-21T14:52:56.720829Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "SGkgRGFubnkh", + "inputTotals": { + "LqfL9CxJxSkKS5Ci2zWxs76i3mVYaeUDvwJgxAenVjXYkhZ9W": "9000", + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "4001761000000", + "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK": "3817541" + }, + "outputTotals": { + "LqfL9CxJxSkKS5Ci2zWxs76i3mVYaeUDvwJgxAenVjXYkhZ9W": "9000", + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "4001760000000", + "wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK": "3817541" + }, + "reusedAddressTotals": null, + "timestamp": "2021-09-21T14:52:56.720829Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "29daHkc3c7EStqpw1vxzHkAbhBG157ywa8qJENc3uzbsxJNJ7Q", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; diff --git a/test/History/export_dumps.ts b/test/History/export_dumps.ts new file mode 100644 index 00000000..b32549bf --- /dev/null +++ b/test/History/export_dumps.ts @@ -0,0 +1,927 @@ +export const ExportTx = `{ + "id": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "export", + "inputs": [ + { + "output": { + "id": "vz89wQkEvPkTuZCQNJZ4DX4Jd5UsDJCMM7WBgHcVLLbVv9rA9", + "transactionID": "2KL4TfCKyHYMxGfWSZkXpurYiDzwk9sASAH47RMikk53cZNNuY", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "10000000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1nqz4gndscpdp6yr326sz0afdlylcj0g6mf0q46" + ], + "caddresses": null, + "timestamp": "2021-09-22T21:09:22.140212Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1nqz4gndscpdp6yr326sz0afdlylcj0g6mf0q46", + "public_key": "Aq+k4JtTmzlCtC8uU9ENcPEWgjGYFCfzcdQXDtr4IlT7", + "signature": "X8SwEoqBv7/PBowHRoe0eQ2s2JhcyLLItwbohORAkC88LYGCJvsnwqI+RXk+nNkD/R1W+HZAabKRykDGDS2kKQA=" + } + ] + }, + { + "output": { + "id": "xvGiZxcY2VgDFvErwE8xev6im9hvkxZErQwjuWuVhnPyfdZju", + "transactionID": "zahiUZvaKBmKL7EwKbcozZ5kckhigKdF63dcgmxYUJT5muM7d", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji190pd0vlcwwh4hznsuv3k0hha2udvq60urx59e2" + ], + "caddresses": null, + "timestamp": "2021-09-02T21:01:20.875899Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji190pd0vlcwwh4hznsuv3k0hha2udvq60urx59e2", + "public_key": "A3TsgMMoUvS+cO8+LmKCg50SYK7r3KQJeeztglCvZe7r", + "signature": "XG4asBpGWrkh1YrvruKC2WO+eqHBfZgaDXlKmglWirE/L2vzFy2f7AN/cNGqiFAvMt8Ti55xCoFQHcxx/VsHYAE=" + } + ] + }, + { + "output": { + "id": "21XwRbMeC9kpjkzNQAdzhVCB61wrKwnvcW44N1SBzx1FvAKGC6", + "transactionID": "1QiuY4o3acMUSH6wh19mxXcy5d4krzu5cpXA7kXwfGke8WJct", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "8411000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1vwsj9la257kmmetu0dvlkpxgd3d4q8mrl7gltj" + ], + "caddresses": null, + "timestamp": "2021-09-03T22:19:30.517533Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1vwsj9la257kmmetu0dvlkpxgd3d4q8mrl7gltj", + "public_key": "A7jmmdCwC/dX86RwJXwQMSKdINEr4keru9rNMi429olZ", + "signature": "RcpEpEzfwsNMcGHllaNM/eq9DNjBesvQoDbodGLY7a16VgZCEXbzhGTPmmHjmDue2ej4AAsJ4WSZgNRepVT58wE=" + } + ] + }, + { + "output": { + "id": "2hRy3WYCtGxr4JARVkJ66LcyhA26enrN6h4Hr1E9Ku1HTASkf5", + "transactionID": "ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "4001760000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji17g00lgxz4a0s8z5jn9t36pqapmrqnkn9f8hjh5" + ], + "caddresses": null, + "timestamp": "2021-09-21T14:52:56.720829Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji17g00lgxz4a0s8z5jn9t36pqapmrqnkn9f8hjh5", + "public_key": "A93gN62RxBUf7ih2e8kq6xlI+aPP3Z+4Sr3vTMKz3b/p", + "signature": "Mi9IJPjfFCh0WUZEuk1yH3cT80rp4959BmxBkeGmX+xRDN9Fh7IBG8a2O8eZmMj5kgE4r4Twe7fVKDr+NMTrKQA=" + } + ] + }, + { + "output": { + "id": "2mEJ6AfE1csM5tv8zMNoZuNckkdWRmxrRpABuGxxmYFnLyMmSf", + "transactionID": "73gpkB6fU2yeGNfyJWKN71uq579bdQgMoDTN3WD2s71paU7tx", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "2000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji12c7g3nzk8dwgk2l9h4p4z70d9f4ejvm0shdtv9" + ], + "caddresses": null, + "timestamp": "2021-09-02T21:40:16.226479Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji12c7g3nzk8dwgk2l9h4p4z70d9f4ejvm0shdtv9", + "public_key": "A5RX3K3duUhEsHb9xuJmk7vB9FVOGCronQnTLyG7tmnF", + "signature": "1ao/rDih7fJSmysPM8H7xnstkzHanZyIIMQFd9UnZwJuo4j02qw94OG+EuD5QNgzW9+Tl9yfOeg+NVV8J5tgGAE=" + } + ] + }, + { + "output": { + "id": "Rp83KCcgYuLsFD14bpDc4i84JgRjSKRrYKjBqC5RCLETqcsSS", + "transactionID": "1QiuY4o3acMUSH6wh19mxXcy5d4krzu5cpXA7kXwfGke8WJct", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "12322000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1vwsj9la257kmmetu0dvlkpxgd3d4q8mrl7gltj" + ], + "caddresses": null, + "timestamp": "2021-09-03T22:19:30.517533Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1vwsj9la257kmmetu0dvlkpxgd3d4q8mrl7gltj", + "public_key": "A7jmmdCwC/dX86RwJXwQMSKdINEr4keru9rNMi429olZ", + "signature": "RcpEpEzfwsNMcGHllaNM/eq9DNjBesvQoDbodGLY7a16VgZCEXbzhGTPmmHjmDue2ej4AAsJ4WSZgNRepVT58wE=" + } + ] + }, + { + "output": { + "id": "vAnexNj6P6TeSuB1Pvx96QUSXAdEhE5S4pQk6MNo3EpU4oCud", + "transactionID": "2bpSrGt93unJL5bHGZx89zWPKyGmHTP3FX48Sj5dhAjm9LQJ4D", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "2000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1q5ajr6ukr5ymepcnu2kp6ww6g0mk4gu52smrra" + ], + "caddresses": null, + "timestamp": "2021-09-02T21:31:47.61453Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1q5ajr6ukr5ymepcnu2kp6ww6g0mk4gu52smrra", + "public_key": "A80rOZyw78ExdXaUKlM24/QJDzirZRg5+h3ZkpC4lCGi", + "signature": "sSz5RDxViNBq7+KHivGqoraz1fm7LdrgaR4JSjGEn8kiepuf5mTOfdd5EAutuA3rDua3gpUHOjakGA6KzB/hJwE=" + } + ] + }, + { + "output": { + "id": "9qVc1GP8gjh6TzGWdzyBrz6qVhkv6ehxX4HrKHEDVa98hRHy6", + "transactionID": "1QiuY4o3acMUSH6wh19mxXcy5d4krzu5cpXA7kXwfGke8WJct", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "2140000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1vwsj9la257kmmetu0dvlkpxgd3d4q8mrl7gltj" + ], + "caddresses": null, + "timestamp": "2021-09-03T22:19:30.517533Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1vwsj9la257kmmetu0dvlkpxgd3d4q8mrl7gltj", + "public_key": "A7jmmdCwC/dX86RwJXwQMSKdINEr4keru9rNMi429olZ", + "signature": "RcpEpEzfwsNMcGHllaNM/eq9DNjBesvQoDbodGLY7a16VgZCEXbzhGTPmmHjmDue2ej4AAsJ4WSZgNRepVT58wE=" + } + ] + }, + { + "output": { + "id": "LzRb7zvCRsk7zpGNELgfQW5JTVbmsFZjgWbj4att1x4uepSCu", + "transactionID": "1QiuY4o3acMUSH6wh19mxXcy5d4krzu5cpXA7kXwfGke8WJct", + "outputIndex": 3, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "21401000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1vwsj9la257kmmetu0dvlkpxgd3d4q8mrl7gltj" + ], + "caddresses": null, + "timestamp": "2021-09-03T22:19:30.517533Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1vwsj9la257kmmetu0dvlkpxgd3d4q8mrl7gltj", + "public_key": "A7jmmdCwC/dX86RwJXwQMSKdINEr4keru9rNMi429olZ", + "signature": "RcpEpEzfwsNMcGHllaNM/eq9DNjBesvQoDbodGLY7a16VgZCEXbzhGTPmmHjmDue2ej4AAsJ4WSZgNRepVT58wE=" + } + ] + } + ], + "outputs": [ + { + "id": "UmbKbDiMZ1utJfnLmagxaMtYV7nQJNwnJAks7ttApGZSkohMZ", + "transactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "4051032000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1y7704g80palshkd97sz67ggjmvmd55y8mpalrk" + ], + "caddresses": null, + "timestamp": "2021-09-22T21:09:47.384225Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "dDzU5MHPERUrNGqa9Z78nHwTaqAYMCaqVByHDe6Hqyovs73jc", + "transactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "10000001000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1wukmzzjqn5hwsp4uaswc4c53gc0xz5asvxcujf" + ], + "caddresses": null, + "timestamp": "2021-09-22T21:09:47.384225Z", + "redeemingTransactionID": "27MWgoFkhpwutMpBk2mh9sbQXkevzQgX8v26v41XXUckq7Kiqe", + "chainID": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "14051034000000" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "14051033000000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-09-22T21:09:47.384225Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "oqTJQZ3hp54ydbgChTCNuw4uQME82Gy4MAKWiDFZxL3xiACQV", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; + +export const ExportTx1 = `{ + "id": "2m1z8gQoJfUcRHdrRTAJxnqZ1M1WiavFhvYUjjkUceywVt2mNW", + "chainID": "11111111111111111111111111111111LpoYY", + "type": "pvm_export", + "inputs": [ + { + "output": { + "id": "RV6H8ap9kxgiC2V7yFPcaEpmhaayyhNRpM8w55qtaBtWuDLZw", + "transactionID": "2emeLGwi6zB9UCSR8Z8tM4XgfcAjSsGB95ocPocftSt3dPkKZ8", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "106611041", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut" + ], + "caddresses": null, + "timestamp": "2021-09-01T20:59:00.619712Z", + "redeemingTransactionID": "2m1z8gQoJfUcRHdrRTAJxnqZ1M1WiavFhvYUjjkUceywVt2mNW", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": true + }, + "credentials": [ + { + "address": "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut", + "public_key": "AwOdFp8XEexWOSRM5t7c/l1naPJUGFEMRFGIF1ySrbC0", + "signature": "K0byWZupAOq99qJNpbWh1IE4LxOwrfjWgnEFKwe7OW4qlSFEdwVMOGEMU5Uc6xYKnWgH14wAmOOjIqKOfSxOigE=" + } + ] + }, + { + "output": { + "id": "tFAz572uQnRYDgK1rwqao54EKPBGjyRrmuiEXGpE1rF5AgggJ", + "transactionID": "2emeLGwi6zB9UCSR8Z8tM4XgfcAjSsGB95ocPocftSt3dPkKZ8", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut" + ], + "caddresses": null, + "timestamp": "2020-10-25T19:19:08Z", + "redeemingTransactionID": "2m1z8gQoJfUcRHdrRTAJxnqZ1M1WiavFhvYUjjkUceywVt2mNW", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut", + "public_key": "AwOdFp8XEexWOSRM5t7c/l1naPJUGFEMRFGIF1ySrbC0", + "signature": "K0byWZupAOq99qJNpbWh1IE4LxOwrfjWgnEFKwe7OW4qlSFEdwVMOGEMU5Uc6xYKnWgH14wAmOOjIqKOfSxOigE=" + } + ] + }, + { + "output": { + "id": "2dEcBZi1z4aL6LBd4iytLYVT5zc2dkvFqQgPyVGj5vK9gv5N9X", + "transactionID": "mNjgdZ1CQ3VXPNqqNc6LKmXHvwotVLHwQzq26w8we5Ds79WUA", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "349000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut" + ], + "caddresses": null, + "timestamp": "2021-08-09T18:20:45.550026Z", + "redeemingTransactionID": "2m1z8gQoJfUcRHdrRTAJxnqZ1M1WiavFhvYUjjkUceywVt2mNW", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut", + "public_key": "AwOdFp8XEexWOSRM5t7c/l1naPJUGFEMRFGIF1ySrbC0", + "signature": "K0byWZupAOq99qJNpbWh1IE4LxOwrfjWgnEFKwe7OW4qlSFEdwVMOGEMU5Uc6xYKnWgH14wAmOOjIqKOfSxOigE=" + } + ] + }, + { + "output": { + "id": "2ktUFm4MpQCSS8cFknfkytd5VbWY9mctzaTGsLcNEhntdby4K6", + "transactionID": "2DdDGiAtPNSvgkVcaYDawj6RGaaiyY4baka4SwagrCK8zU4bhf", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "639065398", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1up8efmcantt63mwkvfe888qegxdpepfu6dpr9p" + ], + "caddresses": null, + "timestamp": "2021-08-16T17:34:56.789952Z", + "redeemingTransactionID": "2m1z8gQoJfUcRHdrRTAJxnqZ1M1WiavFhvYUjjkUceywVt2mNW", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1up8efmcantt63mwkvfe888qegxdpepfu6dpr9p", + "public_key": "ArWQXS0Pxc7n1x74NnLXlg31c8E1jT0GP2JyNj3XCkq3", + "signature": "NshELQYSyaT/7Qfv2Q05YFrQj5OfzA+gXWBYhYwQDchNcVtSUbUAQNPkjulugIgU0psASurI+odTHG6wNPjw3wE=" + } + ] + }, + { + "output": { + "id": "2oYUk9q1i9PnQphPhayuXyCDMvePbjTrG7tQVwk3SJ7Ere7CiW", + "transactionID": "q2SD2bKbCKdXEYui1LR8vsb7Q3hFsQfTgqc4MSv5hWgQvDqjW", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "5000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut" + ], + "caddresses": null, + "timestamp": "2020-10-25T19:19:08Z", + "redeemingTransactionID": "2m1z8gQoJfUcRHdrRTAJxnqZ1M1WiavFhvYUjjkUceywVt2mNW", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut", + "public_key": "AwOdFp8XEexWOSRM5t7c/l1naPJUGFEMRFGIF1ySrbC0", + "signature": "K0byWZupAOq99qJNpbWh1IE4LxOwrfjWgnEFKwe7OW4qlSFEdwVMOGEMU5Uc6xYKnWgH14wAmOOjIqKOfSxOigE=" + } + ] + }, + { + "output": { + "id": "2qAUwMFAZm5NxJR6hVMFE5CwaGUuD1EXDn1dsGpArJAEcF13W", + "transactionID": "q2SD2bKbCKdXEYui1LR8vsb7Q3hFsQfTgqc4MSv5hWgQvDqjW", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "529847865", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut" + ], + "caddresses": null, + "timestamp": "2021-08-30T23:59:00.814969Z", + "redeemingTransactionID": "2m1z8gQoJfUcRHdrRTAJxnqZ1M1WiavFhvYUjjkUceywVt2mNW", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": true + }, + "credentials": [ + { + "address": "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut", + "public_key": "AwOdFp8XEexWOSRM5t7c/l1naPJUGFEMRFGIF1ySrbC0", + "signature": "K0byWZupAOq99qJNpbWh1IE4LxOwrfjWgnEFKwe7OW4qlSFEdwVMOGEMU5Uc6xYKnWgH14wAmOOjIqKOfSxOigE=" + } + ] + } + ], + "outputs": [ + { + "id": "2VLYrQfHFgig83CgFVHBHX5gyRLyJDPc7Sqv2QS4zffSyuT8mD", + "transactionID": "2m1z8gQoJfUcRHdrRTAJxnqZ1M1WiavFhvYUjjkUceywVt2mNW", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "347073524304", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1kh5aznz5axhew258mjulrx3ne6t2qudnewqfen" + ], + "caddresses": null, + "timestamp": "2021-09-03T22:35:11.065311Z", + "redeemingTransactionID": "Kzhv5zDBEvtFoMFyfbwauppBBULctQ81QkHwqTVRwfykbYVWY", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "9cTydcVRri4MAZUsARmFSkXwZFTATDDb44QW68hr5UCGbEDAV", + "transactionID": "2m1z8gQoJfUcRHdrRTAJxnqZ1M1WiavFhvYUjjkUceywVt2mNW", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "9201000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji15l87xul3ewrevmkcstyn3sed8nxf2y38sjau75" + ], + "caddresses": null, + "timestamp": "2021-09-03T22:35:11.065311Z", + "redeemingTransactionID": "WDkzbbmwaMaZUrB9MMh1JT9m3oi3HsdT6XWMVZRWTywKn6ah4", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "356275524304" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "356274524304" + }, + "reusedAddressTotals": null, + "timestamp": "2021-09-03T22:35:11.065311Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "nJwpDEHyuYZuyRmR1ne2cWo6PzVrjJqXb4eEGns8cVPaQfGy5" +}`; + +export const ExportTx2 = `{ + "id": "2Ruvbqg9F4T5yv4gC4Y4FU6zecETbmHHqfNUFDv1JU5cqCzDqh", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "export", + "inputs": [ + { + "output": { + "id": "nSDtdH49PAnrtnhxEcLDJUMuFtGA7CqHGcy1qZDPTgrCiDLoK", + "transactionID": "v9CbENRBqzmSCEMtU9exC6puZ7wEeqSfSd8JXePMVVsRf9nmL", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1001000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1zenmzsrswjd6fd2f5a76c5gkzhnrwfxezemkgz" + ], + "caddresses": null, + "timestamp": "2021-10-04T14:57:04.345033Z", + "redeemingTransactionID": "2Ruvbqg9F4T5yv4gC4Y4FU6zecETbmHHqfNUFDv1JU5cqCzDqh", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1zenmzsrswjd6fd2f5a76c5gkzhnrwfxezemkgz", + "public_key": "A+SLtFLS0crVvgwZZBd1r+DrhDIGlV4PXZIqDhflKDU0", + "signature": "TQB6M2I+seX4kkySGyoUyc84IMimr+N2WkB1pfK1baJGnpqKNN4dQMmS9glulB0BhD/CLOQBvB1KcvojjQ3M/AE=" + } + ] + } + ], + "outputs": [ + { + "id": "i8HskcN7TvX1aFmrMQaZwpSjsqFAzZTeFsM1ApHYGp2BpkE3r", + "transactionID": "2Ruvbqg9F4T5yv4gC4Y4FU6zecETbmHHqfNUFDv1JU5cqCzDqh", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji138lyu5lw7uln54lnjec25e9wacm8q6xw752zyr" + ], + "caddresses": null, + "timestamp": "2021-10-04T14:57:32.547869Z", + "redeemingTransactionID": "FR6A2NqGq6ACkM2NyCv4yhXqfAJwn3imJQQ4CNYvnnsQYNHuk", + "chainID": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "1001000000" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "1000000000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-10-04T14:57:32.547869Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "2HYF1P2h5dK4a3RaD6xnAbXys1GMwWhZ7wQqP9qWTVe7JbNC2q", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; + +export const ExportTx3 = `{ + "id": "iKVmtwcNSHtJxXzMNsiDZEsJKh6eB63fzkkTBH6e4nVetYQgn", + "chainID": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", + "type": "atomic_export_tx", + "inputs": [ + { + "output": { + "id": "rY1je3vwnquM7aRanSjBUH8eddhB3j3pC7SsKKM3o5PWxkW12", + "transactionID": "iKVmtwcNSHtJxXzMNsiDZEsJKh6eB63fzkkTBH6e4nVetYQgn", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 4294967281, + "amount": "2002000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 0, + "addresses": null, + "caddresses": [ + "0x5f658A6d1928c39B286b48192FEA8d46D87AD077" + ], + "timestamp": "2021-09-02T21:41:08.039765Z", + "redeemingTransactionID": "", + "chainID": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", + "inChainID": "", + "outChainID": "", + "groupID": 0, + "payload": null, + "block": "1051793", + "nonce": 322, + "rewardUtxo": false + }, + "credentials": null + } + ], + "outputs": [ + { + "id": "rY1je3vwnquM7aRanSjBUH8eddhB3j3pC7SsKKM3o5PWxkW12", + "transactionID": "iKVmtwcNSHtJxXzMNsiDZEsJKh6eB63fzkkTBH6e4nVetYQgn", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "2001000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1mnnsf9zftcud4cky8f2ctxaapnr9hfchnw9zjv" + ], + "caddresses": null, + "timestamp": "2021-09-02T21:41:08.039765Z", + "redeemingTransactionID": "ZbbYVDcinx58Pq2fBD7P1mysZeEaoBP1az31iRyv8d6Cs3cpv", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": {}, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "2001000000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-09-02T21:41:08.039765Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; diff --git a/test/History/history.test.ts b/test/History/history.test.ts new file mode 100644 index 00000000..f139f714 --- /dev/null +++ b/test/History/history.test.ts @@ -0,0 +1,386 @@ +import { + ITransactionData, + getTransactionSummary, + iHistoryImportExport, + iHistoryBaseTx, + iHistoryStaking, + isHistoryImportExportTx, +} from '@/History'; +import { ImportTransaction, ImportTx1 } from './import_dumps'; +import { ExportTx, ExportTx1, ExportTx2, ExportTx3 } from './export_dumps'; +import { BaseTx, BaseTx1, BaseTx2, BaseTxSend0, BaseTxSend1, BaseTxSend2 } from './base_tx_dumps'; +import { StakeTx0, StakeTx1, StakeTx2, StakeTx3 } from './staking_dumps'; + +jest.mock('@/Network', () => { + return { + getAvaxAssetID: jest.fn().mockImplementation(() => { + return 'U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK'; + }), + }; +}); + +jest.mock('@/Network/helpers/aliasFromNetworkID', () => { + return { + idToChainAlias: jest.fn().mockImplementation((id: string) => { + switch (id) { + case '2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm': + return 'X'; + case '11111111111111111111111111111111LpoYY': + return 'P'; + case 'yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp': + return 'C'; + } + throw new Error('Unknown chain id.'); + }), + }; +}); + +jest.mock('@/Asset/Assets', () => { + return { + getAssetDescription: jest.fn().mockImplementation((id: string) => { + switch (id) { + // AVAX + case 'U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK': + return { + assetID: 'U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK', + name: 'Avalanche', + symbol: 'AVAX', + denomination: 9, + }; + case 'wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK': + return { + assetID: 'wxTqKYimwaGNsvnk7WBRq3FyattSuYfoWwrwXvHsEw7QnHhjK', + name: 'Wrapped Ethereum XETH', + symbol: 'XETH', + denomination: 9, + }; + case '6h9wgJto7fTCPSbbMxcaSb47pJUQmELiNfB6iAJGHDng93m8t': + return { + assetID: '6h9wgJto7fTCPSbbMxcaSb47pJUQmELiNfB6iAJGHDng93m8t', + name: 'Wrapped Bitcoin XBTC', + symbol: 'XBTC', + denomination: 8, + }; + case 'LqfL9CxJxSkKS5Ci2zWxs76i3mVYaeUDvwJgxAenVjXYkhZ9W': + return { + assetID: 'LqfL9CxJxSkKS5Ci2zWxs76i3mVYaeUDvwJgxAenVjXYkhZ9W', + name: 'Wrapped Bitcoin', + symbol: 'WBTC', + denomination: 8, + }; + } + + throw new Error('Unknown asset id.'); + }), + }; +}); + +describe('Import Tx', () => { + it('single utxo import, all belong to wallet. P to X', async () => { + let data: ITransactionData = JSON.parse(ImportTransaction); + const myAddresses = ['X-fuji1nqz4gndscpdp6yr326sz0afdlylcj0g6mf0q46']; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = await getTransactionSummary(data, myAddresses, cAddr); + + if (isHistoryImportExportTx(summary)) { + expect(summary.id).toEqual('2KL4TfCKyHYMxGfWSZkXpurYiDzwk9sASAH47RMikk53cZNNuY'); + expect(summary.type).toEqual('import'); + expect(summary.source).toEqual('P'); + expect(summary.destination).toEqual('X'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.amount.toString()).toEqual('10000000000000'); + } else { + throw new Error('Type guard failed.'); + } + }); + + it('multiple import utxos, P to X', async () => { + let data: ITransactionData = JSON.parse(ImportTx1); + const myAddresses = [ + 'X-fuji1mj2x9eecn68weljg3tfaszem6hfx8yyq2kve2a', + 'X-fuji16spahfywxkm2jw0nmag8wdaymg76cccw3hpr5g', + 'X-fuji170mcu46k2rctpzrpe5vgk6nchhzfxt40kgcd2s', + 'X-fuji1kh2tklylfqg3fg2audd53kf2zdnrhamcac0hjk', + ]; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryImportExport; + + expect(summary.id).toEqual('Gnvid4y5ZMW3FFW4r46i9F9tGW81p3q3c4WL6sy3223fRXbM3'); + expect(summary.type).toEqual('import'); + expect(summary.source).toEqual('P'); + expect(summary.destination).toEqual('X'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.amount.toString()).toEqual('3002000000'); + }); +}); + +describe('Export Tx', () => { + it('multiple utxo export to C chain, all belong to wallet', async () => { + let data: ITransactionData = JSON.parse(ExportTx); + const myAddresses = [ + 'X-fuji1y7704g80palshkd97sz67ggjmvmd55y8mpalrk', + 'C-fuji1wukmzzjqn5hwsp4uaswc4c53gc0xz5asvxcujf', + ]; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryImportExport; + + expect(summary.id).toEqual('sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn'); + expect(summary.type).toEqual('export'); + expect(summary.source).toEqual('X'); + expect(summary.destination).toEqual('C'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.amount.toString()).toEqual('10000001000000'); + }); + + it('multiple utxos, P to X, with change utxo', async () => { + let data: ITransactionData = JSON.parse(ExportTx1); + const myAddresses = [ + 'X-fuji15l87xul3ewrevmkcstyn3sed8nxf2y38sjau75', + 'P-fuji1kh5aznz5axhew258mjulrx3ne6t2qudnewqfen', + 'P-fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut', + 'P-fuji1up8efmcantt63mwkvfe888qegxdpepfu6dpr9p', + ]; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryImportExport; + + expect(summary.id).toEqual('2m1z8gQoJfUcRHdrRTAJxnqZ1M1WiavFhvYUjjkUceywVt2mNW'); + expect(summary.type).toEqual('export'); + expect(summary.source).toEqual('P'); + expect(summary.destination).toEqual('X'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.amount.toString()).toEqual('9201000000'); + }); + + it('single utxo, X to C', async () => { + let data: ITransactionData = JSON.parse(ExportTx2); + const myAddresses = [ + 'X-fuji1zenmzsrswjd6fd2f5a76c5gkzhnrwfxezemkgz', + 'C-fuji138lyu5lw7uln54lnjec25e9wacm8q6xw752zyr', + ]; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryImportExport; + + expect(summary.id).toEqual('2Ruvbqg9F4T5yv4gC4Y4FU6zecETbmHHqfNUFDv1JU5cqCzDqh'); + expect(summary.type).toEqual('export'); + expect(summary.source).toEqual('X'); + expect(summary.destination).toEqual('C'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.amount.toString()).toEqual('1000000000'); + }); + + it('export C to X, single utxo', async () => { + let data: ITransactionData = JSON.parse(ExportTx3); + const myAddresses = ['X-fuji1mnnsf9zftcud4cky8f2ctxaapnr9hfchnw9zjv']; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryImportExport; + + expect(summary.id).toEqual('iKVmtwcNSHtJxXzMNsiDZEsJKh6eB63fzkkTBH6e4nVetYQgn'); + expect(summary.type).toEqual('export'); + expect(summary.source).toEqual('C'); + expect(summary.destination).toEqual('X'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.amount.toString()).toEqual('2001000000'); + }); +}); + +describe('Base Transaction Receive', () => { + it('Simple receive AVAX, faucet drip', async () => { + let data: ITransactionData = JSON.parse(BaseTx); + const myAddresses = ['X-fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut']; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryBaseTx; + + expect(summary.id).toEqual('2u6YndP8MRPtrk1AaVS1JoN9iEBuQxZoHxufk6vSz2bni6nxow'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.type).toEqual('transaction'); + expect(summary.tokens.length).toEqual(1); + // expect(summary.tokens[0].isSent).toEqual(false) + expect(summary.tokens[0].amount.toString()).toEqual('2000000000'); + expect(summary.tokens[0].amountDisplayValue).toEqual('2'); + expect(summary.tokens[0].addresses).toEqual(['fuji1xpmx0ljrpvqexrvrj26fnggvr0ax9wm32gaxmx']); + }); + + it('Receive single ANT token', async () => { + let data: ITransactionData = JSON.parse(BaseTx1); + const myAddresses = ['X-fuji1j4l8kt4jpcnua00m09uv4tssjwj5efv02lm04h']; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryBaseTx; + + expect(summary.id).toEqual('evrKDCGkkxVFBhA2u7eL1h91EpjePfW2ynQigSThjSoD9Q2CC'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.type).toEqual('transaction'); + expect(summary.tokens.length).toEqual(1); + // expect(summary.tokens[0].isSent).toEqual(false) + expect(summary.tokens[0].amount.toString()).toEqual('10000000'); + expect(summary.tokens[0].amountDisplayValue).toEqual('0.01'); + expect(summary.tokens[0].addresses).toEqual(['fuji1jq7trjflynjghlc8fv4hktn0f3y4u23shy4cwg']); + }); + + it('Receive 2 ANT tokens', async () => { + let data: ITransactionData = JSON.parse(BaseTx2); + const myAddresses = ['X-fuji1qrpc4fdyupsc3jqytxdecw44skuggr4qq2vlpn']; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryBaseTx; + + expect(summary.id).toEqual('s27VDftrJ1zq5oit9yqPqcxkPY5hvvCmpDQmU6usGLdjGAqo5'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.type).toEqual('transaction'); + expect(summary.tokens.length).toEqual(2); + // For asset 1 + // expect(summary.tokens[0].isSent).toEqual(false) + expect(summary.tokens[0].amount.toString()).toEqual('1'); + expect(summary.tokens[0].amountDisplayValue).toEqual('0.00000001'); + expect(summary.tokens[0].addresses).toEqual(['fuji1gzyk29gqdq95muwlfkllg5ncdwjafrg9att3gp']); + // For asset 2 + // expect(summary.tokens[1].isSent).toEqual(false) + expect(summary.tokens[1].amount.toString()).toEqual('10100000'); + expect(summary.tokens[1].amountDisplayValue).toEqual('0.0101'); + expect(summary.tokens[1].addresses).toEqual(['fuji1gzyk29gqdq95muwlfkllg5ncdwjafrg9att3gp']); + }); +}); + +describe('Base Transaction Send', () => { + it('Simple send AVAX', async () => { + let data: ITransactionData = JSON.parse(BaseTxSend0); + const myAddresses = ['X-fuji1euwa0uxz7fcm8edj5fy490fvdj6e3s2mnmxh6p']; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryBaseTx; + + expect(summary.id).toEqual('2Ac5CkA7AMYQ8JQve4Wcczppn17LSqfftjLwqxbdNpJiKHXDT2'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.type).toEqual('transaction'); + expect(summary.tokens.length).toEqual(1); + expect(summary.tokens[0].amount.toString()).toEqual('-1000000000'); + expect(summary.tokens[0].amountDisplayValue).toEqual('-1'); + expect(summary.tokens[0].addresses).toEqual(['fuji1n8vmuvxudfkr7u6vy307jlyuk84nke0nr769zd']); + }); + + it('Send 1000 AVAX', async () => { + let data: ITransactionData = JSON.parse(BaseTxSend1); + const myAddresses = [ + 'X-fuji1ysxw3923qapq43pukde9vud4wn84exyzdqletm', + 'X-fuji1lcx7plqaajp6730hh7pvyk9l3urjm6auxc3fx5', + ]; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryBaseTx; + + expect(summary.id).toEqual('UGWnqJQqeyZXEYthEeRgcwVrvMLyPgN6uxMY2cE3eU1YQy6ie'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.type).toEqual('transaction'); + expect(summary.memo).toEqual('here you go!'); + expect(summary.tokens.length).toEqual(1); + expect(summary.tokens[0].amount.toString()).toEqual('-1000000000000'); + expect(summary.tokens[0].amountDisplayValue).toEqual('-1,000'); + expect(summary.tokens[0].addresses).toEqual(['fuji17mqelzf3w2l64pmqpxr84na9wmkknn3p3yf0kk']); + }); + + it('Send 2 ANTs', async () => { + let data: ITransactionData = JSON.parse(BaseTxSend2); + const myAddresses = [ + 'X-fuji1lcx7plqaajp6730hh7pvyk9l3urjm6auxc3fx5', + 'X-fuji1ysxw3923qapq43pukde9vud4wn84exyzdqletm', + 'X-fuji19p54jf6y50yn3e8c5lvuuwkumx3yjx762q6t6w', + 'X-fuji17g00lgxz4a0s8z5jn9t36pqapmrqnkn9f8hjh5', + ]; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryBaseTx; + + expect(summary.id).toEqual('ynz91L9CdEfQgeoBYXfNiGtWN8AXmgzXHXSRCUNsucd5he5fV'); + expect(summary.fee.toString()).toEqual('1000000'); + expect(summary.type).toEqual('transaction'); + expect(summary.tokens.length).toEqual(2); + // Asset 1 + expect(summary.tokens[0].amount.toString()).toEqual('-1000'); + expect(summary.tokens[0].amountDisplayValue).toEqual('-0.00001'); + expect(summary.tokens[0].addresses).toEqual(['fuji1x2qdqnkq5tt2j23c3569zffula30h5e0qxklu6']); + // Asset 2 + expect(summary.tokens[1].amount.toString()).toEqual('-1000000'); + expect(summary.tokens[1].amountDisplayValue).toEqual('-0.001'); + expect(summary.tokens[1].addresses).toEqual(['fuji1x2qdqnkq5tt2j23c3569zffula30h5e0qxklu6']); + }); +}); + +describe('Staking TX', () => { + it('Add validator 100 AVAX, staking finished, not rewarded', async () => { + let data: ITransactionData = JSON.parse(StakeTx0); + const myAddresses = [ + 'P-fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut', + 'P-fuji1lzrmf3crp62ayj2kqwh9mzc5es9xv7q6cm00vl', + 'P-fuji1spfpak2gtw87jaex2hqgz842s4xfp2xrjxyrt2', + ]; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryStaking; + + expect(summary.type).toEqual('add_validator'); + expect(summary.isRewarded).toEqual(false); + expect(summary.amount.toString()).toEqual('100000000000'); + expect(summary.amountDisplayValue).toEqual('100'); + expect(summary.rewardAmount?.toString()).toEqual(undefined); + expect(summary.rewardAmountDisplayValue).toEqual(undefined); + }); + + it('Add delegator 100 AVAX, uses lockedstakeable UTXOs, stake finished, rewarded', async () => { + let data: ITransactionData = JSON.parse(StakeTx1); + const myAddresses = [ + 'P-fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut', + 'P-fuji1qhu9lz4aqtp0xzywxz8z42curluwm4y9yj2wgf', + 'P-fuji1w4fjr3ds5rne4d3jm9uhgjn75z2z42fk0k2p74', + 'P-fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8', + ]; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryStaking; + + expect(summary.type).toEqual('add_delegator'); + expect(summary.isRewarded).toEqual(true); + expect(summary.amount.toString()).toEqual('100000000000'); + expect(summary.amountDisplayValue).toEqual('100'); + expect(summary.rewardAmount?.toString()).toEqual('555946308'); + expect(summary.rewardAmountDisplayValue).toEqual('0.555946308'); + }); + + it('Fee received from delegator 0.000225438 AVAX', async () => { + let data: ITransactionData = JSON.parse(StakeTx2); + const myAddresses = ['P-fuji1wvtapgjhf90p6hhsnvran54u9wy7gadkvy5j3p']; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryStaking; + + expect(summary.type).toEqual('delegation_fee'); + expect(summary.rewardAmount?.toString()).toEqual('225438'); + expect(summary.rewardAmountDisplayValue).toEqual('0.000225438'); + }); + + it('Add validator, stake finished, rewarded', async () => { + let data: ITransactionData = JSON.parse(StakeTx3); + const myAddresses = [ + 'P-fuji1lzrmf3crp62ayj2kqwh9mzc5es9xv7q6cm00vl', + 'P-fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut', + 'P-fuji16vhgs3grfegzt23uzp9sxy9r0jy4s8uts5zz5s', + ]; + const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077'; + let summary = (await getTransactionSummary(data, myAddresses, cAddr)) as iHistoryStaking; + + expect(summary.type).toEqual('add_validator'); + expect(summary.amountDisplayValue).toEqual('250'); + expect(summary.isRewarded).toEqual(true); + expect(summary.rewardAmount?.toString()).toEqual('4995764528'); + expect(summary.rewardAmountDisplayValue).toEqual('4.995764528'); + }); +}); + +// describe('Operation Receive', ()=>{ +// it('Mint single NFT', async ()=>{ +// let data: ITransactionData = JSON.parse(OperationTx0) +// const myAddresses = ['X-fuji13jva03qs5lrs32eye85nrwxrq86sjpynguzcgp','X-fuji1as66nrj7n7ckqwmsyfj955tn5spmemsl9rtze0', 'X-fuji1u25fmwqnsyt0qttwht6rfm7dgp8wlydtsyv3y7', 'X-fuji12puq6z9lptfjkh4q7d3y986kwx4gsagp3525t9'] +// const cAddr = '0x5f658A6d1928c39B286b48192FEA8d46D87AD077' +// let summary = await getTransactionSummary(data,myAddresses,cAddr) as iHistoryBaseTx +// +// console.log(summary) +// expect(summary.id).toEqual('2gJbPfNaX4kWuSJSZwrKsJ3nB9NnAihWBKQy2mQda2GxA3iasJ') +// expect(summary.fee.toString()).toEqual('1000000') +// expect(summary.type).toEqual('transaction') +// expect(summary.tokens.length).toEqual(0) +// // expect(summary.tokens[0].isSent).toEqual(false) +// // expect(summary.tokens[0].amount.toString()).toEqual('10000000') +// // expect(summary.tokens[0].addresses).toEqual(['fuji1jq7trjflynjghlc8fv4hktn0f3y4u23shy4cwg']) +// }) +// }) diff --git a/test/History/import_dumps.ts b/test/History/import_dumps.ts new file mode 100644 index 00000000..409f64a0 --- /dev/null +++ b/test/History/import_dumps.ts @@ -0,0 +1,329 @@ +// Single UTXO import, from same wallet +export const ImportTransaction = `{ + "id": "2KL4TfCKyHYMxGfWSZkXpurYiDzwk9sASAH47RMikk53cZNNuY", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "import", + "inputs": [ + { + "output": { + "id": "25qYtoa8iUs1C3fiFd5zVBgGkGKAy5cJAB8h3pZ9KEsFATrzvN", + "transactionID": "2ZCs8ivLqFJMY95xfbjEvmmYHLRKJ482LRRhRHJTbh5ozgkTK", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "10000001000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1nqz4gndscpdp6yr326sz0afdlylcj0g6mf0q46" + ], + "caddresses": null, + "timestamp": "2021-09-22T21:09:12.080818Z", + "redeemingTransactionID": "2KL4TfCKyHYMxGfWSZkXpurYiDzwk9sASAH47RMikk53cZNNuY", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1nqz4gndscpdp6yr326sz0afdlylcj0g6mf0q46", + "public_key": "Aq+k4JtTmzlCtC8uU9ENcPEWgjGYFCfzcdQXDtr4IlT7", + "signature": "+JDS2npkiUeUCJbd4omE42p84NxWrZesXbl6Xc/T2hgAWpavImf8q82O0iqpjsk+4V6d7vFZ7ljjxfyGbrdt5QA=" + } + ] + } + ], + "outputs": [ + { + "id": "vz89wQkEvPkTuZCQNJZ4DX4Jd5UsDJCMM7WBgHcVLLbVv9rA9", + "transactionID": "2KL4TfCKyHYMxGfWSZkXpurYiDzwk9sASAH47RMikk53cZNNuY", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "10000000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1nqz4gndscpdp6yr326sz0afdlylcj0g6mf0q46" + ], + "caddresses": null, + "timestamp": "2021-09-22T21:09:22.140212Z", + "redeemingTransactionID": "sgX4P3HuZnNYZvaQFTrhCM1CUjDyzhJeDEhsMVi4JZ1YPjkJn", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "10000001000000" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "10000000000000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-09-22T21:09:22.140212Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "Nk3tnXwzna7TRHqZdcip9mYZsHfuxzVuwD7r9FprUEjnx73pX", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; + +/** + * Multiple input UTXOs + */ +export const ImportTx1 = `{ + "id": "Gnvid4y5ZMW3FFW4r46i9F9tGW81p3q3c4WL6sy3223fRXbM3", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "import", + "inputs": [ + { + "output": { + "id": "2SWfaryWASwABQnLHo6csTmYzT32wc5SkMHauhwFxRu2wj9ZS1", + "transactionID": "2Zu4HyHvNYZrHS4WuLWzWvnLRdudzxhrwAWio6dxWi9V8j1QZE", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1001000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji16spahfywxkm2jw0nmag8wdaymg76cccw3hpr5g" + ], + "caddresses": null, + "timestamp": "2021-09-22T14:53:28.682254Z", + "redeemingTransactionID": "Gnvid4y5ZMW3FFW4r46i9F9tGW81p3q3c4WL6sy3223fRXbM3", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji16spahfywxkm2jw0nmag8wdaymg76cccw3hpr5g", + "public_key": "A8pS71G9B7Vxcj+Tl3w6HAzYkRVlGyaZx8DwbDy0VzQE", + "signature": "BaJNUuyjNMCaMu7KGF7PJD+egRluFHg/odbr5oHQxE4wqycts/c+v+kT/HKuay1kd20+Z2LdONbmUYRjWIpdhgA=" + } + ] + }, + { + "output": { + "id": "Fsz8Lowagfbt9MBrfqvMGR3D26o2RFuDQ2UYBPb6hGxCyuEQB", + "transactionID": "Kzhv5zDBEvtFoMFyfbwauppBBULctQ81QkHwqTVRwfykbYVWY", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1001000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji170mcu46k2rctpzrpe5vgk6nchhzfxt40kgcd2s" + ], + "caddresses": null, + "timestamp": "2021-09-22T14:51:01.675742Z", + "redeemingTransactionID": "Gnvid4y5ZMW3FFW4r46i9F9tGW81p3q3c4WL6sy3223fRXbM3", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji170mcu46k2rctpzrpe5vgk6nchhzfxt40kgcd2s", + "public_key": "AqSeXd3beQ9iQ9kUMEeh1y5oLuMqDP7K0I91L5bQ2VnW", + "signature": "jxg1Cv0nSPL0eBbDDq+2nC8WZ4dWMJJiarna697yWEB/msBQMk5dmDm6tPNOFGideb6lgBNdDTQfb9tGKbVTIAA=" + } + ] + }, + { + "output": { + "id": "kMpYcRJw8g8HGhwXifUAcoyeRSLCXFMY9N2ZbgLrCx11RsXAj", + "transactionID": "2sTXUQJrxkaiLvK17vK11AyH4x2m4n6jJuAARepZQygNVS6WX4", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1001000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1kh2tklylfqg3fg2audd53kf2zdnrhamcac0hjk" + ], + "caddresses": null, + "timestamp": "2021-09-22T15:29:00.285528Z", + "redeemingTransactionID": "Gnvid4y5ZMW3FFW4r46i9F9tGW81p3q3c4WL6sy3223fRXbM3", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1kh2tklylfqg3fg2audd53kf2zdnrhamcac0hjk", + "public_key": "AocSxsnd7Vm7M9b0G70yRVC5GoX6ebN7YwTPGoyf58Yb", + "signature": "mamBZA1CHofvE+YGaMTQujY5jmwt9008rIuy+uV24qBo3ZmB9DDWY8VuBddTIHR+zXiDYE4UuKi2EQEo74SBDQE=" + } + ] + } + ], + "outputs": [ + { + "id": "w7VCmj68M1d528nkgfsPgQcGqW88fL8QQhWfE8J1qjqmX9cHQ", + "transactionID": "Gnvid4y5ZMW3FFW4r46i9F9tGW81p3q3c4WL6sy3223fRXbM3", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1mj2x9eecn68weljg3tfaszem6hfx8yyq2kve2a" + ], + "caddresses": null, + "timestamp": "2021-09-22T21:08:33.770254Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "tBwQq3sfe14HRmzoJeteQ1hKr8t5aN5QDvRgtLX7yrjsw8f5X", + "transactionID": "Gnvid4y5ZMW3FFW4r46i9F9tGW81p3q3c4WL6sy3223fRXbM3", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1001000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1mj2x9eecn68weljg3tfaszem6hfx8yyq2kve2a" + ], + "caddresses": null, + "timestamp": "2021-09-22T21:08:33.770254Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2H7UTsEDVcSqs5khTyQscye2iE5noa1xc7Uoz7a1vFartqa5if", + "transactionID": "Gnvid4y5ZMW3FFW4r46i9F9tGW81p3q3c4WL6sy3223fRXbM3", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1001000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1mj2x9eecn68weljg3tfaszem6hfx8yyq2kve2a" + ], + "caddresses": null, + "timestamp": "2021-09-22T21:08:33.770254Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "3003000000" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "3002000000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-09-22T21:08:33.770254Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "2jhMUtWCZAVqu5nRTWiByMzXauQXHVQYpysD2A8VjrtiB1tuwH", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; diff --git a/test/History/operation_dumps.ts b/test/History/operation_dumps.ts new file mode 100644 index 00000000..d6696286 --- /dev/null +++ b/test/History/operation_dumps.ts @@ -0,0 +1,158 @@ +export const OperationTx0 = `{ + "id": "2gJbPfNaX4kWuSJSZwrKsJ3nB9NnAihWBKQy2mQda2GxA3iasJ", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "type": "operation", + "inputs": [ + { + "output": { + "id": "Z9LRZGxNV5DVtH2DvLaL2fi7MSmdcNMAFoiecUdYccqJ24ffv", + "transactionID": "wVzcrpPJoDP4y3G9obvNueqwYGk8VSAZHDgTH3fmir2e47YFE", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "9472966000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji13jva03qs5lrs32eye85nrwxrq86sjpynguzcgp" + ], + "caddresses": null, + "timestamp": "2021-06-16T18:06:19.86263Z", + "redeemingTransactionID": "2gJbPfNaX4kWuSJSZwrKsJ3nB9NnAihWBKQy2mQda2GxA3iasJ", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji13jva03qs5lrs32eye85nrwxrq86sjpynguzcgp", + "public_key": "A3I9O+Ng6/AmbYZydjlz8eoslIbiNgr0t29Ds2N8SNxj", + "signature": "mV2SHrxAZEqLBjgZm+CHn+jsGRUkikyL3ZUvhxYVfgxxDN1jdQuHMgxQue9Ysz+vdV380nAGZR/O51eny9ZmEwE=" + } + ] + }, + { + "output": { + "id": "jrETXHSzcUpMk14meRQhLh6AMyJcdBmvXxEB7w41PSTCM98ba", + "transactionID": "2GSWoUZhQ4f5r5khEcJQVpH5VQv15Q4d5Y7EUeEaWNfCHvUAao", + "outputIndex": 6, + "assetID": "2GSWoUZhQ4f5r5khEcJQVpH5VQv15Q4d5Y7EUeEaWNfCHvUAao", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 10, + "amount": "0", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji12puq6z9lptfjkh4q7d3y986kwx4gsagp3525t9" + ], + "caddresses": null, + "timestamp": "2020-12-15T23:11:47Z", + "redeemingTransactionID": "2gJbPfNaX4kWuSJSZwrKsJ3nB9NnAihWBKQy2mQda2GxA3iasJ", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 5, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": null + } + ], + "outputs": [ + { + "id": "sHRLMt1ZSyBoC8UNX7xxLUB16FAE1rCLzbT9m1jejy3cjccpa", + "transactionID": "2gJbPfNaX4kWuSJSZwrKsJ3nB9NnAihWBKQy2mQda2GxA3iasJ", + "outputIndex": 1, + "assetID": "2GSWoUZhQ4f5r5khEcJQVpH5VQv15Q4d5Y7EUeEaWNfCHvUAao", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 11, + "amount": "0", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1u25fmwqnsyt0qttwht6rfm7dgp8wlydtsyv3y7" + ], + "caddresses": null, + "timestamp": "2021-06-23T20:06:41.299631Z", + "redeemingTransactionID": "", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 5, + "payload": "GHsiYXZhbGFuY2hlIjp7InZlcnNpb24iOjEsInR5cGUiOiJnZW5lcmljIiwidGl0bGUiOiJNZWViaXQiLCJpbWciOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vZHFHYi1GTlA3emFwUFQxM05kRnpQZ202bFhZVVVKS2hUbW83X0JmN1NBVndrUlZrM2syaGNZcHYwOC01MllicVU0UHpDdEI4bnEwdERTNW5mRnF1U3hNUmNrV0lMWFpNc2JlYT13NjAwIiwiZGVzYyI6IkZBS0UifX0=", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "hGaDY3SCdrke3kKfqbCxz7JEWea8Ewa4XrXcVwyHH4xwzCGgT", + "transactionID": "2gJbPfNaX4kWuSJSZwrKsJ3nB9NnAihWBKQy2mQda2GxA3iasJ", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "9472965000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1as66nrj7n7ckqwmsyfj955tn5spmemsl9rtze0" + ], + "caddresses": null, + "timestamp": "2021-06-23T20:06:41.299631Z", + "redeemingTransactionID": "26ooJSxgQBVDUL7cKWiPJ3z1zsr9nfmAoY3pq11DKvg8En21c6", + "chainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "inChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "outChainID": "2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "2GSWoUZhQ4f5r5khEcJQVpH5VQv15Q4d5Y7EUeEaWNfCHvUAao": "0", + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "9472966000000" + }, + "outputTotals": { + "2GSWoUZhQ4f5r5khEcJQVpH5VQv15Q4d5Y7EUeEaWNfCHvUAao": "0", + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "9472965000000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-06-23T20:06:41.299631Z", + "txFee": 1000000, + "genesis": false, + "rewarded": false, + "rewardedTime": null, + "epoch": 0, + "vertexId": "jYrQXc2UDmuJErBtnSWbdB96qnghPK472XaXgasF48h2MTZs8", + "validatorNodeID": "", + "validatorStart": 0, + "validatorEnd": 0, + "txBlockId": "" +}`; diff --git a/test/History/staking_dumps.ts b/test/History/staking_dumps.ts new file mode 100644 index 00000000..5c072e13 --- /dev/null +++ b/test/History/staking_dumps.ts @@ -0,0 +1,1586 @@ +// Add validator 100 AVAX, staking finished, not rewarded +export const StakeTx0 = `{ + "id": "27jssVvW2S77qy7H7K5SBtvvgPzEkHTFoWmCh6jcF9BjgZjP5i", + "chainID": "11111111111111111111111111111111LpoYY", + "type": "add_validator", + "inputs": [ + { + "output": { + "id": "hiCvVCwJo7LSXeeH2WV6xu4ebw3t5ctpA4qJtem4D6jdYmdii", + "transactionID": "QoBwddxibJn8k2CmpkqRXoZE9mhSkeFyAkiLNpPK7Cu8tJ7au", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "499000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut" + ], + "caddresses": null, + "timestamp": "2021-07-28T17:04:11.363816Z", + "redeemingTransactionID": "27jssVvW2S77qy7H7K5SBtvvgPzEkHTFoWmCh6jcF9BjgZjP5i", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut", + "public_key": "AwOdFp8XEexWOSRM5t7c/l1naPJUGFEMRFGIF1ySrbC0", + "signature": "m99RqAcBnkPvyy22PcmItKm419Wky1jj2JXvTH9CkRx8vpxm/9Vg9zReORE82DtnOs4QUqfKLIMWk37o6FO2CwA=" + } + ] + } + ], + "outputs": [ + { + "id": "k25joZvnvxTvEvBT332joSevrVJDKNGSjgN9BJbV2XHeQbfXK", + "transactionID": "27jssVvW2S77qy7H7K5SBtvvgPzEkHTFoWmCh6jcF9BjgZjP5i", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "399000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1lzrmf3crp62ayj2kqwh9mzc5es9xv7q6cm00vl" + ], + "caddresses": null, + "timestamp": "2021-08-05T04:24:50.444771Z", + "redeemingTransactionID": "mNjgdZ1CQ3VXPNqqNc6LKmXHvwotVLHwQzq26w8we5Ds79WUA", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "QytiHSLGF9iAQpXK7h3BqBdhrVGSu7H4Hwkrxqw9VDkiss8A3", + "transactionID": "27jssVvW2S77qy7H7K5SBtvvgPzEkHTFoWmCh6jcF9BjgZjP5i", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "100000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1spfpak2gtw87jaex2hqgz842s4xfp2xrjxyrt2" + ], + "caddresses": null, + "timestamp": "2021-08-05T04:24:50.444771Z", + "redeemingTransactionID": "2GSAeJXeg1syJiQpfjmfzzNSUGL3dGiHZVoG9mk8QtbjoL6EvF", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "499000000000" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "499000000000" + }, + "reusedAddressTotals": null, + "timestamp": "2021-08-05T04:24:50.444771Z", + "txFee": 0, + "genesis": false, + "rewarded": false, + "rewardedTime": "2021-08-19T04:39:14.771312Z", + "epoch": 0, + "vertexId": "", + "validatorNodeID": "CZmZ9xpCzkWqjAwxpSr811fWai1WDij2F", + "validatorStart": 1628137790, + "validatorEnd": 1629347954, + "txBlockId": "DN7KhA2n9JPqhytgphpUeYkD2uxBQUeH6CGpadWqr5oREj4Ee" +}`; + +// Add delegator 100 AVAX, stake finished, rewarded +export const StakeTx1 = `{ + "id": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "type": "add_delegator", + "inputs": [ + { + "output": { + "id": "2YowBKRVDVxg7x5URXqi8masJh9azqdBnwzQdBdYbkyBsNvTay", + "transactionID": "KGoo4FTaPcyqRYj1dqPSAWkhAhRNKgoZ71piicuGxfYBJ1Jck", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1832496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-10T23:53:11.737965Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "47smRxw8isWvD9NA5KWBCdnCfEX9oHpZnq9wPSGzsRkrnGK7D", + "transactionID": "2fiaSeeivgJAxzEsvqpcM5P1Ctcp94ryjpgyJZTVQERGxKAvPi", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1832496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-12T17:54:26.274991Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "foVXKk12Bt4udXKGUpEQsg8exGfLwESbe8Gwcsp7yBmWMtCBE", + "transactionID": "MESyUmFw7aL3CmcjnWQ9pcead67Pirov3ajGutaCfD3T69s5Q", + "outputIndex": 3, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1832496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-10T18:58:23.872743Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "rW4rvhyZzNFmVoAAEuXrNgRHF7QUWEhWXkGYvbB5Nt7mdxCKc", + "transactionID": "2fiaSeeivgJAxzEsvqpcM5P1Ctcp94ryjpgyJZTVQERGxKAvPi", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-12T17:54:26.274991Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "xFHGxZiu3odBqggw9ZQjpWsEXXzjSfYMgiBhQpJ46aJm15JFC", + "transactionID": "h4baGQJLCbgVPjhJyWCqhvji55EKc64REwj6yNmL7W4SPJFFC", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1862496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-06-03T23:09:41.900522Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "2tGa8sZj8RjYPfmkXt1k22nuniMwxCK8vTEkqgT25vwjSLq7xV", + "transactionID": "LN4BXd5KHXtFgVYN4AX8vW7rYfLXNW22Sx9nAD81aXTbWn6H1", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-11T00:08:37.882266Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "2kmXjDADeKRRpd5RHPLnBiKgjGtwHZRTTk83MEvQX2u2jowbfy", + "transactionID": "MESyUmFw7aL3CmcjnWQ9pcead67Pirov3ajGutaCfD3T69s5Q", + "outputIndex": 4, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1842496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-10T18:58:23.872743Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "cofq3P2Bzvp9R6DzW3EJweabNA1veFwWgJd4fQrJ9kGUR6gfc", + "transactionID": "2mR8PSuLZsPVYZoJuoK75C7yAsJsVPR36k9N6KsA4mpMDwNXXr", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1w4fjr3ds5rne4d3jm9uhgjn75z2z42fk0k2p74" + ], + "caddresses": null, + "timestamp": "2021-05-03T16:52:29.602538Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1w4fjr3ds5rne4d3jm9uhgjn75z2z42fk0k2p74", + "public_key": "A4vkv2gU2GCo9OvrIQv8+LsTYJekm1J4R0cP2KVSFrvS", + "signature": "lGtv9+H7XTSaIDmUGGK5covJSE12jKq7tY8p0f0A7q0e4KFM7ZzzZcv8H9oshq5UdDnjlQsPwoO4TdVz6HdqHQE=" + } + ] + }, + { + "output": { + "id": "ixrGnKJdHUooguPWWog8nJ6NPiYKt5yi7ujV1GrbBqKZwS5q5", + "transactionID": "h4baGQJLCbgVPjhJyWCqhvji55EKc64REwj6yNmL7W4SPJFFC", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1852496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-06-03T23:09:41.900522Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "XrUtfbLbksdTDM9pQ3xr1kyqtUQgq1RSGV73EdWT6URBmTugz", + "transactionID": "qYEeA7UzKn2aLuDx3ABrT9k6D6eU9ZQAwzY53taxczj9fhBHL", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1499994000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1gc99ltssvx0za6g2uhqtpgqu0tj7c735rd6ehp" + ], + "caddresses": null, + "timestamp": "2021-07-21T23:35:21.577838Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1gc99ltssvx0za6g2uhqtpgqu0tj7c735rd6ehp", + "public_key": "AzG4vqwTzlULfhuUTvxpr8IU+awNsschChfHWkLL+67J", + "signature": "RDTuRpyyrRqxGhgo9RKhIXgBHY58x1EKiWktnRvJrDAEMTycokN9KR9UwSzFlAwlCrXfiOo5rpJceyzpi2natgE=" + } + ] + }, + { + "output": { + "id": "2bp4Nt2GPB4kU4rr6774dnZu7usDkKc3tUHf4dm6RbwEHx7V9z", + "transactionID": "aCbUkYhEUfRRSqAf9iu2pYLDjz3KB8PovDEEHKz54weSgCppo", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-10T23:26:30.392836Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "W93YJopXTF8JkVDPa9SdZEgzEZpvEF5hhU9B1gVCZX6eFtsoP", + "transactionID": "aCbUkYhEUfRRSqAf9iu2pYLDjz3KB8PovDEEHKz54weSgCppo", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1832496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-10T23:26:30.392836Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "6Tt1tmWhcXJpYrMFgEitsG2NuVTApDdPMH6hhLCTpthpM2XCd", + "transactionID": "LN4BXd5KHXtFgVYN4AX8vW7rYfLXNW22Sx9nAD81aXTbWn6H1", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1832496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-11T00:08:37.882266Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "PLHixgwKcy7Qiz6iFA33ESMYDdeS1i92QeivrgKMStYRcojkq", + "transactionID": "KGoo4FTaPcyqRYj1dqPSAWkhAhRNKgoZ71piicuGxfYBJ1Jck", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-10T23:53:11.737965Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + }, + { + "output": { + "id": "2NAYcVckQNtmjPCFbZ4bjiqGzvNN1PYdTnHAQrwUnMH3BeRCv3", + "transactionID": "MESyUmFw7aL3CmcjnWQ9pcead67Pirov3ajGutaCfD3T69s5Q", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-05-10T18:58:23.872743Z", + "redeemingTransactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8", + "public_key": "AmPjSsajpAZSGdvCNuPkp1r2cigsIwJfkHMKDnJr7trX", + "signature": "U5bK7L5hPvv78L8H038CMo0oWviD27iNT/cTFFWDBZVobWHUFSaiQdF7w499UZXe35FhoUHheaC5vPJtXxs8/AA=" + } + ] + } + ], + "outputs": [ + { + "id": "gpySFTnZ68Ao4RVp4iVXgwnm1JzDTLB7zusegYhARMTSqqbj2", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 8, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1832496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "22R76vakhdJEVto9Nhq9BzVohchzUF5UGwegDThApQN67ttP7d", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 12, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1832496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2bB98Har4h8agKyip5TCDcpxdUPJh4XzPRcoVP3YfhHxx6zZgN", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 4, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2J36LmeHcPXAyRkXLDaCpLSEyZpW6w4ApqAEMjjT7P6S7EG8Rg", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 5, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "GSqCELHikAhLQg7H77Qu4od8KTW5oUVmPyvFMbNnmBzfB1Zf4", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 3, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "TNgnvtXgnDJrvD6qPdmV3xrmhQQmiDW38Epeh38CHN4VkhRxX", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 9, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1832496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "4YfTiDzcJA9omyStnv4cdbSbpsjwkyT46J3LSz9fLmiY9GQwc", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 10, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1832496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2KuMpyWKdXmX7EdJcpj5RUCBCSMqvjBkzeF4GmzLbdRMsyizdG", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "79000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1qhu9lz4aqtp0xzywxz8z42curluwm4y9yj2wgf" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "X7R8E5uEVyBzhFuxSmkeGmT6DMemKT5KTbipgYCqYMeAuAozv", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "GMRUh2RjS123Mf54VavgYfW9RbyqNxAieaat7szcyMbHBCRNw", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1w4fjr3ds5rne4d3jm9uhgjn75z2z42fk0k2p74" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "KqC22p5wuxurzycN4UfS5a1kTqR1eaeomACexvRUnrXBYzb5B", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 13, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1842496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "22a6Qc88uLMLDc5MNgYp6H44YG9RFeDGHPxVgnbAJLUZysYpvn", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 16, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "555946308", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1qhu9lz4aqtp0xzywxz8z42curluwm4y9yj2wgf" + ], + "caddresses": null, + "timestamp": "2021-08-12T16:10:25.074989Z", + "redeemingTransactionID": "X7R8E5uEVyBzhFuxSmkeGmT6DMemKT5KTbipgYCqYMeAuAozv", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": true + }, + { + "id": "2nKN7H1dTFHdEkJvERD8CgdPE5aJDSSHiU3XGGmr1zn9AJC9wK", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 7, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2SpKMWejxFYmqHo9GHyPK1uWqDXuYnDEVUoUVdjDcYSvE4rrX4", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 11, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1832496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2RkJg46D1NuAs18j75WDZcZUiktV1QykdQ5yXDVZEvftVxnQfc", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 14, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1852496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "qb2xKcJdrJXp9ms5yaNoegHpnNSnGeDawfHi1T6QUhsnLNAqc", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 15, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1862496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2KQ3sHfLSs8n5Rtp8S6o5Ea4mEYJGc8kZYxvzF1pipQxq3KeTz", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 17, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "11345844", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1wycv8n7d2fg9aq6unp23pnj4q0arv03ysya8jw" + ], + "caddresses": null, + "timestamp": "2021-08-12T16:10:25.074989Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": true + }, + { + "id": "nw7xPQjfnwXbC6LXXzmLFsLyLsHP3womMtqrKryeWEJPnFCUq", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1420994000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "Rb6k8uHHKAvkq5qGF3QnyGvnG7ngkNAyWzmxjWqLvX83iT6Zd", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2EXh99YAaCE53CkeYGdurbJqxTZi9bxprwMqDCc5YGym3Gj8PA", + "transactionID": "22HBFSK2gYnCvs2kEa49spgUzcGgrxDpvPnf6dedbvkeXhhpov", + "outputIndex": 6, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": true, + "genesisutxo": false, + "outputType": 7, + "amount": "1500000000", + "locktime": 0, + "stakeLocktime": 1822496480, + "threshold": 1, + "addresses": [ + "fuji1afe8kypsetchzcz6fwlx2kdgaykevtru694ev8" + ], + "caddresses": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "1520994000000" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "1521561292152" + }, + "reusedAddressTotals": null, + "timestamp": "2021-07-22T15:55:52.164679Z", + "txFee": 0, + "genesis": false, + "rewarded": true, + "rewardedTime": "2021-08-12T16:10:25.075302Z", + "epoch": 0, + "vertexId": "", + "validatorNodeID": "4KXitMCoE9p2BHA6VzXtaTxLoEjNDo2Pt", + "validatorStart": 1626969651, + "validatorEnd": 1628784625, + "txBlockId": "2PndWGKpbMAgZK3mo46Jhe6GWmSYxoQgDy5c6rZNKPRc3GPYHZ" +}`; + +// Fee received from delegator 0.000225438 AVAX +export const StakeTx2 = `{ + "id": "2i8piG7iEJznXpdf83XLKgnhXhB9EXRtWewSA2kDr9s1HMbszr", + "chainID": "11111111111111111111111111111111LpoYY", + "type": "add_delegator", + "inputs": [ + { + "output": { + "id": "yoqGbmr2stZ1cFfea3aaSaZ4RBiiUNfCBUyMc6mvaeLbUHxVo", + "transactionID": "DnfUhaFCvY6CbM1hJqf7Bx1nzfrb5KkoPJ1V6Lp11t7SkwLJ3", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1986926133894", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji10rlz0k90vl6ywdqrlu5w0wgeffwk7jve8am2ml" + ], + "caddresses": null, + "timestamp": "2021-05-03T16:44:53.066773Z", + "redeemingTransactionID": "2i8piG7iEJznXpdf83XLKgnhXhB9EXRtWewSA2kDr9s1HMbszr", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji10rlz0k90vl6ywdqrlu5w0wgeffwk7jve8am2ml", + "public_key": "A1GT0+Nk0POyqzUZ1X6APvf8VSZdYt3VtbYJxizIMv/x", + "signature": "WRerFdiBF5iHTt6Jfr7P3YOK+4vs8bIMYLHFgnlBQUAbv+NEZZXSXMAN8CaElQ+PZEw7WPij6A/N1cMQ8gPmbAE=" + } + ] + } + ], + "outputs": [ + { + "id": "2pY8QaDwRgfpuiDFDLkzohm3zY4N45U8XPTkv8y34YtKnzHgrP", + "transactionID": "2i8piG7iEJznXpdf83XLKgnhXhB9EXRtWewSA2kDr9s1HMbszr", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "11046430", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1eh80w84fa3zftfj856awp486afsm6a8v5fgqav" + ], + "caddresses": null, + "timestamp": "2021-05-24T17:01:22.061362Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": true + }, + { + "id": "MzuZEUED8hhU6TnwsN5i74UdacZc1P4FaGG2T3GWqzYDa8icy", + "transactionID": "2i8piG7iEJznXpdf83XLKgnhXhB9EXRtWewSA2kDr9s1HMbszr", + "outputIndex": 3, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "225438", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1wvtapgjhf90p6hhsnvran54u9wy7gadkvy5j3p" + ], + "caddresses": null, + "timestamp": "2021-05-24T17:01:22.061362Z", + "redeemingTransactionID": "QRP9FVafDqQXxwbz93X9ubjkRSNodkRQoHbmVGTi98ugs1Hc1", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": true + }, + { + "id": "TKYRFGrhXkMxdi4HQ68aMXXLhBkgf2hosUvAwwNAQnHcrqJGg", + "transactionID": "2i8piG7iEJznXpdf83XLKgnhXhB9EXRtWewSA2kDr9s1HMbszr", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1984939207761", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1wra9n4lralt0vvlxv82g66xteac56dy78frlmc" + ], + "caddresses": null, + "timestamp": "2021-05-03T16:46:32.429477Z", + "redeemingTransactionID": "SMhtJ7jMCMkLUmMiQP2vqbenvzSW1En4as5ffvsgZEV6oUUgy", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "6CLEerzvTsBeG6ZJnFhdBpPiHcxmgzXqKdy2y3SY88Vuro5Xs", + "transactionID": "2i8piG7iEJznXpdf83XLKgnhXhB9EXRtWewSA2kDr9s1HMbszr", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "1986926133", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1eh80w84fa3zftfj856awp486afsm6a8v5fgqav" + ], + "caddresses": null, + "timestamp": "2021-05-03T16:46:32.429477Z", + "redeemingTransactionID": "", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + } + ], + "memo": "", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "1986926133894" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "1986937405762" + }, + "reusedAddressTotals": null, + "timestamp": "2021-05-03T16:46:32.429477Z", + "txFee": 0, + "genesis": false, + "rewarded": true, + "rewardedTime": "2021-05-24T17:01:22.061468Z", + "epoch": 0, + "vertexId": "", + "validatorNodeID": "CTtkcXvVdhpNtiPzzMTvwirbsjMr84mF9", + "validatorStart": 1620060690, + "validatorEnd": 1621875682, + "txBlockId": "2hrdCv8KpMfUfQk8xSUEMbkqPvynxzfGTpvyWiAJmxQj3LPBVA" +}`; + +// Add validator, stake finished, rewarded +export const StakeTx3 = `{ + "id": "2vTrEyvoaxfFpyC6ZotZqzSeVxeBBY5cCcDfiLaTWXBiFU5GWv", + "chainID": "11111111111111111111111111111111LpoYY", + "type": "add_validator", + "inputs": [ + { + "output": { + "id": "jsdvmYja8wY826KFNizdgGaX7soWWUw2VCe93oM2QnZ37HALD", + "transactionID": "NgoumCgn6AWKB6D2BwnMb4udFxzCVmFb4nABdYbfw3HTJpvaZ", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "590000341969", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1lzrmf3crp62ayj2kqwh9mzc5es9xv7q6cm00vl" + ], + "caddresses": null, + "timestamp": "2021-03-08T23:27:36.747151Z", + "redeemingTransactionID": "2vTrEyvoaxfFpyC6ZotZqzSeVxeBBY5cCcDfiLaTWXBiFU5GWv", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + "credentials": [ + { + "address": "fuji1lzrmf3crp62ayj2kqwh9mzc5es9xv7q6cm00vl", + "public_key": "Aob6BQcc6PmtW1SMWIT74Ztp2jOrDeOQAknqpJ6vE7Mr", + "signature": "EY1aa7RE+4dHKP4dJCPsynPuIwp2s+RHMtz+f4Ex/DluA5iaRtht4jN7nq/LEQODMchzej+9FuDnGOMfxnqagwA=" + } + ] + } + ], + "outputs": [ + { + "id": "2hfpCuKnryBeLLBz2JR1VQ8u1PLYuxQ4kMzzkzd58xFtXpoA6B", + "transactionID": "2vTrEyvoaxfFpyC6ZotZqzSeVxeBBY5cCcDfiLaTWXBiFU5GWv", + "outputIndex": 0, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "340000341969", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji1ur873jhz9qnaqv5qthk5sn3e8nj3e0kmafyxut" + ], + "caddresses": null, + "timestamp": "2021-03-09T00:18:36.747113Z", + "redeemingTransactionID": "EA5DKncfgLUSfuXRbgt77JTjeuWaHv35tJGB3VZcxhkemambh", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "2iLj4FvvQZLV678CLNHD4WBmLYVqpYP9oSxnN1YWLSAsPmEfhm", + "transactionID": "2vTrEyvoaxfFpyC6ZotZqzSeVxeBBY5cCcDfiLaTWXBiFU5GWv", + "outputIndex": 1, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": true, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "250000000000", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji16vhgs3grfegzt23uzp9sxy9r0jy4s8uts5zz5s" + ], + "caddresses": null, + "timestamp": "2021-03-09T00:18:36.747113Z", + "redeemingTransactionID": "QRP9FVafDqQXxwbz93X9ubjkRSNodkRQoHbmVGTi98ugs1Hc1", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": false + }, + { + "id": "LHgMvpY3KLHYW6KQojyvJTSJpow9wQKpi55A61TsQCvTRgHzd", + "transactionID": "2vTrEyvoaxfFpyC6ZotZqzSeVxeBBY5cCcDfiLaTWXBiFU5GWv", + "outputIndex": 2, + "assetID": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", + "stake": false, + "frozen": false, + "stakeableout": false, + "genesisutxo": false, + "outputType": 7, + "amount": "4995764528", + "locktime": 0, + "stakeLocktime": 0, + "threshold": 1, + "addresses": [ + "fuji16vhgs3grfegzt23uzp9sxy9r0jy4s8uts5zz5s" + ], + "caddresses": null, + "timestamp": "2021-05-20T00:32:49.061196Z", + "redeemingTransactionID": "QRP9FVafDqQXxwbz93X9ubjkRSNodkRQoHbmVGTi98ugs1Hc1", + "chainID": "11111111111111111111111111111111LpoYY", + "inChainID": "11111111111111111111111111111111LpoYY", + "outChainID": "11111111111111111111111111111111LpoYY", + "groupID": 0, + "payload": "", + "block": "", + "nonce": 0, + "rewardUtxo": true + } + ], + "memo": "AAAAAA==", + "inputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "590000341969" + }, + "outputTotals": { + "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK": "594996106497" + }, + "reusedAddressTotals": null, + "timestamp": "2021-03-09T00:18:36.747113Z", + "txFee": 0, + "genesis": false, + "rewarded": true, + "rewardedTime": "2021-05-20T00:32:49.061258Z", + "epoch": 0, + "vertexId": "", + "validatorNodeID": "CTtkcXvVdhpNpEmiFufVL2abzgSxYsCJN", + "validatorStart": 1615249389, + "validatorEnd": 1621470769, + "txBlockId": "RwBDmLs4Zxu5ZhgLSZ5CsjMT2LzHCxnbQBURgdiaeWYhj8pby" +}`; diff --git a/test/Wallet/PublicMnemonicWallet.test.ts b/test/Wallet/PublicMnemonicWallet.test.ts index 738a49c4..f7f70527 100644 --- a/test/Wallet/PublicMnemonicWallet.test.ts +++ b/test/Wallet/PublicMnemonicWallet.test.ts @@ -1,6 +1,14 @@ // Source mnemonic // chimney noodle canyon tunnel sample stuff scan symbol sight club net own arrive cause suffer purity manage squirrel boost diesel bring cement father slide +jest.mock('@/Network', () => { + return { + getAvaxAssetID: jest.fn().mockImplementation(() => { + return 'U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK'; + }), + }; +}); + import PublicMnemonicWallet from '@/Wallet/PublicMnemonicWallet'; const XPUB_AVM = `xpub6CvdTKLRh3ehvVLR2f3M1GUTFesrz5zoYFbw32iZqRShmoDnxtfSaF7mdCvXwNRfTwce5RYEADGb6YAzhqEAujEkvjTod6s2WEkpUBJZwqf`; diff --git a/yarn.lock b/yarn.lock index f96180bd..500cd176 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2023,9 +2023,9 @@ ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: type-fest "^0.21.3" ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^3.2.1: version "3.2.1" @@ -3202,10 +3202,10 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" -dompurify@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.1.tgz#a47059ca21fd1212d3c8f71fdea6943b8bfbdf6a" - integrity sha512-xGWt+NHAQS+4tpgbOAI08yxW0Pr256Gu/FNE2frZVTbgrBUn8M7tz7/ktS/LZ2MHeGqz6topj0/xY+y8R5FBFw== +dompurify@^2.3.0: + version "2.3.3" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.3.tgz#c1af3eb88be47324432964d8abc75cf4b98d634c" + integrity sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg== duplexer3@^0.1.4: version "0.1.4" @@ -4858,6 +4858,15 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isomorphic-dompurify@^0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/isomorphic-dompurify/-/isomorphic-dompurify-0.15.0.tgz#afa64f9888bbbcb4bcea42d4e7fec2ae0c4744c2" + integrity sha512-k6QjRSV2NiWI5C6NH7oU3DHagKFzX0NzLp9UcMtL1gUHKmtMIaiQucpRhCVrZkv0s9tMljtbCJyKxJK2EQhiIw== + dependencies: + "@types/dompurify" "^2.2.3" + dompurify "^2.3.0" + jsdom "^16.6.0" + isomorphic-ws@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" @@ -5351,6 +5360,39 @@ jsdom@^16.4.0: ws "^7.4.5" xml-name-validator "^3.0.0" +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"