UNPKG

@celo-tools/celo-ethers-wrapper

Version:

A minimal wrapper to make Ethers.JS compatible with the Celo network.

168 lines (167 loc) 13.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const ethers_1 = require("ethers"); const CeloProvider_1 = __importDefault(require("./CeloProvider")); const utils_1 = require("./transaction/utils"); const transactions_1 = require("./transactions"); const consts_1 = require("../consts"); const CoreContract_1 = require("./CoreContract"); const forwardErrors = [ "INSUFFICIENT_FUNDS", "NONCE_EXPIRED", "REPLACEMENT_UNDERPRICED", ]; class CeloWallet extends ethers_1.Wallet { async isCel2() { const code = await this.provider?.getCode(consts_1.L2_PROXY_ADMIN_ADDRESS); if (typeof code === "string") { return code != "0x" && code.length > 2; } return false; } /** * Override to skip checkTransaction step which rejects Celo tx properties * https://github.com/ethers-io/ethers.js/blob/master/packages/abstract-signer/src.ts/index.ts */ async populateTransaction(transaction) { let tx = await (0, ethers_1.resolveProperties)(transaction); if ((0, utils_1.isEmpty)(tx.from)) { tx.from = this.address; } if ((0, utils_1.isEmpty)(tx.nonce)) { tx.nonce = await this.provider?.getTransactionCount(tx.from, "pending"); } if ((0, utils_1.isEmpty)(tx.gasLimit)) { try { tx.gasLimit = await this.estimateGas(tx); } catch (error) { // If there is an error code it's an expected error if (forwardErrors.indexOf(error.code) >= 0) { throw error; } // If there is no error code it's an unexpected error (0, ethers_1.assertArgument)(false, "cannot estimate gas; transaction may fail or may require manual gas limit", "transaction", { error: error, tx: tx, }); } } await this.populateFees(tx); if ((0, utils_1.isEmpty)(tx.chainId)) { tx.chainId = (await this.provider.getNetwork()).chainId; } else { tx.chainId = Promise.all([ tx.chainId, (await this.provider.getNetwork()).chainId, ]).then(([txChainId, providerChainId]) => { if (providerChainId !== 0n && txChainId !== providerChainId) { (0, ethers_1.assertArgument)(false, "chainId address mismatch", "transaction", transaction); } return txChainId; }); } return (0, ethers_1.resolveProperties)(tx); } // sets feedata for the transaction. // async populateFees(tx) { const noFeeCurrency = !tx.feeCurrency; const useCIP66ForEasyFeeTransactions = false; // cip66 is not yet implemented in nodes // CIP 66 transactions are denominated in CELO not the fee token const feesAreInCELO = noFeeCurrency || useCIP66ForEasyFeeTransactions; if ((0, utils_1.isEmpty)(tx.maxPriorityFeePerGas) || (0, utils_1.isEmpty)(tx.maxFeePerGas)) { const { maxFeePerGas, maxPriorityFeePerGas } = (await this.provider?.getFeeData(tx.feeCurrency, feesAreInCELO)); tx.maxFeePerGas = maxFeePerGas; tx.maxPriorityFeePerGas = maxPriorityFeePerGas; if (useCIP66ForEasyFeeTransactions && (0, utils_1.isEmpty)(tx.maxFeeInFeeCurrency)) { const gasLimit = BigInt(tx.gasLimit); const maxFeeInFeeCurrency = await this.estimateMaxFeeInFeeToken({ feeCurrency: tx.feeCurrency, gasLimit, maxFeePerGas: maxFeePerGas, }); tx.maxFeeInFeeCurrency = maxFeeInFeeCurrency; } } return tx; } /** * Override to serialize transaction using custom serialize method * https://github.com/ethers-io/ethers.js/blob/master/packages/wallet/src.ts/index.ts */ async signTransaction(transaction) { const tx = await this.populateTransaction(transaction); if (tx.from != null) { if ((0, ethers_1.getAddress)(tx.from) !== this.address) { (0, ethers_1.assertArgument)(false, "transaction from address mismatch", "transaction.from", transaction.from); } delete tx.from; } const signature = this.signingKey.sign((0, ethers_1.keccak256)((0, transactions_1.serializeCeloTransaction)(tx))); const serialized = (0, transactions_1.serializeCeloTransaction)(tx, signature); return serialized; } /** * Override to serialize transaction using custom serialize method */ async sendTransaction(transaction) { const provider = this.provider; const pop = await this.populateTransaction(transaction); delete pop.from; return await provider.broadcastTransaction(await this.signTransaction(pop)); } /** * Override to skip checkTransaction step which rejects Celo tx properties * https://github.com/ethers-io/ethers.js/blob/master/packages/abstract-signer/src.ts/index.ts */ async estimateGas(transaction) { return this.provider.estimateGas(transaction).then(utils_1.adjustForGasInflation); } /** * @remarks For cip 66 transactions it is necessary to provide the absolute limit one is willing to pay denominated in the token. * In contrast with earlier tx types for fee currencies (celo legacy, cip42, cip 64). * Calulating Estimation requires the gas, maxfeePerGas and the conversion rate from CELO to feeToken * https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0066.md * * @dev cip66 has yet to be implemented on celo nodes. Dont add maxFeeInFeeCurrency to your transaction. use cip64 */ async estimateMaxFeeInFeeToken({ gasLimit, maxFeePerGas, feeCurrency, }) { const maxGasFeesInCELO = gasLimit * maxFeePerGas; const [numerator, denominator] = await (0, CoreContract_1.getConversionRateFromCeloToToken)(feeCurrency, this); const feeDenominatedInToken = (0, utils_1.convertFromCeloToToken)({ amountInCelo: maxGasFeesInCELO, ratioTOKEN: numerator, ratioCELO: denominator, }); return feeDenominatedInToken; } /** * Override to support alternative gas currencies * @dev (for cip66 txn you want gasPrice in CELO so dont pass in the feeToken) * https://github.com/celo-tools/ethers.js/blob/master/packages/abstract-signer/src.ts/index.ts */ async getGasPrice(feeCurrencyAddress) { return await this.provider._perform({ method: "getGasPrice", feeCurrencyAddress, }); } static fromMnemonic(phrase, path, wordlist) { const hdWallet = ethers_1.HDNodeWallet.fromMnemonic(ethers_1.Mnemonic.fromPhrase(phrase, null, wordlist), path); return new CeloWallet(hdWallet.privateKey, new CeloProvider_1.default()); } /** * Override just for type fix * https://github.com/ethers-io/ethers.js/blob/master/packages/wallet/src.ts/index.ts */ connect(provider) { return new CeloWallet(this.signingKey, provider); } } exports.default = CeloWallet; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2Vsb1dhbGxldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvQ2Vsb1dhbGxldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLG1DQWFnQjtBQUNoQixrRUFBMEM7QUFDMUMsK0NBSTZCO0FBQzdCLGlEQUl3QjtBQUN4QixzQ0FBbUQ7QUFDbkQsaURBQWtFO0FBRWxFLE1BQU0sYUFBYSxHQUFHO0lBQ3BCLG9CQUFvQjtJQUNwQixlQUFlO0lBQ2YseUJBQXlCO0NBQ1gsQ0FBQztBQUVqQixNQUFxQixVQUFXLFNBQVEsZUFBTTtJQUM1QyxLQUFLLENBQUMsTUFBTTtRQUNWLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsK0JBQXNCLENBQUMsQ0FBQztRQUNsRSxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsRUFBRTtZQUM1QixPQUFPLElBQUksSUFBSSxJQUFJLElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7U0FDeEM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsbUJBQW1CLENBQ3ZCLFdBQW1DO1FBRW5DLElBQUksRUFBRSxHQUFRLE1BQU0sSUFBQSwwQkFBaUIsRUFBQyxXQUFXLENBQUMsQ0FBQztRQUVuRCxJQUFJLElBQUEsZUFBTyxFQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUNwQixFQUFFLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUM7U0FDeEI7UUFDRCxJQUFJLElBQUEsZUFBTyxFQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUNyQixFQUFFLENBQUMsS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsRUFBRSxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1NBQ3pFO1FBQ0QsSUFBSSxJQUFBLGVB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