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
Arbitrum L1 to L2 messaging proposal #13516
Conversation
Thank you for your pull request and welcome to Unlock! We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @blahkheart on file. |
Thank you for your pull request and welcome to Unlock! We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @blahkheart on 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.
Thanks for the PR. Good start. A few comments added !
governance/.env
Outdated
# Duplicate this file as .env | ||
|
||
# Your Private key | ||
DEVNET_PRIVKEY="0x14e1a3103ce06d0348acf19df3df1965ee55f9cdb16708c0bb8cd3d843ab8805" |
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.
You should never check a private key into a git repo...
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 totally agree with that, I didn't know .env wasn't included in the .gitignore file, especially because I saw a .env.copy file already present in the /governance/
folder, which I copied and renamed to .env. For what it's worth it's a fresh wallet I created specifically for the tests.
Thank you for your pull request and welcome to Unlock! We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @blahkheart on file. |
const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider) | ||
|
||
module.exports = async () => { | ||
await arbLog('Cross-chain Proposer') |
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.
what is arbLog
used for ?
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.
It came with the arbitrum sdk, its more or less a branding/description of the script.
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.
Can we just use a regular console.log
please?
gasPriceBid, | ||
transfer_calldata, | ||
], | ||
value: 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 comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure you need to pass the value again here? It is already declared above
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.
Yes, from my understanding of the existing format, and correct me if I'm wrong but this value property is responsible for passing the eth amount to a payable function, and in this case that's the eth deposit to be sent to arbitrum's inbox contract.
If you were referring to this line const values = [L1ToL2MessageGasParams.deposit.toNumber() * 10]
that was declared to show how the proposal can be created from an interface like etherscan or remix, but if its not necessary or confusing I can remove it as well.
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.
Can you please use #13509 to run tests for your proposal, then import the values in Tenderly to check that it passes?
governance/.env.copy
Outdated
export GNOSISSCAN_API_KEY= | ||
|
||
# This is a sample .env file for use in local development. |
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.
Please remeove these changes...
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.
Okay got it
governance/package.json
Outdated
"@arbitrum/nitro-contracts": "v1.0.2", | ||
"@arbitrum/sdk": "^v3.1.9", |
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.
Please use fixed version numbers (no v
or ^
)
governance/package.json
Outdated
@@ -21,8 +23,9 @@ | |||
"@unlock-protocol/hardhat-helpers": "workspace:^", | |||
"@unlock-protocol/hardhat-plugin": "workspace:^", | |||
"@unlock-protocol/networks": "workspace:./packages/networks", | |||
"arb-shared-dependencies": "^1.0.0", |
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.
Same here!
/** | ||
* Set up: instantiate L1 / L2 wallets connected to providers | ||
*/ | ||
const walletPrivateKey = 'Your_Private_key' |
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.
Please use env variables here
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.
@clemsos earlier informed me .env is not supported, how else would I use env variables?
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.
Process.env.PRIVATE_KEY for example
* Set up: instantiate L1 / L2 wallets connected to providers | ||
*/ | ||
const walletPrivateKey = 'Your_Private_key' | ||
const L1RPC = 'https://mainnet.infura.io/v3/<your_infura_api_key>' |
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.
Please use https://rpc.unlock-protocol.com/1
so that this does not break in the future.
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.
Got it
const ARBTokenAddressOnL2 = '0x912CE59144191C1204E64559FE8253a0e49E6548' // ARB TOKEN ADDRESS ON ARBITRUM ONE | ||
const grantsContractAddress = '0x00D5E0d31d37cc13C645D86410aB4cB7Cb428ccA' | ||
const timelockL2Alias = '0x28ffDfB0A6e6E06E95B3A1f928Dc4024240bD87c' // Timelock Alias Address on L2 | ||
const L1TimelockContract = '0x17EEDFb0a6E6e06E95B3A1F928dc4024240BC76B' // Timelock Address mainnet |
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.
We should probably move that to a config file in this folder.
from: L1TimelockContract, | ||
to: ARBTokenAddressOnL2, | ||
l2CallValue: 0, | ||
excessFeeRefundAddress: l2Wallet.address, |
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.
Can you explain why l2Wallet
would recive the excess here?
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.
That's following the format from arbitrum's example, but I didn't need to change it because the L1 and L2 wallets are the same. Ideally you want to specify the wallet address you want the excess eth refund to be sent to if it's different.
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.
Where is the excess ETH coming from? An funds should go back to the DAO and not to some external address.
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.
Got it, it has now been changed to the DAO's address. The reason for having it that way in the first place is due to the nature of the transaction. The createRetryable
function forces the caller to pay the value sent to the Delayed Inbox contract, Therefore ETH is paid by the person calling the execute()
function and not the Timelock. So it was set up so whoever creates the proposal and provides the private key gets any excess ETH refund sent to that address. But that was flawed by the assumption that the proposer will always be the executor. Ideally, the DAO will fund/reimburse whoever executes the proposal so excess should return to the DAO, thank you for pointing that out.
to: ARBTokenAddressOnL2, | ||
l2CallValue: 0, | ||
excessFeeRefundAddress: l2Wallet.address, | ||
callValueRefundAddress: l2Wallet.address, |
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.
Same here?
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.
Same reason as before
const inbox_calldata = iface_inbox.encodeFunctionData( | ||
'createRetryableTicket', | ||
[ | ||
ARBTokenAddressOnL2, |
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.
Please add comments in front of each of these params to provide their names
] | ||
) | ||
|
||
const proposalName = `# Test Transaction before 7k ARB Transfer To Fund Unlock Protocol’s Ecosystem via Grants Stack 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.` |
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.
Please format this correctly.
This would be
Test Transaction before 7k ARB Transfer To Fund Unlock Protocol’s Ecosystem via Grants Stack 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.
Make sure there is a title, one (or more) distinct paragraphs, as well as links to provide clarity (links to the snapshot, to the UI on which people are voting... etc)
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.
Got it
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…rk-parse to v11 (unlock-protocol#13531) * Updated unified & related dependencies * Updated remark
…15, remark-parse to v11" (unlock-protocol#13532) Revert "fix(deps): update dependency unified to v11, remark-html to v15, rema…" This reverts commit 80969a6.
unlock-protocol#13528) * changed the UI for refunds per Gnosis * refactored receipt number
* Update Referrals.tsx microcopy fix * Update CancellationForm.tsx microcopy update * Update UpdateReferralFee.tsx microcopy update
…tocol#13534) * add publicLock changelog * add Unlock changelog
…-protocol#13509) * allow test execution of proposal from tx id * parse and pass correctly tx args * add unlock addresses in whales * allow proposal id only for votes * pass odwn tx receipt * herlpes for gov contract * log events after proposal execution * Update governance/scripts/gov/index.js --------- Co-authored-by: Julien Genestoux <julien.genestoux@gmail.com>
…3541) * Updated nuintun/qrcode * Update qrcode.ts
*/ | ||
const walletPrivateKey = process.env.PRIVATE_KEY | ||
const L1RPC = 'https://rpc.unlock-protocol.com/1' // mainnet RPC | ||
const L2RPC = 'https://rpc.unlock-protocol.com/42161' // Arbitrum RPC |
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.
same
const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider) | ||
|
||
module.exports = async () => { | ||
console.log('Cross-chain Proposer') |
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.
This is misleading. Can you use a better description please?
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'm not sure what you mean here, what are you referring to please?
const tokenAmount = ethers.parseEther('1') | ||
|
||
// Create an instance of the Interface from the ABIs | ||
const iface_erc20 = new ethers.Interface(ERC20_ABI) |
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.
Please respect the styleguide if you can:
const iface_erc20 = new ethers.Interface(ERC20_ABI) | |
const ifaceErc20 = new ethers.Interface(ERC20_ABI) |
const iface_inbox = new ethers.Interface(INBOX_ABI) | ||
|
||
// Encode the ERC20 Token transfer calldata | ||
const transfer_calldata = iface_erc20.encodeFunctionData('transfer', [ |
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.
const transfer_calldata = iface_erc20.encodeFunctionData('transfer', [ | |
const transferCalldata = iface_erc20.encodeFunctionData('transfer', [ |
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 comment
The 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 comment
The 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 l1ToL2MessageGasEstimate.estimateAll({params})
function provided by the Arbitrum sdk. When the createRetryableTicket
function is called, it forces the caller to pay this amount else reverts, this is why the excessFeeRefundAddress
you asked about earlier is needed, to send any excess back. Here I multiply the actual value by 10 as a buffer because in the time it takes to execute a proposal that value may change.
Note that, the function createRetryableTicket
forces the sender to provide a reasonable amount of funds (at least enough for submitting, and attempting to execute the ticket), but that doesn't guarantee a successful auto-redemption. Checkout arbitrum docs for more info..
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.
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!
* Used providers, and addresses from networks package * Renamed config.js to constants.js * Used suggested style guide for variable names * More detailed description
governance/.gitignore
Outdated
@@ -2,6 +2,7 @@ | |||
cache | |||
contracts | |||
artifacts | |||
.env |
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.
same here
).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 comment
The 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 ethers.parseUnits
as this is an ERC20, not Ethers.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
same here. do not use formatEther
when it is an ERC20.
|
||
#### 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 comment
The reason will be displayed to describe this comment to others. Learn more.
same
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) | ||
.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 comment
The reason will be displayed to describe this comment to others. Learn more.
same
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.
since the DAO does not hold any ETH and yet it needs to send ETH to the mailbox contract (if I understand your proposal correctly), how will this work?
@blahkheart I refactored the proposal script a bit to make it clearer. Almost there ! |
"eslint": "8.54.0", | ||
"ethers": "6.10.0", | ||
"ethers5": "npm:ethers@5", |
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.
We have to add ethers5
here, as it is required by the arbitrum sdk
Great! Is any further action required on my part? |
I think I mentioned this earlier, one way I feel this could work is whoever calls the |
* Use actual amount of ARB tokens required
* Use correct proposal amount * Revert .gitignore, and .env.copy changes
# Transfer 8200 ARB To Fund Unlock Protocol’s Ecosystem via Grants Stack | ||
|
||
### Goal of the proposal | ||
This proposal requests to use 8200 ARB from the tokens given to Unlock Protocol DAO by ArbitrumDAO to fund the retroQF round on Grants Stack for projects building on Unlock Protocol. |
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.
This is UP from what the snapshot proposal initially asked...
Asking for 7k in ARB to help Fund Unlock Protocol’s Ecosystem via Grants Stack
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.
There is an explanation for why this is up from the initial 7k as well as a reference to the snapshot proposal included in the description
Please @blahkheart merge the conflicts on |
Description
This PR adds an example of how to create a DAO proposal for execution of Arbitrum's L1-to-L2 message passing system (aka "retryable tickets")
Issues
Fixes #13515
Refs #13515
Checklist:
Release Note Draft Snippet