New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Arbitrum L1 to L2 messaging proposal #13516
Changes from 31 commits
f0cbaf2
85376b1
247edf0
2f0608f
b9c3467
20939ee
506fdc6
09aada2
6cd79c2
cd41637
80b6fe6
14273ca
6709e11
a6942e4
b54ffa4
347d6bf
98935ee
e98703b
6c9f33a
3e817b7
39b4e79
24d81c3
eabfe4d
cbdfb95
fa63c3d
0f7ec36
ce0e970
c1fd7d7
7bced2f
0a993b8
c9a28c1
4d42172
c33c977
79327c5
ace2d13
794914d
a82a7c0
debbbdf
6687533
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
cache | ||
contracts | ||
artifacts | ||
.env | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
|
||
# zksync | ||
zk-artifacts | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
const ethers = require('ethers') | ||
const { | ||
L1ToL2MessageGasEstimator, | ||
} = require('@arbitrum/sdk/dist/lib/message/L1ToL2MessageGasEstimator') | ||
const { EthBridger, getL2Network } = require('@arbitrum/sdk') | ||
const { getBaseFee } = require('@arbitrum/sdk/dist/lib/utils/lib') | ||
const { | ||
L1_RPC, | ||
L2_RPC, | ||
ARB_TOKEN_ADRESS_ON_L2, | ||
GRANTS_CONTRACT_ADDRESS, | ||
TIMELOCK_L2_ALIAS, | ||
L1_TIMELOCK_CONTRACT, | ||
} = require('./constants') | ||
|
||
const ERC20_ABI = [ | ||
{ | ||
inputs: [ | ||
{ | ||
internalType: 'address', | ||
name: 'account', | ||
type: 'address', | ||
}, | ||
], | ||
name: 'balanceOf', | ||
outputs: [ | ||
{ | ||
internalType: 'uint256', | ||
name: '', | ||
type: 'uint256', | ||
}, | ||
], | ||
stateMutability: 'view', | ||
type: 'function', | ||
}, | ||
{ | ||
inputs: [ | ||
{ | ||
internalType: 'address', | ||
name: 'to', | ||
type: 'address', | ||
}, | ||
{ | ||
internalType: 'uint256', | ||
name: 'amount', | ||
type: 'uint256', | ||
}, | ||
], | ||
name: 'transfer', | ||
outputs: [ | ||
{ | ||
internalType: 'bool', | ||
name: '', | ||
type: 'bool', | ||
}, | ||
], | ||
stateMutability: 'nonpayable', | ||
type: 'function', | ||
}, | ||
] | ||
clemsos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const INBOX_ABI = [ | ||
{ | ||
inputs: [ | ||
{ | ||
internalType: 'address', | ||
name: 'to', | ||
type: 'address', | ||
}, | ||
{ | ||
internalType: 'uint256', | ||
name: 'l2CallValue', | ||
type: 'uint256', | ||
}, | ||
{ | ||
internalType: 'uint256', | ||
name: 'maxSubmissionCost', | ||
type: 'uint256', | ||
}, | ||
{ | ||
internalType: 'address', | ||
name: 'excessFeeRefundAddress', | ||
type: 'address', | ||
}, | ||
{ | ||
internalType: 'address', | ||
name: 'callValueRefundAddress', | ||
type: 'address', | ||
}, | ||
{ | ||
internalType: 'uint256', | ||
name: 'gasLimit', | ||
type: 'uint256', | ||
}, | ||
{ | ||
internalType: 'uint256', | ||
name: 'maxFeePerGas', | ||
type: 'uint256', | ||
}, | ||
{ | ||
internalType: 'bytes', | ||
name: 'data', | ||
type: 'bytes', | ||
}, | ||
], | ||
name: 'createRetryableTicket', | ||
outputs: [ | ||
{ | ||
internalType: 'uint256', | ||
name: '', | ||
type: 'uint256', | ||
}, | ||
], | ||
stateMutability: 'payable', | ||
type: 'function', | ||
}, | ||
] | ||
|
||
/** | ||
* Set up: instantiate L1 / L2 wallets connected to providers | ||
*/ | ||
|
||
const walletPrivateKey = process.env.PRIVATE_KEY | ||
const l1Provider = new ethers.JsonRpcProvider(L1_RPC) | ||
const l2Provider = new ethers.JsonRpcProvider(L2_RPC) | ||
// const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider) | ||
const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider) | ||
|
||
module.exports = async () => { | ||
console.log( | ||
'Proposal For Executing L1 to L2 Messaging Using Arbitrum Delayed Inbox (Retryable Tickets)' | ||
) | ||
|
||
const l2Network = await getL2Network(l2Provider) | ||
const ethBridger = new EthBridger(l2Network) | ||
const inboxAddress = ethBridger.l2Network.ethBridge.inbox | ||
|
||
const L2TokenContract = new ethers.Contract( | ||
ARB_TOKEN_ADRESS_ON_L2, | ||
ERC20_ABI, | ||
l2Wallet | ||
).connect(l2Wallet) | ||
|
||
const balanceOf = await L2TokenContract.balanceOf(TIMELOCK_L2_ALIAS) | ||
const tokenAmount = ethers.parseEther('1') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please let's use the real anount. It does not make sense to send 1 ARB if this has been tested correctly (as I am sure you have done by now!) Also, please use |
||
|
||
// Create an instance of the Interface from the ABIs | ||
const erc20ContractInterface = new ethers.Interface(ERC20_ABI) | ||
const inboxContractInterface = new ethers.Interface(INBOX_ABI) | ||
|
||
// Encode the ERC20 Token transfer calldata | ||
const transferCalldata = erc20ContractInterface.encodeFunctionData( | ||
'transfer', | ||
[GRANTS_CONTRACT_ADDRESS, tokenAmount] | ||
) | ||
/** | ||
* Now we can query the required gas params using the estimateAll method in Arbitrum SDK | ||
*/ | ||
const l1ToL2MessageGasEstimate = new L1ToL2MessageGasEstimator(l2Provider) | ||
|
||
/** | ||
* The estimateAll method gives us the following values for sending an L1->L2 message | ||
* (1) maxSubmissionCost: The maximum cost to be paid for submitting the transaction | ||
* (2) gasLimit: The L2 gas limit | ||
* (3) deposit: The total amount to deposit on L1 to cover L2 gas and L2 call value | ||
*/ | ||
const L1ToL2MessageGasParams = await l1ToL2MessageGasEstimate.estimateAll( | ||
{ | ||
from: L1_TIMELOCK_CONTRACT, | ||
to: ARB_TOKEN_ADRESS_ON_L2, | ||
l2CallValue: 0, | ||
excessFeeRefundAddress: L1_TIMELOCK_CONTRACT, | ||
callValueRefundAddress: L1_TIMELOCK_CONTRACT, | ||
data: transferCalldata, | ||
}, | ||
await getBaseFee(l1Provider), | ||
l1Provider | ||
) | ||
const gasPriceBid = await l2Provider.getGasPrice() | ||
const ETHDeposit = L1ToL2MessageGasParams.deposit.toNumber() * 10 // I Multiply by 10 to add extra in case gas changes due to proposal delay | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain what this ETHDeposit is? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ETHDeposit is the amount ETH value that must be sent to the Delayed Inbox Contract for a successful retryable ticket creation. It is estimated by calling the Note that, the function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok that makes sense. Please add this nside the proposal. Because this comment won't be easy to find for people who are reviewing the proposal! |
||
const params = [ | ||
ARB_TOKEN_ADRESS_ON_L2, // to | ||
0, // l2CallValue | ||
L1ToL2MessageGasParams.maxSubmissionCost, // maxSubmissionCost | ||
L1_TIMELOCK_CONTRACT, // excessFeeRefundAddress | ||
L1_TIMELOCK_CONTRACT, // callValueRefundAddress | ||
L1ToL2MessageGasParams.gasLimit, // gasLimit | ||
gasPriceBid, // maxFeePerGas | ||
transferCalldata, // data | ||
] | ||
|
||
const inboxCalldata = inboxContractInterface.encodeFunctionData( | ||
'createRetryableTicket', | ||
params | ||
) | ||
|
||
const proposalName = ` | ||
# Test Transaction before 7k ARB Transfer To Fund Unlock Protocol’s Ecosystem via Grants Stack | ||
|
||
### Goal of the proposal | ||
This proposal requests to use 1 ARB from the tokens given to Unlock Protocol DAO by ArbitrumDAO to run a test transaction to de-risk the transfer of 7k ARB tokens to fund the retroQF round on Grants Stack. | ||
|
||
#### Current situation of DAO's ARB Tokens | ||
- total: ${ethers.formatEther(balanceOf).toString()} ARB. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here. do not use |
||
- DAO ALIAS Address (On Arbitrum): [${TIMELOCK_L2_ALIAS}](https://arbiscan.io/address/${TIMELOCK_L2_ALIAS}) | ||
|
||
For Reference | ||
[Snapshot temperature check for 7k ARBs](https://snapshot.org/#/unlock-protocol.eth/proposal/0xaa142e599d981f0b58c3ac1a51af9f9a52fb5307f27d791ecc18c4da69eeacc3) | ||
|
||
#### About the proposal | ||
The proposal contains a single call to the Arbitrum Delayed Inbox Contract's \`createRetryableTicket\` function on mainnet to create a \`Retryable Ticket\` that will attempt to execute an L2 request to the ARB token contract to transfer ${ethers | ||
.formatEther(tokenAmount) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
.toString()} of token from the Timelock L2 Alias address \`${TIMELOCK_L2_ALIAS}\` to the [grants contract](https://arbiscan.io/address/0x00d5e0d31d37cc13c645d86410ab4cb7cb428cca) - \`transfer(${GRANTS_CONTRACT_ADDRESS},${ethers | ||
.formatEther(tokenAmount) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
.toString()})\`. | ||
|
||
Once approved and executed, the request will be sent to the Delayed Inbox contract and a ticket is created. | ||
|
||
Note that, this function forces the sender to provide a reasonable amount of funds (at least enough to submitting, and attempting to executing the ticket), but that doesn't guarantee a successful auto-redemption. [Checkout arbitrum docs for more info.](https://docs.arbitrum.io/arbos/l1-to-l2-messaging). | ||
|
||
Thank you! | ||
` | ||
// Proposal ARGS i.e Call Governor.propose() directly with these values | ||
const targets = [inboxAddress] | ||
const values = [ETHDeposit] | ||
const calldatas = [inboxCalldata] | ||
const description = proposalName | ||
|
||
const calls = [ | ||
{ | ||
contractNameOrAbi: INBOX_ABI, | ||
contractAddress: inboxAddress, | ||
functionName: 'createRetryableTicket', | ||
functionArgs: params, | ||
value: ETHDeposit, | ||
}, | ||
] | ||
|
||
return { | ||
proposalName, | ||
calls, | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const { mainnet, arbitrum } = require('@unlock-protocol/networks') | ||
|
||
const L1_RPC = mainnet.provider // mainnet RPC | ||
const L2_RPC = arbitrum.provider // Arbitrum RPC | ||
const GRANTS_CONTRACT_ADDRESS = '0x00D5E0d31d37cc13C645D86410aB4cB7Cb428ccA' // Grants contract on Arbitrum | ||
const TIMELOCK_L2_ALIAS = '0x28ffDfB0A6e6E06E95B3A1f928Dc4024240bD87c' // Timelock Alias Address on L2 | ||
const L1_TIMELOCK_CONTRACT = '0x17EEDFb0a6E6e06E95B3A1F928dc4024240BC76B' // Timelock Address mainnet | ||
const ARB_TOKEN_ADRESS_ON_L2 = arbitrum.tokens.filter( | ||
(token) => token.symbol === 'ARB' | ||
)[0].address // ARB TOKEN ADDRESS ON ARBITRUM ONE | ||
clemsos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
module.exports = { | ||
L1_RPC, | ||
L2_RPC, | ||
ARB_TOKEN_ADRESS_ON_L2, | ||
GRANTS_CONTRACT_ADDRESS, | ||
TIMELOCK_L2_ALIAS, | ||
L1_TIMELOCK_CONTRACT, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't add that, it was already in the .env.copy file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it in the diff of this pull-request then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its a deleted newline it seems
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah that change should not be in this PR.