Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/mean-spies-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/sdk': minor
---

New isL2Provider helper function. Internal cleanups.
24 changes: 12 additions & 12 deletions packages/sdk/src/adapters/dai-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,29 @@ export class DAIBridgeAdapter extends StandardBridgeAdapter {
[
{
inputs: [],
name: 'l1Token',
name: 'l1Token' as const,
outputs: [
{
internalType: 'address',
name: '',
type: 'address',
internalType: 'address' as const,
name: '' as const,
type: 'address' as const,
},
],
stateMutability: 'view',
type: 'function',
stateMutability: 'view' as const,
type: 'function' as const,
},
{
inputs: [],
name: 'l2Token',
name: 'l2Token' as const,
outputs: [
{
internalType: 'address',
name: '',
type: 'address',
internalType: 'address' as const,
name: '' as const,
type: 'address' as const,
},
],
stateMutability: 'view',
type: 'function',
stateMutability: 'view' as const,
type: 'function' as const,
},
],
this.messenger.l1Provider
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/adapters/eth-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export class ETHBridgeAdapter extends StandardBridgeAdapter {
opts?: {
overrides?: Overrides
}
): Promise<TransactionRequest> => {
): Promise<never> => {
Comment thread
roninjin10 marked this conversation as resolved.
throw new Error(`approvals not necessary for ETH bridge`)
},

Expand Down
11 changes: 4 additions & 7 deletions packages/sdk/src/cross-chain-messenger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,15 @@ export class CrossChainMessenger implements ICrossChainMessenger {
if (Provider.isProvider(this.l1SignerOrProvider)) {
return this.l1SignerOrProvider
} else {
return this.l1SignerOrProvider.provider as any
return this.l1SignerOrProvider.provider
Comment thread
roninjin10 marked this conversation as resolved.
}
}

get l2Provider(): Provider {
if (Provider.isProvider(this.l2SignerOrProvider)) {
return this.l2SignerOrProvider
} else {
return this.l2SignerOrProvider.provider as any
return this.l2SignerOrProvider.provider
}
}

Expand All @@ -144,10 +144,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
} = {}
): Promise<CrossChainMessage[]> {
// Wait for the transaction receipt if the input is waitable.
// TODO: Maybe worth doing this with more explicit typing but whatever for now.
if (typeof (transaction as any).wait === 'function') {
await (transaction as any).wait()
}
await (transaction as TransactionResponse).wait?.()

// Convert the input to a transaction hash.
const txHash = toTransactionHash(transaction)
Expand Down Expand Up @@ -821,7 +818,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
)

const stateTrieProof = await makeStateTrieProof(
this.l2Provider as any,
this.l2Provider as ethers.providers.JsonRpcProvider,
resolved.blockNumber,
this.contracts.l2.OVM_L2ToL1MessagePasser.address,
messageSlot
Expand Down
6 changes: 6 additions & 0 deletions packages/sdk/src/interfaces/l2-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,10 @@ export type L2Provider<TProvider extends Provider> = TProvider & {
* @returns Estimated total gas cost.
*/
estimateTotalGasCost(tx: TransactionRequest): Promise<BigNumber>

/**
* Internal property to determine if a provider is a L2Provider
* You are likely looking for the isL2Provider function
*/
_isL2Provider: true
}
10 changes: 10 additions & 0 deletions packages/sdk/src/interfaces/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ import { Contract, BigNumber } from 'ethers'
import { ICrossChainMessenger } from './cross-chain-messenger'
import { IBridgeAdapter } from './bridge-adapter'

/**
* Commonly used Chain IDs
*/
export enum Chain {
MAINNET = 1,
GOERLI = 5,
KOVAN = 42,
HARDHAT_LOCAL = 31337,
}

/**
* L1 contract references.
*/
Expand Down
41 changes: 31 additions & 10 deletions packages/sdk/src/l2-provider.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import assert from 'assert'

import { Provider, TransactionRequest } from '@ethersproject/abstract-provider'
import { serialize } from '@ethersproject/transactions'
import { Contract, BigNumber } from 'ethers'
Expand All @@ -7,6 +9,8 @@ import cloneDeep from 'lodash/cloneDeep'
import { L2Provider, ProviderLike, NumberLike } from './interfaces'
import { toProvider, toNumber, toBigNumber } from './utils'

type ProviderTypeIsWrong = any

/**
* Returns a Contract object for the GasPriceOracle.
*
Expand Down Expand Up @@ -115,6 +119,24 @@ export const estimateTotalGasCost = async (
return l1GasCost.add(l2GasCost)
}

/**
* Determines if a given Provider is an L2Provider. Will coerce type
* if true
*
* @param provider The provider to check
* @returns Boolean
* @example
* if (isL2Provider(provider)) {
* // typescript now knows it is of type L2Provider
* const gasPrice = await provider.estimateL2GasPrice(tx)
* }
*/
export const isL2Provider = <TProvider extends Provider>(
provider: TProvider
): provider is L2Provider<TProvider> => {
return Boolean((provider as L2Provider<TProvider>)._isL2Provider)
}

/**
* Returns an provider wrapped as an Optimism L2 provider. Adds a few extra helper functions to
* simplify the process of estimating the gas usage for a transaction on Optimism. Returns a COPY
Expand All @@ -126,22 +148,21 @@ export const estimateTotalGasCost = async (
export const asL2Provider = <TProvider extends Provider>(
provider: TProvider
): L2Provider<TProvider> => {
// Make a copy of the provider since we'll be modifying some internals and don't want to mess
// with the original object.
const l2Provider = cloneDeep(provider) as any

// Skip if we've already wrapped this provider.
if (l2Provider._isL2Provider) {
return l2Provider
if (isL2Provider(provider)) {
return provider
}

// Make a copy of the provider since we'll be modifying some internals and don't want to mess
// with the original object.
const l2Provider = cloneDeep(provider) as L2Provider<TProvider>

// Not exactly sure when the provider wouldn't have a formatter function, but throw an error if
// it doesn't have one. The Provider type doesn't define it but every provider I've dealt with
// seems to have it.
const formatter = l2Provider.formatter
if (formatter === undefined) {
throw new Error(`provider.formatter must be defined`)
}
// TODO this may be fixed if library has gotten updated since
const formatter = (l2Provider as ProviderTypeIsWrong).formatter
assert(formatter, `provider.formatter must be defined`)

// Modify the block formatter to return the state root. Not strictly related to Optimism, just a
// generally useful thing that really should've been on the Ethers block object to begin with.
Expand Down
26 changes: 10 additions & 16 deletions packages/sdk/src/utils/chain-constants.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import { Chain } from '../interfaces'

export const DEPOSIT_CONFIRMATION_BLOCKS = {
// Mainnet
1: 50,
// Goerli
5: 12,
// Kovan
42: 12,
// Hardhat Local
[Chain.MAINNET]: 50 as const,
[Chain.GOERLI]: 12 as const,
[Chain.KOVAN]: 12 as const,
// 2 just for testing purposes
31337: 2,
[Chain.HARDHAT_LOCAL]: 2 as const,
}

export const CHAIN_BLOCK_TIMES = {
// Mainnet
1: 13,
// Goerli
5: 15,
// Kovan
42: 4,
// Hardhat Local
31337: 1,
[Chain.MAINNET]: 13 as const,
[Chain.GOERLI]: 15 as const,
[Chain.KOVAN]: 4 as const,
[Chain.HARDHAT_LOCAL]: 1 as const,
}
7 changes: 3 additions & 4 deletions packages/sdk/src/utils/coercion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export const toSignerOrProvider = (
if (typeof signerOrProvider === 'string') {
return new ethers.providers.JsonRpcProvider(signerOrProvider)
} else if (Provider.isProvider(signerOrProvider)) {
return signerOrProvider as Provider
return signerOrProvider
} else if (Signer.isSigner(signerOrProvider)) {
return signerOrProvider as Signer
return signerOrProvider
} else {
throw new Error('Invalid provider')
}
Expand All @@ -48,7 +48,7 @@ export const toProvider = (provider: ProviderLike): Provider => {
if (typeof provider === 'string') {
return new ethers.providers.JsonRpcProvider(provider)
} else if (Provider.isProvider(provider)) {
return provider as Provider
return provider
} else {
throw new Error('Invalid provider')
}
Expand All @@ -66,7 +66,6 @@ export const toTransactionHash = (transaction: TransactionLike): string => {
ethers.utils.isHexString(transaction, 32),
'Invalid transaction hash'
)

return transaction
} else if ((transaction as TransactionReceipt).transactionHash) {
return (transaction as TransactionReceipt).transactionHash
Expand Down
Loading