Commit 0c54e60e authored by kf's avatar kf

feat(sdk): add approval fns to the SDK

parent 67a0414d
---
'@eth-optimism/sdk': patch
---
Add approval functions to the SDK
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
import { ethers, Overrides } from 'ethers' import { ethers, Contract, Overrides, BigNumber } from 'ethers'
import { TransactionRequest, BlockTag } from '@ethersproject/abstract-provider' import { TransactionRequest, BlockTag } from '@ethersproject/abstract-provider'
import { predeploys } from '@eth-optimism/contracts' import { predeploys, getContractInterface } from '@eth-optimism/contracts'
import { hexStringEquals } from '@eth-optimism/core-utils' import { hexStringEquals } from '@eth-optimism/core-utils'
import { import {
...@@ -17,6 +17,14 @@ import { StandardBridgeAdapter } from './standard-bridge' ...@@ -17,6 +17,14 @@ import { StandardBridgeAdapter } from './standard-bridge'
* Bridge adapter for the ETH bridge. * Bridge adapter for the ETH bridge.
*/ */
export class ETHBridgeAdapter extends StandardBridgeAdapter { export class ETHBridgeAdapter extends StandardBridgeAdapter {
public async approval(
l1Token: AddressLike,
l2Token: AddressLike,
signer: ethers.Signer
): Promise<BigNumber> {
throw new Error(`approval not necessary for ETH bridge`)
}
public async getDepositsByAddress( public async getDepositsByAddress(
address: AddressLike, address: AddressLike,
opts?: { opts?: {
...@@ -104,6 +112,17 @@ export class ETHBridgeAdapter extends StandardBridgeAdapter { ...@@ -104,6 +112,17 @@ export class ETHBridgeAdapter extends StandardBridgeAdapter {
} }
populateTransaction = { populateTransaction = {
approve: async (
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
overrides?: Overrides
}
): Promise<TransactionRequest> => {
throw new Error(`approvals not necessary for ETH bridge`)
},
deposit: async ( deposit: async (
l1Token: AddressLike, l1Token: AddressLike,
l2Token: AddressLike, l2Token: AddressLike,
......
...@@ -185,6 +185,38 @@ export class StandardBridgeAdapter implements IBridgeAdapter { ...@@ -185,6 +185,38 @@ export class StandardBridgeAdapter implements IBridgeAdapter {
} }
} }
public async approval(
l1Token: AddressLike,
l2Token: AddressLike,
signer: ethers.Signer
): Promise<BigNumber> {
if (!(await this.supportsTokenPair(l1Token, l2Token))) {
throw new Error(`token pair not supported by bridge`)
}
const token = new Contract(
toAddress(l1Token),
getContractInterface('L2StandardERC20'), // Any ERC20 will do
this.messenger.l1Provider
)
return token.allowance(await signer.getAddress(), this.l1Bridge.address)
}
public async approve(
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
signer: Signer,
opts?: {
overrides?: Overrides
}
): Promise<TransactionResponse> {
return signer.sendTransaction(
await this.populateTransaction.approve(l1Token, l2Token, amount, opts)
)
}
public async deposit( public async deposit(
l1Token: AddressLike, l1Token: AddressLike,
l2Token: AddressLike, l2Token: AddressLike,
...@@ -217,6 +249,31 @@ export class StandardBridgeAdapter implements IBridgeAdapter { ...@@ -217,6 +249,31 @@ export class StandardBridgeAdapter implements IBridgeAdapter {
} }
populateTransaction = { populateTransaction = {
approve: async (
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
overrides?: Overrides
}
): Promise<TransactionRequest> => {
if (!(await this.supportsTokenPair(l1Token, l2Token))) {
throw new Error(`token pair not supported by bridge`)
}
const token = new Contract(
toAddress(l1Token),
getContractInterface('L2StandardERC20'), // Any ERC20 will do
this.messenger.l1Provider
)
return token.populateTransaction.approve(
this.l1Bridge.address,
amount,
opts?.overrides || {}
)
},
deposit: async ( deposit: async (
l1Token: AddressLike, l1Token: AddressLike,
l2Token: AddressLike, l2Token: AddressLike,
...@@ -288,6 +345,19 @@ export class StandardBridgeAdapter implements IBridgeAdapter { ...@@ -288,6 +345,19 @@ export class StandardBridgeAdapter implements IBridgeAdapter {
} }
estimateGas = { estimateGas = {
approve: async (
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
overrides?: Overrides
}
): Promise<BigNumber> => {
return this.messenger.l1Provider.estimateGas(
await this.populateTransaction.approve(l1Token, l2Token, amount, opts)
)
},
deposit: async ( deposit: async (
l1Token: AddressLike, l1Token: AddressLike,
l2Token: AddressLike, l2Token: AddressLike,
......
...@@ -109,7 +109,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -109,7 +109,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
if (Provider.isProvider(this.l1SignerOrProvider)) { if (Provider.isProvider(this.l1SignerOrProvider)) {
return this.l1SignerOrProvider return this.l1SignerOrProvider
} else { } else {
return this.l1SignerOrProvider.provider return this.l1SignerOrProvider.provider as any
} }
} }
...@@ -117,7 +117,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -117,7 +117,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
if (Provider.isProvider(this.l2SignerOrProvider)) { if (Provider.isProvider(this.l2SignerOrProvider)) {
return this.l2SignerOrProvider return this.l2SignerOrProvider
} else { } else {
return this.l2SignerOrProvider.provider return this.l2SignerOrProvider.provider as any
} }
} }
...@@ -844,6 +844,36 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -844,6 +844,36 @@ export class CrossChainMessenger implements ICrossChainMessenger {
) )
} }
public async approval(
l1Token: AddressLike,
l2Token: AddressLike,
opts?: {
signer?: Signer
}
): Promise<BigNumber> {
const bridge = await this.getBridgeForTokenPair(l1Token, l2Token)
return bridge.approval(l1Token, l2Token, opts?.signer || this.l1Signer)
}
public async approveERC20(
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
signer?: Signer
overrides?: Overrides
}
): Promise<TransactionResponse> {
return (opts?.signer || this.l1Signer).sendTransaction(
await this.populateTransaction.approveERC20(
l1Token,
l2Token,
amount,
opts
)
)
}
public async depositERC20( public async depositERC20(
l1Token: AddressLike, l1Token: AddressLike,
l2Token: AddressLike, l2Token: AddressLike,
...@@ -986,6 +1016,18 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -986,6 +1016,18 @@ export class CrossChainMessenger implements ICrossChainMessenger {
) )
}, },
approveERC20: async (
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
overrides?: Overrides
}
): Promise<TransactionRequest> => {
const bridge = await this.getBridgeForTokenPair(l1Token, l2Token)
return bridge.populateTransaction.approve(l1Token, l2Token, amount, opts)
},
depositERC20: async ( depositERC20: async (
l1Token: AddressLike, l1Token: AddressLike,
l2Token: AddressLike, l2Token: AddressLike,
...@@ -1082,6 +1124,24 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -1082,6 +1124,24 @@ export class CrossChainMessenger implements ICrossChainMessenger {
) )
}, },
approveERC20: async (
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
overrides?: Overrides
}
): Promise<BigNumber> => {
return this.l1Provider.estimateGas(
await this.populateTransaction.approveERC20(
l1Token,
l2Token,
amount,
opts
)
)
},
depositERC20: async ( depositERC20: async (
l1Token: AddressLike, l1Token: AddressLike,
l2Token: AddressLike, l2Token: AddressLike,
......
...@@ -78,6 +78,41 @@ export interface IBridgeAdapter { ...@@ -78,6 +78,41 @@ export interface IBridgeAdapter {
l2Token: AddressLike l2Token: AddressLike
): Promise<boolean> ): Promise<boolean>
/**
* Queries the account's approval amount for a given L1 token.
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param signer Signer to query the approval for.
* @returns Amount of tokens approved for deposits from the account.
*/
approval(
l1Token: AddressLike,
l2Token: AddressLike,
signer: Signer
): Promise<BigNumber>
/**
* Approves a deposit into the L2 chain.
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to approve.
* @param signer Signer used to sign and send the transaction.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction response for the approval transaction.
*/
approve(
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
signer: Signer,
opts?: {
overrides?: Overrides
}
): Promise<TransactionResponse>
/** /**
* Deposits some tokens into the L2 chain. * Deposits some tokens into the L2 chain.
* *
...@@ -131,6 +166,25 @@ export interface IBridgeAdapter { ...@@ -131,6 +166,25 @@ export interface IBridgeAdapter {
* Follows the pattern used by ethers.js. * Follows the pattern used by ethers.js.
*/ */
populateTransaction: { populateTransaction: {
/**
* Generates a transaction for approving some tokens to deposit into the L2 chain.
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to approve.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to deposit the tokens.
*/
approve(
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
overrides?: Overrides
}
): Promise<TransactionRequest>
/** /**
* Generates a transaction for depositing some tokens into the L2 chain. * Generates a transaction for depositing some tokens into the L2 chain.
* *
...@@ -181,6 +235,25 @@ export interface IBridgeAdapter { ...@@ -181,6 +235,25 @@ export interface IBridgeAdapter {
* Follows the pattern used by ethers.js. * Follows the pattern used by ethers.js.
*/ */
estimateGas: { estimateGas: {
/**
* Estimates gas required to approve some tokens to deposit into the L2 chain.
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to approve.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @returns Gas estimate for the transaction.
*/
approve(
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
overrides?: Overrides
}
): Promise<BigNumber>
/** /**
* Estimates gas required to deposit some tokens into the L2 chain. * Estimates gas required to deposit some tokens into the L2 chain.
* *
......
...@@ -411,6 +411,44 @@ export interface ICrossChainMessenger { ...@@ -411,6 +411,44 @@ export interface ICrossChainMessenger {
} }
): Promise<TransactionResponse> ): Promise<TransactionResponse>
/**
* Queries the account's approval amount for a given L1 token.
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param opts Additional options.
* @param opts.signer Optional signer to get the approval for.
* @returns Amount of tokens approved for deposits from the account.
*/
approval(
l1Token: AddressLike,
l2Token: AddressLike,
opts?: {
signer?: Signer
}
): Promise<BigNumber>
/**
* Approves a deposit into the L2 chain.
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to approve.
* @param opts Additional options.
* @param opts.signer Optional signer to use to send the transaction.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction response for the approval transaction.
*/
approveERC20(
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
signer?: Signer
overrides?: Overrides
}
): Promise<TransactionResponse>
/** /**
* Deposits some ERC20 tokens into the L2 chain. * Deposits some ERC20 tokens into the L2 chain.
* *
...@@ -517,6 +555,25 @@ export interface ICrossChainMessenger { ...@@ -517,6 +555,25 @@ export interface ICrossChainMessenger {
} }
): Promise<TransactionRequest> ): Promise<TransactionRequest>
/**
* Generates a transaction for approving some tokens to deposit into the L2 chain.
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to approve.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction response for the approval transaction.
*/
approveERC20(
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
overrides?: Overrides
}
): Promise<TransactionRequest>
/** /**
* Generates a transaction for depositing some ETH into the L2 chain. * Generates a transaction for depositing some ETH into the L2 chain.
* *
...@@ -652,6 +709,25 @@ export interface ICrossChainMessenger { ...@@ -652,6 +709,25 @@ export interface ICrossChainMessenger {
} }
): Promise<BigNumber> ): Promise<BigNumber>
/**
* Estimates gas required to approve some tokens to deposit into the L2 chain.
*
* @param l1Token The L1 token address.
* @param l2Token The L2 token address.
* @param amount Amount of the token to approve.
* @param opts Additional options.
* @param opts.overrides Optional transaction overrides.
* @returns Transaction response for the approval transaction.
*/
approveERC20(
l1Token: AddressLike,
l2Token: AddressLike,
amount: NumberLike,
opts?: {
overrides?: Overrides
}
): Promise<BigNumber>
/** /**
* Estimates gas required to deposit some ETH into the L2 chain. * Estimates gas required to deposit some ETH into the L2 chain.
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment