Skip to content
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

Merged
merged 39 commits into from Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
f0cbaf2
added 010-arbitrum-l1-l2-messaging.js to /goverance/proposals
blahkheart Mar 22, 2024
85376b1
removed unnecessary comments
blahkheart Mar 22, 2024
247edf0
moved ERC20_ABI and INBOX_ABI inline and removed /helper/abi folder
blahkheart Mar 25, 2024
2f0608f
signed Contributor License Agreement
blahkheart Mar 25, 2024
b9c3467
removed console logs, and .env file
blahkheart Mar 26, 2024
20939ee
Merge branch 'master' into l1-l2-msg-proposal
julien51 Mar 26, 2024
506fdc6
used fixed version numbers for arbitrum packages, added config.js file
blahkheart Mar 28, 2024
09aada2
changed excessFeeRefundAddress to the dao's address
blahkheart Mar 28, 2024
6cd79c2
added comments in front of params to provide their names
blahkheart Mar 28, 2024
cd41637
formated proposal description correctly
blahkheart Mar 28, 2024
80b6fe6
feat(locksmith): better fatal error handling with a logging statement
julien51 Mar 26, 2024
14273ca
feat(locksmith): adding cache for decoy users
julien51 Mar 26, 2024
6709e11
fix(deps): update dependency express [security] (#13524)
renovate[bot] Mar 27, 2024
a6942e4
fix(deps): update dependency unified to v11, remark-html to v15, rema…
SVell Mar 27, 2024
b54ffa4
Revert "fix(deps): update dependency unified to v11, remark-html to v…
julien51 Mar 27, 2024
347d6bf
feat(unlock-app): changed the UI for refunds per Dappcon Team request…
julien51 Mar 27, 2024
98935ee
fix(unlock-protocol-com): removed distDir from next config
julien51 Mar 27, 2024
e98703b
Ccarfi microcopy fixes on referrals and refunds (#13536)
ccarfi Mar 28, 2024
6c9f33a
feat(docs): add changelog for Unlock 13 and PublicLock 14 (#13534)
clemsos Mar 28, 2024
3e817b7
add contributors to .clabot (#13537)
TylerSehr Mar 28, 2024
39b4e79
feat(governance): allow test execution of proposal from tx id (#13509)
clemsos Mar 29, 2024
24d81c3
fix(deps): update dependency @nuintun/qrcode to v4 (#13541)
SVell Mar 29, 2024
eabfe4d
fix(deps): update dependency unified to v11, remark-html to v16, rema…
SVell Mar 29, 2024
cbdfb95
fix(locksmith) fixing export (#13542)
julien51 Mar 29, 2024
fa63c3d
feat(networks): add support for Base sepolia (#13529)
clemsos Mar 29, 2024
0f7ec36
cleanup: removed goerli (#13540)
julien51 Mar 30, 2024
ce0e970
Updated PR to address comments
blahkheart Mar 30, 2024
c1fd7d7
Merge branch 'master' into l1-l2-msg-proposal
clemsos Apr 1, 2024
7bced2f
Updated PR
blahkheart Apr 1, 2024
0a993b8
Resolved yarn.lock merge conflict
blahkheart Apr 2, 2024
c9a28c1
Updated PR:
blahkheart Apr 3, 2024
4d42172
Update governance/proposals/constants.js
clemsos Apr 3, 2024
c33c977
Update governance/proposals/010-arbitrum-l1-l2-messaging.js
clemsos Apr 3, 2024
79327c5
use ethers5
clemsos Apr 3, 2024
ace2d13
refactor proposal
clemsos Apr 3, 2024
794914d
Merge branch 'master' of github.com:unlock-protocol/unlock into l1-l2…
clemsos Apr 3, 2024
a82a7c0
* Revert change to .gitignore, and .env.copy
blahkheart Apr 3, 2024
debbbdf
* Update proposal description
blahkheart Apr 3, 2024
6687533
Resolved yarn.lock conflict
blahkheart Apr 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion governance/.env.copy
Expand Up @@ -9,4 +9,4 @@ export BSCSCAN_API_KEY=
export SNOWTRACE_API_KEY=
export ARBISCAN_API_KEY=
export CELO_API_KEY=
export GNOSISSCAN_API_KEY=
export GNOSISSCAN_API_KEY=
Copy link
Member

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?

Copy link
Contributor Author

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

Copy link
Member

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?

Copy link
Member

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

Copy link
Member

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.

1 change: 1 addition & 0 deletions governance/.gitignore
Expand Up @@ -2,6 +2,7 @@
cache
contracts
artifacts
.env
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here


# zksync
zk-artifacts
Expand Down
3 changes: 3 additions & 0 deletions governance/package.json
Expand Up @@ -3,6 +3,8 @@
"description": "Scripts for the management of the Unlock Protocol",
"private": true,
"dependencies": {
"@arbitrum/nitro-contracts": "1.0.2",
"@arbitrum/sdk": "3.1.9",
"@matterlabs/hardhat-zksync-deploy": "1.1.2",
"@matterlabs/hardhat-zksync-solc": "1.1.0",
"@matterlabs/hardhat-zksync-upgradable": "1.2.4",
Expand All @@ -21,6 +23,7 @@
"@unlock-protocol/hardhat-helpers": "workspace:^",
"@unlock-protocol/hardhat-plugin": "workspace:^",
"@unlock-protocol/networks": "workspace:./packages/networks",
"arb-shared-dependencies": "1.0.0",
"eslint": "8.54.0",
"ethers": "6.10.0",
"fs-extra": "11.2.0",
Expand Down
242 changes: 242 additions & 0 deletions governance/proposals/010-arbitrum-l1-l2-messaging.js
@@ -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')
Copy link
Member

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.


// 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
Copy link
Member

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?

Copy link
Contributor Author

@blahkheart blahkheart Apr 3, 2024

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..

Copy link
Member

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!

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.
Copy link
Member

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.

- 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)
Copy link
Member

Choose a reason for hiding this comment

The 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)
Copy link
Member

Choose a reason for hiding this comment

The 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,
}
}
19 changes: 19 additions & 0 deletions governance/proposals/constants.js
@@ -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,
}