UNPKG

@arbitrum/sdk

Version:

Typescript library client-side interactions with Arbitrum

148 lines (147 loc) 6.73 kB
/* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* eslint-env node */ 'use strict'; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChildTransactionReceipt = void 0; const signerOrProvider_1 = require("../dataEntities/signerOrProvider"); const ChildToParentMessage_1 = require("./ChildToParentMessage"); const ArbSys__factory_1 = require("../abi/factories/ArbSys__factory"); const ArbRetryableTx__factory_1 = require("../abi/factories/ArbRetryableTx__factory"); const NodeInterface__factory_1 = require("../abi/factories/NodeInterface__factory"); const errors_1 = require("../dataEntities/errors"); const constants_1 = require("../dataEntities/constants"); const event_1 = require("../dataEntities/event"); const arbProvider_1 = require("../utils/arbProvider"); /** * Extension of ethers-js TransactionReceipt, adding Arbitrum-specific functionality */ class ChildTransactionReceipt { constructor(tx) { this.to = tx.to; this.from = tx.from; this.contractAddress = tx.contractAddress; this.transactionIndex = tx.transactionIndex; this.root = tx.root; this.gasUsed = tx.gasUsed; this.logsBloom = tx.logsBloom; this.blockHash = tx.blockHash; this.transactionHash = tx.transactionHash; this.logs = tx.logs; this.blockNumber = tx.blockNumber; this.confirmations = tx.confirmations; this.cumulativeGasUsed = tx.cumulativeGasUsed; this.effectiveGasPrice = tx.effectiveGasPrice; this.byzantium = tx.byzantium; this.type = tx.type; this.status = tx.status; } /** * Get {@link ChildToParentTransactionEvent} events created by this transaction * @returns */ getChildToParentEvents() { const classicLogs = (0, event_1.parseTypedLogs)(ArbSys__factory_1.ArbSys__factory, this.logs, 'L2ToL1Transaction'); const nitroLogs = (0, event_1.parseTypedLogs)(ArbSys__factory_1.ArbSys__factory, this.logs, 'L2ToL1Tx'); return [...classicLogs, ...nitroLogs]; } /** * Get event data for any redeems that were scheduled in this transaction * @returns */ getRedeemScheduledEvents() { return (0, event_1.parseTypedLogs)(ArbRetryableTx__factory_1.ArbRetryableTx__factory, this.logs, 'RedeemScheduled'); } async getChildToParentMessages(parentSignerOrProvider) { const provider = signerOrProvider_1.SignerProviderUtils.getProvider(parentSignerOrProvider); if (!provider) throw new errors_1.ArbSdkError('Signer not connected to provider.'); return this.getChildToParentEvents().map(log => ChildToParentMessage_1.ChildToParentMessage.fromEvent(parentSignerOrProvider, log)); } /** * Get number of parent chain confirmations that the batch including this tx has * @param childProvider * @returns number of confirmations of batch including tx, or 0 if no batch included this tx */ getBatchConfirmations(childProvider) { const nodeInterface = NodeInterface__factory_1.NodeInterface__factory.connect(constants_1.NODE_INTERFACE_ADDRESS, childProvider); return nodeInterface.getL1Confirmations(this.blockHash); } /** * Get the number of the batch that included this tx (will throw if no such batch exists) * @param childProvider * @returns number of batch in which tx was included, or errors if no batch includes the current tx */ async getBatchNumber(childProvider) { const nodeInterface = NodeInterface__factory_1.NodeInterface__factory.connect(constants_1.NODE_INTERFACE_ADDRESS, childProvider); const arbProvider = new arbProvider_1.ArbitrumProvider(childProvider); const rec = await arbProvider.getTransactionReceipt(this.transactionHash); if (rec == null) throw new errors_1.ArbSdkError('No receipt receipt available for current transaction'); // findBatchContainingBlock errors if block number does not exist return nodeInterface.findBatchContainingBlock(rec.blockNumber); } /** * Whether the data associated with this transaction has been * made available on parent chain * @param childProvider * @param confirmations The number of confirmations on the batch before data is to be considered available * @returns */ async isDataAvailable(childProvider, confirmations = 10) { const res = await this.getBatchConfirmations(childProvider); // is there a batch with enough confirmations return res.toNumber() > confirmations; } /** * Adds a waitForRedeem function to a redeem transaction * @param redeemTx * @param childProvider * @returns */ static toRedeemTransaction(redeemTx, childProvider) { const returnRec = redeemTx; returnRec.waitForRedeem = async () => { const rec = await redeemTx.wait(); const redeemScheduledEvents = await rec.getRedeemScheduledEvents(); if (redeemScheduledEvents.length !== 1) { throw new errors_1.ArbSdkError(`Transaction is not a redeem transaction: ${rec.transactionHash}`); } return await childProvider.getTransactionReceipt(redeemScheduledEvents[0].retryTxHash); }; return returnRec; } } exports.ChildTransactionReceipt = ChildTransactionReceipt; _a = ChildTransactionReceipt; /** * Replaces the wait function with one that returns an L2TransactionReceipt * @param contractTransaction * @returns */ ChildTransactionReceipt.monkeyPatchWait = (contractTransaction) => { const wait = contractTransaction.wait; contractTransaction.wait = async (_confirmations) => { // we ignore the confirmations for now since child chain transactions shouldn't re-org // in future we should give users a more fine grained way to check the finality of // an child chain transaction - check if a batch is on a parent chain, if an assertion has been made, and if // it has been confirmed. const result = await wait(); return new _a(result); }; return contractTransaction; };