UNPKG

@1hive/connect-core

Version:

Access and interact with Aragon Organizations and their apps.

117 lines 5.98 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildForwardingFeePreTransactions = exports.buildApprovePreTransactions = exports.createForwarderTransactionBuilder = exports.createDirectTransactionForApp = exports.createDirectTransaction = void 0; const abi_1 = require("@ethersproject/abi"); const contracts_1 = require("@ethersproject/contracts"); const errors_1 = require("../errors"); const abis_1 = require("./abis"); const abi_2 = require("./abi"); const Transaction_1 = __importDefault(require("../entities/Transaction")); async function createDirectTransaction(sender, destination, methodAbiFragment, params) { if (methodAbiFragment.type === 'fallback' && params.length > 1) { throw new Error(`Could not create transaction to fallback function due to too many parameters: ${params}`); } // The direct transaction we eventually want to perform return new Transaction_1.default({ from: sender, to: destination, data: new abi_1.Interface([methodAbiFragment]).encodeFunctionData(abi_1.FunctionFragment.from(methodAbiFragment), params), }); } exports.createDirectTransaction = createDirectTransaction; async function createDirectTransactionForApp(sender, app, methodSignature, params) { if (!app) { throw new errors_1.ErrorInvalid(`Could not create transaction due to missing app artifact`); } const destination = app.address; if (!app.abi) { throw new errors_1.ErrorInvalid(`No ABI specified in artifact for ${destination}`); } const fragment = abi_2.findMethodAbiFragment(app.abi, methodSignature); if (!fragment) { throw new errors_1.ErrorInvalid(`${methodSignature} not found on ABI for ${destination}`); } return createDirectTransaction(sender, app.address, fragment, params); } exports.createDirectTransactionForApp = createDirectTransactionForApp; function createForwarderTransactionBuilder(sender, directTransaction) { const forwarder = new abi_1.Interface(abis_1.forwarderAbi); return (forwarderAddress, script) => new Transaction_1.default({ ...directTransaction, from: sender, to: forwarderAddress, data: forwarder.encodeFunctionData('forward', [script]), }); } exports.createForwarderTransactionBuilder = createForwarderTransactionBuilder; async function buildApprovePreTransactions(transaction, tokenData, provider) { // Token allowance pre-transaction const { from, to } = transaction; const { address: tokenAddress, value: tokenValue, spender } = tokenData; const tokenContract = new contracts_1.Contract(tokenAddress, abis_1.erc20ABI, provider); const balance = await tokenContract.balanceOf(from); const tokenValueBN = BigInt(tokenValue.toString()); if (BigInt(balance) < tokenValueBN) { throw new errors_1.ErrorUnsufficientBalance(`Balance too low. ${from} balance of ${tokenAddress} token is ${balance} (attempting to send ${tokenValue})`); } // Approve the transaction destination unless an spender is passed to approve a different contract const approveSpender = spender !== null && spender !== void 0 ? spender : to; const allowance = await tokenContract.allowance(from, approveSpender); // If allowance is already greater than or equal to amount, there is no need to do an approve transaction const allowanceBN = BigInt(allowance); if (allowanceBN >= tokenValueBN) { return []; } const transactions = []; const erc20 = new abi_1.Interface(abis_1.erc20ABI); // If the current allowance is greater than zero, we send a first pre-transaction to set it to zero if (allowanceBN > BigInt(0)) { console.warn(`${from} already approved ${approveSpender} some amount, adding one extra pre-transaction to set it to zero to avoid a failing approval.`); const zeroApprovalPreTransaction = new Transaction_1.default({ from, to: tokenAddress, data: erc20.encodeFunctionData('approve', [approveSpender, '0']), }); transactions.push(zeroApprovalPreTransaction); } const requestedApprovalPreTransaction = new Transaction_1.default({ from, to: tokenAddress, data: erc20.encodeFunctionData('approve', [approveSpender, tokenValue]), }); transactions.push(requestedApprovalPreTransaction); return transactions; } exports.buildApprovePreTransactions = buildApprovePreTransactions; async function buildForwardingFeePreTransactions(forwardingTransaction, provider) { const { to: forwarderAddress, from } = forwardingTransaction; const forwarderFee = new contracts_1.Contract(forwarderAddress, abis_1.forwarderFeeAbi, provider); const feeDetails = { amount: BigInt(0), tokenAddress: '' }; try { const overrides = { from, }; // Passing the EOA as `msg.sender` to the forwardFee call is useful for use cases where the fee differs relative to the account const [tokenAddress, amount] = await forwarderFee.forwardFee(overrides); // forwardFee() returns (address, uint256) feeDetails.tokenAddress = tokenAddress; feeDetails.amount = BigInt(amount); } catch (err) { // Not all forwarders implement the `forwardFee()` interface } if (feeDetails.tokenAddress && feeDetails.amount > BigInt(0)) { // Needs a token approval pre-transaction const tokenData = { address: feeDetails.tokenAddress, spender: forwarderAddress, value: feeDetails.amount.toString(), }; return buildApprovePreTransactions(forwardingTransaction, tokenData, provider); } return []; } exports.buildForwardingFeePreTransactions = buildForwardingFeePreTransactions; //# sourceMappingURL=transactions.js.map