UNPKG

@dojima-wallet/connection

Version:

Initialise and connection for layer 1&2 blockchain

328 lines (292 loc) 9.71 kB
import { ChainClientParams, Network } from "../client"; import { validatePhrase } from "../crypto"; // import BigNumber from "bignumber.js"; import * as ethers from "ethers"; import Web3 from "web3"; import { DOJ_DECIMAL } from "./const"; import { DojTransferParams, DojTxData } from "./types"; import { calcDoubleSwapOutput, calcDoubleSwapSlip, calcSwapOutput, calcSwapSlip, getStagenetInboundObject, getTestnetInboundObject, PoolData, SwapFeeResult, } from "../swap_utils"; import { SwapAssetList } from "@dojima-wallet/utils"; export type DojRpcParams = { privateKey: string; rpcUrl: string; infuraApiKey?: string; }; class DojimaClient { protected network: Network; protected web3: Web3; protected rpcUrl: string; protected provider: ethers.ethers.providers.JsonRpcProvider; protected account: ethers.ethers.Wallet; private phrase = ""; private privateKey = ""; constructor({ phrase, privateKey, network, rpcUrl, }: ChainClientParams & DojRpcParams) { this.network = network; this.rpcUrl = rpcUrl; this.web3 = new Web3(new Web3.providers.HttpProvider(this.rpcUrl)); this.provider = new ethers.providers.JsonRpcProvider(this.rpcUrl); if ((!phrase && !privateKey) || (phrase && privateKey)) { throw new Error("Any one of phrase or privateKey should be provided"); } if (phrase) { if (!validatePhrase(phrase)) { throw new Error("Invalid phrase"); } this.phrase = phrase; const accountData = ethers.Wallet.fromMnemonic(this.phrase); this.account = new ethers.Wallet(accountData.privateKey).connect( this.provider ); } if (privateKey) { this.privateKey = privateKey; this.account = new ethers.Wallet(this.privateKey).connect(this.provider); } } getAddress(): string { return this.account.address; } async getBalance(address: string): Promise<number> { const gweiBalance = await this.web3.eth.getBalance(address); // Results balance in gwei, 1 doj = 10^9 gwei(1,000,000,000) const dojBalance = this.web3.utils.fromWei(gweiBalance); return Number(dojBalance); } // calculateDojFee(baseGasFee: number, multiplier: number): number { // return new BigNumber(baseGasFee) // .times(new BigNumber(multiplier)) // .toNumber(); // } // async estimateGasFee(amount: number, memo?: string): Promise<number> { return await this.web3.eth.estimateGas({ from: this.getAddress(), to: this.getAddress(), value: amount * Math.pow(10, DOJ_DECIMAL), data: memo ? this.web3.utils.toHex(memo) : undefined, }); } // // async getFees(amount: number, memo?: string): Promise<GasfeeResult> { // const estimateGas = await this.estimateGasFee( // amount, // memo ? memo : undefined // ); // return { // slow: this.calculateDojFee(estimateGas, 1) / Math.pow(10, 9), // average: this.calculateDojFee(estimateGas, 1.5) / Math.pow(10, 9), // fast: this.calculateDojFee(estimateGas, 2) / Math.pow(10, 9), // }; // } // Function to estimate gas limit async estimateGasLimit( tx: ethers.providers.TransactionRequest ): Promise<ethers.BigNumber> { return await this.provider.estimateGas(tx); } // Function to get the current gas price async getCurrentGasPrice(): Promise<ethers.BigNumber> { return await this.provider.getGasPrice(); } // Function to calculate the gas fee async calculateGasFee( recipient: string, amount: number, memo?: string ): Promise<string> { const tx = { to: recipient, value: ethers.utils.parseEther(`${amount}`), data: memo ? ethers.utils.toUtf8Bytes(memo) : undefined, }; const gasLimit = await this.estimateGasLimit(tx); const gasPrice = await this.getCurrentGasPrice(); return ethers.utils.formatEther(gasLimit.mul(gasPrice)); } async transfer(params: DojTransferParams): Promise<string> { if (this.network === Network.Testnet) { const transaction = await this.web3.eth.accounts.signTransaction( { from: this.getAddress(), to: params.recipient, value: params.amount * Math.pow(10, DOJ_DECIMAL), gas: params.fee ? params.fee * Math.pow(10, 9) : await this.estimateGasFee( params.amount, params.memo ? params.memo : undefined ), data: params.memo ? this.web3.utils.toHex(params.memo) : undefined, }, this.account.privateKey ); const transactionResult = await this.web3.eth.sendSignedTransaction( transaction.rawTransaction as string ); return transactionResult.transactionHash; } else { const tx = { to: params.recipient, value: ethers.utils.parseEther(`${params.amount}`), data: params.memo ? ethers.utils.toUtf8Bytes(params.memo) : undefined, }; // Send transaction with gas limit and gas price const gasLimit = await this.estimateGasLimit(tx); const gasPrice = await this.getCurrentGasPrice(); const transactionResponse = await this.account.sendTransaction({ ...tx, gasLimit, gasPrice, }); return transactionResponse.hash; } } async dummyTx(recipient: string, amount: number): Promise<string> { const memo = `NOOP:NOVAULT`; const poolHash = await this.transfer({ recipient, amount, memo, }); return poolHash; } async getTransactionData(hash: string): Promise<DojTxData> { const tx = await this.provider.getTransaction(hash); const receipt = await this.provider.getTransactionReceipt(hash); if (tx && receipt) { const amount = ethers.utils.formatEther(tx.value); const gasUsed = ethers.utils.formatUnits(receipt.gasUsed, "gwei"); const gasPrice = ethers.utils.formatUnits(tx.gasPrice, "gwei"); return { transaction_hash: tx.hash, from: tx.from, to: tx.to as string, amount: parseFloat(amount), gasFee: parseFloat(gasPrice) * parseFloat(gasUsed), block_number: receipt.blockNumber as number, block_hash: receipt.blockHash as string, gasPrice: gasPrice, transaction_status: receipt.status, nonce: tx.nonce, }; } else { throw new Error(`Failed to get transaction data (tx-hash: ${hash})`); } // const data = await this.web3.eth.getTransaction(hash); // if (data) { // return { // transaction_hash: data.hash, // from: data.from, // to: data.to as string, // amount: Number(data.value) / Math.pow(10, 18), // gasFee: data.gas / Math.pow(10, 9), // block_number: data.blockNumber as number, // block_hash: data.blockHash as string, // gasPrice: data.gasPrice, // nonce: data.nonce, // }; // } else { // throw new Error(`Failed to get transaction data (tx-hash: ${hash})`); // } } getSwapOutput(inputAmount: number, pool: PoolData, toDoj: boolean): number { const input = inputAmount * Math.pow(10, DOJ_DECIMAL); return calcSwapOutput(input, pool, toDoj); } getDoubleSwapOutput( inputAmount: number, pool1: PoolData, pool2: PoolData ): number { const input = inputAmount * Math.pow(10, DOJ_DECIMAL); return calcDoubleSwapOutput(input, pool1, pool2); } getSwapSlip(inputAmount: number, pool: PoolData, toDoj: boolean): number { const input = inputAmount * Math.pow(10, DOJ_DECIMAL); return calcSwapSlip(input, pool, toDoj); } getDoubleSwapSlip( inputAmount: number, pool1: PoolData, pool2: PoolData ): number { const input = inputAmount * Math.pow(10, DOJ_DECIMAL); return calcDoubleSwapSlip(input, pool1, pool2); } async getSwapFeesData(): Promise<SwapFeeResult> { return; } async getDojimaInboundAddress(hermesApiUrl: string): Promise<string> { switch (this.network) { case Network.Testnet: { const inboundObj = await getTestnetInboundObject(hermesApiUrl, "DOJ"); return inboundObj.address; } case Network.Stagenet: { const inboundObj = await getStagenetInboundObject(hermesApiUrl, "DOJ"); return inboundObj.address; } case Network.Mainnet: { return ""; } } } async getDefaultLiquidityPoolGasFee(hermesApiUrl: string): Promise<number> { switch (this.network) { case Network.Testnet: { const inboundObj = await getTestnetInboundObject(hermesApiUrl, "DOJ"); const gasFee = Number(inboundObj.gas_rate) / Math.pow(10, DOJ_DECIMAL); return gasFee; } case Network.Stagenet: { const inboundObj = await getStagenetInboundObject(hermesApiUrl, "DOJ"); const gasFee = Number(inboundObj.gas_rate) / Math.pow(10, DOJ_DECIMAL); return gasFee; } case Network.Mainnet: { return 0; } } } async addLiquidityPool( amount: number, inboundAddress: string, hermesAddress?: string ): Promise<string> { const memo = hermesAddress ? `ADD:DOJ.DOJ:${hermesAddress}` : `ADD:DOJ.DOJ`; const txHash = await this.transfer({ amount, recipient: inboundAddress, memo, }); return txHash; } async swap( amount: number, token: SwapAssetList, inboundAddress: string, recipient: string ): Promise<string> { const memo = `SWAP:${token}:${recipient}`; const txHash = await this.transfer({ amount, recipient: inboundAddress, memo, }); return txHash; } } export { DojimaClient };