@dojima-wallet/connection
Version:
Initialise and connection for layer 1&2 blockchain
319 lines (296 loc) • 9.94 kB
text/typescript
import Arweave from "arweave";
import Transaction from "arweave/node/lib/transaction";
import _ from "lodash";
import {
ArTxDataResult,
ArTxsResult,
InnerDataResult,
OuterDataResult,
} from "./types";
import {
GQLResultInterface,
GQLTransactionsResultInterface,
convertTimestampToDateFormat,
convertTimestampToTimeFormat,
AR_DECIMAL,
} from "./utils";
export interface ReqVariables {
ownersFilter: Array<string>;
first: number;
after?: string;
}
export default class ArweaveTxClient {
ownerHasNextPage: boolean | undefined;
recipientHasNextPage: boolean | undefined;
ownerCursor: string;
recipientCursor: string;
constructor() {
this.ownerHasNextPage = undefined;
this.recipientHasNextPage = undefined;
this.ownerCursor = "";
this.recipientCursor = "";
}
async getTxData(arweave: Arweave, hash: string): Promise<ArTxDataResult> {
const tx: Transaction = await arweave.transactions.get(hash);
if (!tx) throw Error(`Failed to get transaction data (tx-hash: ${hash})`);
const fromAddress = await arweave.wallets.ownerToAddress(tx.owner);
const resultData: ArTxDataResult = {
transaction_hash: tx.id,
from: fromAddress,
to: tx.target,
value: Number(tx.quantity) / Math.pow(10, AR_DECIMAL),
gas_price: (Number(tx.reward) / Math.pow(10, AR_DECIMAL)).toFixed(
AR_DECIMAL
),
signature: tx.signature,
};
return resultData;
}
async getTxsHistory(arweave: Arweave, owner: string, limit?: number) {
let ownerVariables: ReqVariables;
if (this.ownerCursor !== "") {
ownerVariables = {
ownersFilter: [owner],
first: limit ? limit : 100,
after: this.ownerCursor,
};
} else {
ownerVariables = {
ownersFilter: [owner],
first: limit ? limit : 100,
};
}
let recipientVariables: ReqVariables;
if (this.recipientCursor !== "") {
recipientVariables = {
ownersFilter: [owner],
first: limit ? limit : 100,
after: this.recipientCursor,
};
} else {
recipientVariables = {
ownersFilter: [owner],
first: limit ? limit : 100,
};
}
let txs: GQLTransactionsResultInterface;
const outerTxsData: OuterDataResult[] = [];
const innerTxsData: InnerDataResult[] = [];
const txsDataFinal: ArTxsResult = {
outer: outerTxsData,
inner: innerTxsData,
};
if (this.ownerHasNextPage === true || this.ownerHasNextPage === undefined) {
txs = await this.getOwnersTxsQueryResult(arweave, ownerVariables);
this.ownerHasNextPage = txs.pageInfo.hasNextPage;
if (txs.edges.length > 0) {
this.ownerCursor = txs.edges[txs.edges.length - 1].cursor;
txs.edges.map((res) => {
const outerResult: OuterDataResult = {
timestamp: res.node.block ? `${res.node.block.timestamp}` : "-",
transaction_hash: res.node.id,
block: res.node.block ? `${res.node.block.height}` : "-",
from: res.node.owner.address,
to: res.node.recipient,
value: res.node.quantity.ar,
gas_price: res.node.fee.ar,
date:
res.node.block && res.node.block.timestamp !== undefined
? convertTimestampToDateFormat(res.node.block.timestamp)
: "-",
time:
res.node.block && res.node.block.timestamp !== undefined
? convertTimestampToTimeFormat(res.node.block.timestamp)
: "-",
};
outerTxsData.push(outerResult);
const innerResult: InnerDataResult = {
timestamp: res.node.block ? `${res.node.block.timestamp}` : "-",
transaction_hash: res.node.id,
block: res.node.block ? `${res.node.block.height}` : "-",
from: res.node.owner.address,
to: res.node.recipient,
value: res.node.quantity.ar,
gas_price: res.node.fee.ar,
date:
res.node.block && res.node.block.timestamp !== undefined
? convertTimestampToDateFormat(res.node.block.timestamp)
: "-",
time:
res.node.block && res.node.block.timestamp !== undefined
? convertTimestampToTimeFormat(res.node.block.timestamp)
: "-",
signature: res.node.signature,
block_hash: res.node.block ? res.node.block.id : "-",
};
innerTxsData.push(innerResult);
});
}
}
if (
this.recipientHasNextPage === true ||
this.recipientHasNextPage === undefined
) {
txs = await this.getRecipientsTxsQueryResult(arweave, recipientVariables);
this.recipientHasNextPage = txs.pageInfo.hasNextPage;
if (txs.edges.length > 0) {
this.recipientCursor = txs.edges[txs.edges.length - 1].cursor;
txs.edges.map((res) => {
const outerResult: OuterDataResult = {
timestamp: res.node.block ? `${res.node.block.timestamp}` : "-",
transaction_hash: res.node.id,
block: res.node.block ? `${res.node.block.height}` : "-",
from: res.node.owner.address,
to: res.node.recipient,
value: res.node.quantity.ar,
gas_price: res.node.fee.ar,
date:
res.node.block && res.node.block.timestamp !== undefined
? convertTimestampToDateFormat(res.node.block.timestamp)
: "-",
time:
res.node.block && res.node.block.timestamp !== undefined
? convertTimestampToTimeFormat(res.node.block.timestamp)
: "-",
};
outerTxsData.push(outerResult);
const innerResult: InnerDataResult = {
timestamp: res.node.block ? `${res.node.block.timestamp}` : "-",
transaction_hash: res.node.id,
block: res.node.block ? `${res.node.block.height}` : "-",
from: res.node.owner.address,
to: res.node.recipient,
value: res.node.quantity.ar,
gas_price: res.node.fee.ar,
date:
res.node.block && res.node.block.timestamp !== undefined
? convertTimestampToDateFormat(res.node.block.timestamp)
: "-",
time:
res.node.block && res.node.block.timestamp !== undefined
? convertTimestampToTimeFormat(res.node.block.timestamp)
: "-",
signature: res.node.signature,
block_hash: res.node.block ? res.node.block.id : "-",
};
innerTxsData.push(innerResult);
});
}
}
if (outerTxsData.length !== 0) {
const outerLodash: OuterDataResult[] = _.orderBy(
outerTxsData,
"timestamp",
"desc"
);
txsDataFinal.outer = outerLodash;
}
if (innerTxsData.length !== 0) {
const innerLodash: InnerDataResult[] = _.orderBy(
innerTxsData,
"timestamp",
"desc"
);
txsDataFinal.inner = innerLodash;
}
return txsDataFinal;
}
async getOwnersTxsQueryResult(
arweave: Arweave,
variables: ReqVariables
): Promise<GQLTransactionsResultInterface> {
const query = `query Transactions($ownersFilter: [String!], $first: Int!, $after: String) {
transactions(owners: $ownersFilter, first: $first, sort: HEIGHT_ASC, after: $after) {
pageInfo {
hasNextPage
}
edges {
node {
id
owner { address }
recipient
block {
height
id
timestamp
}
fee {
ar
winston
}
quantity {
ar
winston
}
parent { id }
signature
}
cursor
}
}
}`;
const response = await arweave.api.post("graphql", {
query,
variables,
});
if (response.status !== 200) {
throw new Error(
`Unable to retrieve transactions. Arweave gateway responded with status ${response.status}.`
);
}
const data: GQLResultInterface = response.data;
const txs = data.data.transactions;
return txs;
}
async getRecipientsTxsQueryResult(
arweave: Arweave,
variables: ReqVariables
): Promise<GQLTransactionsResultInterface> {
const query = `query Transactions($ownersFilter: [String!], $first: Int!, $after: String) {
transactions(recipients: $ownersFilter, first: $first, sort: HEIGHT_ASC, after: $after) {
pageInfo {
hasNextPage
}
edges {
node {
id
owner { address }
recipient
tags {
name
value
}
block {
height
id
timestamp
}
fee {
ar
winston
}
quantity {
ar
winston
}
parent { id }
signature
}
cursor
}
}
}`;
const response = await arweave.api.post("graphql", {
query,
variables,
});
if (response.status !== 200) {
throw new Error(
`Unable to retrieve transactions. Arweave gateway responded with status ${response.status}.`
);
}
const data: GQLResultInterface = response.data;
const txs: GQLTransactionsResultInterface = data.data.transactions;
return txs;
}
}