import Utils from "./utils"; import BigNumber from "bignumber.js"; import type Api from "./api"; import base64url from "base64url"; import type { WithdrawalResponse } from "./types"; /** * Create and send a withdrawal request * @param utils Instance of Utils * @param api Instance of API * @param wallet Wallet to use * @param amount amount to withdraw in winston * @returns the response from the bundler */ export async function withdrawBalance(utils: Utils, api: Api, amount: BigNumber.Value | "all"): Promise { const c = utils.tokenConfig; const { deepHash, stringToBuffer } = c.irys.arbundles; const pkey = await c.getPublicKey(); const withdrawAll = amount === "all"; const data = { publicKey: pkey, currency: utils.token, amount: withdrawAll ? "all" : new BigNumber(amount).toString(), nonce: await utils.getNonce(), signature: "", sigType: c.getSigner().signatureType, }; const deephash = await deepHash([stringToBuffer(data.currency), stringToBuffer(data.amount.toString()), stringToBuffer(data.nonce.toString())]); if (!Buffer.isBuffer(data.publicKey)) { data.publicKey = Buffer.from(data.publicKey); } const signature = await c.sign(deephash); const isValid = await c.verify(data.publicKey, deephash, signature); data.publicKey = base64url.encode(data.publicKey); data.signature = base64url.encode(Buffer.from(signature)); const cpk = base64url.toBuffer(data.publicKey); const csig = base64url.toBuffer(data.signature); // should match opk and csig const dh2 = await deepHash([stringToBuffer(data.currency), stringToBuffer(data.amount.toString()), stringToBuffer(data.nonce.toString())]); const isValid2 = await c.verify(cpk, dh2, csig); const isValid3 = c.ownerToAddress(c.name == "arweave" ? base64url.decode(data.publicKey) : base64url.toBuffer(data.publicKey)) === c.address; if (!(isValid || isValid2 || isValid3)) { throw new Error(`Internal withdrawal validation failed - please report this!\nDebug Info:${JSON.stringify(data)}`); } const res = await api.post("/account/withdraw", data); if (res.status === 202) { // node has timed/erroed out confirming the withdrawal const txId = res.data.tx_id; const withdrawalConfirmed = await utils.confirmationPoll(txId); if (!(withdrawalConfirmed === true)) throw new Error(`Unable to confirm withdrawal tx ${txId} ${withdrawalConfirmed ? withdrawalConfirmed?.toString() : ""}`); } else { Utils.checkAndThrow(res, "Withdrawing balance"); } return res.data; }