Skip to content

Commit

Permalink
updated with base token changes
Browse files Browse the repository at this point in the history
and files that need to be copied
  • Loading branch information
kelemeno authored and danijelTxFusion committed Jan 8, 2024
1 parent a1411a9 commit 70db89a
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 20 deletions.
2 changes: 1 addition & 1 deletion scripts/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ solc --base-path system-contracts \
mkdir abi /abi
mv l1-abi/* system-contracts-abi/* abi

contracts="IBridgehub.abi IL1Bridge.abi IL2Bridge.abi IContractDeployer.abi IEthToken.abi IL1Messenger.abi INonceHolder.abi IPaymasterFlow.abi"
contracts="IBridgehub.abi IZkSyncStateTransition.abi IStateTransitionChain.abi IL1Bridge.abi IL2Bridge.abi IContractDeployer.abi IEthToken.abi IL1Messenger.abi INonceHolder.abi IPaymasterFlow.abi ITestnetERC20Token.abi"

for filename in $contracts; do
jq '.' "abi/$filename" > "/abi/${filename%.abi}.json"
Expand Down
227 changes: 211 additions & 16 deletions src/adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {Il2BridgeFactory as IL2BridgeFactory} from "../typechain/Il2BridgeFactor
import {IBridgehubFactory} from "../typechain/IBridgehubFactory";
import {IBridgehub} from "../typechain/IBridgehub";
import {INonceHolderFactory} from "../typechain/INonceHolderFactory";
import {IStateTransitionChainFactory} from "../typechain/IStateTransitionChainFactory";
import {IStateTransitionChain} from "../typechain/IStateTransitionChain";
import {Provider} from "./provider";
import {
Address,
Expand All @@ -22,6 +24,7 @@ import {
estimateCustomBridgeDepositL2Gas,
estimateDefaultBridgeDepositL2Gas,
ETH_ADDRESS,
ETH_ADDRESS_IN_CONTRACTS,
getERC20DefaultBridgeData,
isETH,
L1_MESSENGER_ADDRESS,
Expand Down Expand Up @@ -58,6 +61,11 @@ export function AdapterL1<TBase extends Constructor<TxSender>>(Base: TBase) {
throw new Error("Must be implemented by the derived class!");
}

async getMainContract(): Promise<IStateTransitionChain> {
const address = await this._providerL2().getMainContractAddress();
return IStateTransitionChainFactory.connect(address, this._signerL1());
}

async getBridgehubContract(): Promise<IBridgehub> {
const address = await this._providerL2().getBridgehubContractAddress();
return IBridgehubFactory.connect(address, this._signerL1());
Expand Down Expand Up @@ -186,6 +194,7 @@ export function AdapterL1<TBase extends Constructor<TxSender>>(Base: TBase) {
operatorTip?: BigNumberish;
bridgeAddress?: Address;
approveERC20?: boolean;
approveBaseERC20?: boolean;
l2GasLimit?: BigNumberish;
gasPerPubdataByte?: BigNumberish;
refundRecipient?: Address;
Expand All @@ -194,17 +203,21 @@ export function AdapterL1<TBase extends Constructor<TxSender>>(Base: TBase) {
customBridgeData?: BytesLike;
}): Promise<PriorityOpResponse> {
const depositTx = await this.getDepositTx(transaction);
const bridgehub = await this.getBridgehubContract();
const chainId = (await this._providerL2().getNetwork()).chainId;
const baseTokenAddress = await bridgehub.baseToken(chainId);
const baseTokenBridge = await bridgehub.baseTokenBridge(chainId);
const bridgeContracts = await this.getL1BridgeContracts();

if (transaction.token == ETH_ADDRESS) {
if ((transaction.token == ETH_ADDRESS) && (baseTokenAddress == ETH_ADDRESS_IN_CONTRACTS)) {
const baseGasLimit = await this.estimateGasRequestExecute(depositTx);
const gasLimit = scaleGasLimit(baseGasLimit);

depositTx.overrides ??= {};
depositTx.overrides.gasLimit ??= gasLimit;

return this.requestExecute(depositTx);
} else {
const bridgeContracts = await this.getL1BridgeContracts();
} else if (baseTokenAddress == ETH_ADDRESS_IN_CONTRACTS) {
if (transaction.approveERC20) {
let l2WethToken = ethers.constants.AddressZero;
try {
Expand Down Expand Up @@ -240,6 +253,114 @@ export function AdapterL1<TBase extends Constructor<TxSender>>(Base: TBase) {

depositTx.gasLimit ??= gasLimit;

return await this._providerL2().getPriorityOpResponse(
await this._signerL1().sendTransaction(depositTx),
);
} else if (transaction.token == ETH_ADDRESS) {
const mintValue = parseInt(depositTx.data.slice(2+8+3*64, 2+8+4*64), 16);
// we are depositing eth into a non-eth based chain. We go through the weth bridge.
if (transaction.approveBaseERC20) {
// We only request the allowance if the current one is not enough.
const allowance = await this.getAllowanceL1(baseTokenAddress, baseTokenBridge);
if (allowance.lt(mintValue)) {
const approveTx = await this.approveERC20(
baseTokenAddress,
mintValue,
{
bridgeAddress: baseTokenBridge,
...transaction.approveOverrides,
},
);
await approveTx.wait();
}
}

const baseGasLimit = await this._providerL1().estimateGas(depositTx);
const gasLimit = scaleGasLimit(baseGasLimit);

depositTx.gasLimit ??= gasLimit;

return await this._providerL2().getPriorityOpResponse(
await this._signerL1().sendTransaction(depositTx),
);

} else if (transaction.token == baseTokenAddress) {
const mintValue = depositTx.mintValue;
// we are bridging the base token to a non-eth based chain. We go through the bridgehub, and give approval
if ((transaction.approveERC20) || (transaction.approveBaseERC20)) {
// We only request the allowance if the current one is not enough.
const allowance = await this.getAllowanceL1(baseTokenAddress, baseTokenBridge);
if (allowance.lt(mintValue)) {
const approveTx = await this.approveERC20(
baseTokenAddress,
mintValue,
{
bridgeAddress: baseTokenBridge,
...transaction.approveOverrides,
},
);
await approveTx.wait();
}
}
const baseGasLimit = await this.estimateGasRequestExecute(depositTx);
const gasLimit = scaleGasLimit(baseGasLimit);

depositTx.overrides ??= {};
depositTx.overrides.gasLimit ??= gasLimit;

return this.requestExecute(depositTx);
} else {
const mintValue = parseInt(depositTx.data.slice(2+8+3*64, 2+8+4*64), 16);
// we are depositing a non-eth and non-base token to a non-eth based chain. We go through the bridgehub, and give approval for both tokens
if (transaction.approveERC20) {
let l2WethToken = ethers.constants.AddressZero;
try {
l2WethToken = await bridgeContracts.weth.l2TokenAddress(transaction.token);
} catch (e) {}
// If the token is Wrapped Ether, use its bridge.
const proposedBridge =
l2WethToken != ethers.constants.AddressZero
? bridgeContracts.weth.address
: bridgeContracts.erc20.address;
const bridgeAddress = transaction.bridgeAddress
? transaction.bridgeAddress
: proposedBridge;

// We only request the allowance if the current one is not enough.
const allowance = await this.getAllowanceL1(transaction.token, bridgeAddress);
if (allowance.lt(transaction.amount)) {
const approveTx = await this.approveERC20(
transaction.token,
transaction.amount,
{
bridgeAddress,
...transaction.approveOverrides,
},
);
await approveTx.wait();
}
}
if (transaction.approveBaseERC20) {
// We only request the allowance if the current one is not enough.
const allowance = await this.getAllowanceL1(baseTokenAddress, baseTokenBridge);
if (allowance.lt(mintValue)) {
const approveTx = await this.approveERC20(
baseTokenAddress,
mintValue,
{
bridgeAddress: baseTokenBridge,
...transaction.approveOverrides,
},
);
await approveTx.wait();
}
}

const baseGasLimit = await this._providerL1().estimateGas(depositTx);
const gasLimit = scaleGasLimit(baseGasLimit);

depositTx.gasLimit ??= gasLimit;

return await this._providerL2().getPriorityOpResponse(
await this._signerL1().sendTransaction(depositTx),
);
Expand Down Expand Up @@ -328,42 +449,108 @@ export function AdapterL1<TBase extends Constructor<TxSender>>(Base: TBase) {
const gasPriceForEstimation = overrides.maxFeePerGas || overrides.gasPrice;

const bridgehub = await this.getBridgehubContract();
const chainId = (await this._providerL2().getNetwork()).chainId;
const baseTokenAddress = await bridgehub.baseToken(chainId);

const baseCost = await bridgehub.l2TransactionBaseCost(
(await this._providerL2().getNetwork()).chainId,
chainId,
await gasPriceForEstimation,
tx.l2GasLimit,
tx.gasPerPubdataByte,
);

if (token == ETH_ADDRESS) {
if ((token == ETH_ADDRESS) && (baseTokenAddress == ETH_ADDRESS_IN_CONTRACTS)) {
// we are depositing Eth to an Eth based chain
overrides.value ??= baseCost.add(operatorTip).add(amount);

return {
contractAddress: to,
calldata: "0x",
mintValue: overrides.value,
l2Value: amount,
// For some reason typescript can not deduce that we've already set the
// tx.l2GasLimit
l2GasLimit: tx.l2GasLimit!,
...tx,
};
} else {
} else if (baseTokenAddress == ETH_ADDRESS_IN_CONTRACTS) {
// we are depositing some token to an Eth based chain
overrides.value ??= baseCost.add(operatorTip);
await checkBaseCost(baseCost, overrides.value);

let refundRecipient = tx.refundRecipient ?? ethers.constants.AddressZero;
const args: [BigNumberish, Address, Address, BigNumberish, BigNumberish, BigNumberish, BigNumberish, Address] = [
(await this._providerL2().getNetwork()).chainId,
to,
token,
BigNumber.from(0), // TODO CHANGE THIS
await overrides.value, // TODO CHANGE THIS
amount,
tx.l2GasLimit,
tx.gasPerPubdataByte,
refundRecipient,
];

overrides.value ??= baseCost.add(operatorTip);
await checkBaseCost(baseCost, overrides.value);
// check if we're depositing weth
let l2WethToken = ethers.constants.AddressZero;
try {
l2WethToken = await bridgeContracts.weth.l2TokenAddress(tx.token);
} catch (e) {}

const bridge =
l2WethToken != ethers.constants.AddressZero
? bridgeContracts.weth
: bridgeContracts.erc20;
return await bridge.populateTransaction.deposit(...args, overrides);
} else if (token == ETH_ADDRESS) {
// we are depositing eth into a non-eth based chain. We go through the weth bridge.
overrides.value ??= amount;
await checkBaseCost(baseCost, baseCost.add(operatorTip)); // this is base token, not eth

let refundRecipient = tx.refundRecipient ?? ethers.constants.AddressZero;
const args: [BigNumberish, Address, Address, BigNumberish, BigNumberish, BigNumberish, BigNumberish, Address] = [
(await this._providerL2().getNetwork()).chainId,
to,
ETH_ADDRESS_IN_CONTRACTS,
baseCost.add(operatorTip), // of the base token, not eth
0, // amount of weth deposited is 0, eth is in msg.value
tx.l2GasLimit,
tx.gasPerPubdataByte,
refundRecipient,
];

return await bridgeContracts.weth.populateTransaction.deposit(...args, overrides);
} else if (token == baseTokenAddress){
overrides.value ??= 0;
// we are bridging the base token to a non-eth based chain. We go through the bridgehub
return {
contractAddress: to,
calldata: "0x",
mintValue: baseCost.add(operatorTip).add(amount),
l2Value: amount,
// For some reason typescript can not deduce that we've already set the
// tx.l2GasLimit
l2GasLimit: tx.l2GasLimit!,
...tx,
};
} else {
// we are bridging not eth and not the base token to a non-eth based chain
let mintValue = baseCost.add(operatorTip);
await checkBaseCost(baseCost, mintValue);
overrides.value ??= 0;

let refundRecipient = tx.refundRecipient ?? ethers.constants.AddressZero;
const args: [BigNumberish, Address, Address, BigNumberish, BigNumberish, BigNumberish, BigNumberish, Address] = [
(await this._providerL2().getNetwork()).chainId,
to,
token,
mintValue,
amount,
tx.l2GasLimit,
tx.gasPerPubdataByte,
refundRecipient,
];

// check if we're depositing weth
let l2WethToken = ethers.constants.AddressZero;
try {
l2WethToken = await bridgeContracts.weth.l2TokenAddress(tx.token);
Expand Down Expand Up @@ -578,8 +765,9 @@ export function AdapterL1<TBase extends Constructor<TxSender>>(Base: TBase) {

const contractAddress = await this._providerL2().getBridgehubContractAddress();
const bridgehub = IBridgehubFactory.connect(contractAddress, this._signerL1());
const wethBridge = IL1BridgeFactory.connect(await bridgehub.wethBridge(), this._signerL1());

return await bridgehub.finalizeEthWithdrawal(
return await wethBridge.finalizeWithdrawal(
(await this._providerL2().getNetwork()).chainId,
l1BatchNumber,
l2MessageIndex,
Expand Down Expand Up @@ -704,7 +892,9 @@ export function AdapterL1<TBase extends Constructor<TxSender>>(Base: TBase) {
async getRequestExecuteTx(transaction: {
contractAddress: Address;
calldata: BytesLike;
payer?: Address;
l2GasLimit?: BigNumberish;
mintValue?: BigNumberish;
l2Value?: BigNumberish;
factoryDeps?: ethers.BytesLike[];
operatorTip?: BigNumberish;
Expand All @@ -713,9 +903,13 @@ export function AdapterL1<TBase extends Constructor<TxSender>>(Base: TBase) {
overrides?: ethers.PayableOverrides;
}): Promise<ethers.PopulatedTransaction> {
const bridgehub = await this.getBridgehubContract();
const chainId = (await this._providerL2().getNetwork()).chainId;
const ethIsBaseToken = (await bridgehub.baseToken(chainId) == ETH_ADDRESS_IN_CONTRACTS);

const {...tx} = transaction;
tx.l2Value ??= BigNumber.from(0);
tx.payer ??= await this.getAddress();
tx.mintValue ??= BigNumber.from(0);
tx.operatorTip ??= BigNumber.from(0);
tx.factoryDeps ??= [];
tx.overrides ??= {};
Expand All @@ -725,6 +919,8 @@ export function AdapterL1<TBase extends Constructor<TxSender>>(Base: TBase) {

const {
contractAddress,
payer,
mintValue,
l2Value,
calldata,
l2GasLimit,
Expand All @@ -746,20 +942,19 @@ export function AdapterL1<TBase extends Constructor<TxSender>>(Base: TBase) {

overrides.value ??= baseCost.add(operatorTip).add(l2Value);

await checkBaseCost(baseCost, overrides.value);
await checkBaseCost(baseCost, ethIsBaseToken? overrides.value : mintValue);

return await bridgehub.populateTransaction.requestL2Transaction(
{
chainId: (await this._providerL2().getNetwork()).chainId,
return await bridgehub.populateTransaction.requestL2Transaction({
chainId,
payer: payer,
l2Contract: contractAddress,
mintValue: mintValue,
l2Value: l2Value,
l2Calldata: calldata,
l2GasLimit: l2GasLimit,
l2GasPerPubdataByteLimit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT,
factoryDeps: factoryDeps,
refundRecipient: refundRecipient,
payer: null, // TODO CHANGE THIS
mintValue: BigNumber.from(0) // TODO CHANGE THIS
},
overrides,
);
Expand Down
Loading

0 comments on commit 70db89a

Please sign in to comment.