Skip to content

Commit

Permalink
fix(governance) update arbitrum l1 to l2 messaging proposal to arbitr…
Browse files Browse the repository at this point in the history
…um sdk v4
  • Loading branch information
blahkheart committed Dec 21, 2024
1 parent d7615e9 commit f936bec
Show file tree
Hide file tree
Showing 2 changed files with 393 additions and 0 deletions.
252 changes: 252 additions & 0 deletions governance/proposals/udt/018-tech-fusion-2024-event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
const ethers = require('ethers')
const { ParentToChildMessageGasEstimator } = require('@arbitrum/sdk')
const { EthBridger, getL2Network } = require('@arbitrum/sdk')
const { getBaseFee } = require('@arbitrum/sdk/dist/lib/utils/lib')
const { mainnet, arbitrum } = require('@unlock-protocol/networks')

const GRANTS_CONTRACT_ADDRESS = '0xD2BC5cb641aE6f7A880c3dD5Aee0450b5210BE23' // Receiving Address on Arbitrum
const TIMELOCK_L2_ALIAS = '0x28ffDfB0A6e6E06E95B3A1f928Dc4024240bD87c' // Timelock Alias Address on L2
const L1_TIMELOCK_CONTRACT = '0x17EEDFb0a6E6e06E95B3A1F928dc4024240BC76B' // Timelock Address mainnet

// ARB TOKEN ADDRESS ON ARBITRUM ONE
const { address: ARB_TOKEN_ADRESS_ON_L2 } = arbitrum.tokens.find(
({ symbol }) => symbol === 'ARB'
)
const ERC20_ABI = require('@unlock-protocol/hardhat-helpers/dist/ABIs/erc20.json')
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 l1Provider = new ethers.JsonRpcProvider(mainnet.provider)
const l2Provider = new ethers.JsonRpcProvider(arbitrum.provider)

module.exports = async ({
tokenAddressL2 = ARB_TOKEN_ADRESS_ON_L2,
fromL1 = L1_TIMELOCK_CONTRACT,
toL2 = GRANTS_CONTRACT_ADDRESS,
fromL2 = TIMELOCK_L2_ALIAS,
}) => {
console.log('Proposal For TechFusion 2024 Event')

const l2Network = await getL2Network(l2Provider)
const ethBridger = new EthBridger(l2Network)
const inboxAddress = ethBridger.l2Network.ethBridge.inbox

// token on L2
const L2TokenContract = new ethers.Contract(
tokenAddressL2,
ERC20_ABI,
l2Provider
)
const decimals = await L2TokenContract.decimals()

// check balance of sender on L2
const balanceOf = await L2TokenContract.balanceOf(fromL2)
const tokenToReceive = '373'
const tokenAmount = ethers.parseUnits(tokenToReceive, decimals)

// 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',
[toL2, tokenAmount]
)

/**
* Now we can query the required gas params using the estimateAll method in Arbitrum SDK
*/
const l1ToL2MessageGasEstimate = new ParentToChildMessageGasEstimator(
l2Provider
)

const estimateAllParams = {
from: fromL1,
to: tokenAddressL2,
l2CallValue: 0,
excessFeeRefundAddress: fromL1,
callValueRefundAddress: fromL1,
data: transferCalldata,
}

/**
* 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(
estimateAllParams,
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

const params = [
estimateAllParams.to,
estimateAllParams.l2CallValue,
L1ToL2MessageGasParams.maxSubmissionCost.toString() * 10, // maxSubmissionCost: I Multiply by 10 to add extra in case gas changes due to proposal delay
estimateAllParams.excessFeeRefundAddress,
estimateAllParams.callValueRefundAddress,
L1ToL2MessageGasParams.gasLimit.toString(), // gasLimit
gasPriceBid.toString(), // maxFeePerGas
estimateAllParams.data,
]

const inboxCalldata = inboxContractInterface.encodeFunctionData(
'createRetryableTicket',
params
)

const proposalName = `
# Transfer 373 ARB To Fund TechFusion 2024 Event
### Background
We are very excited to organize this event with a new emerging community called ComunDAO3600, as we aim to become a DAO dedicated to supporting Bolivian projects. Our event, TechFusion, seeks to bring together hundreds of people interested in exploring synergies between AI and blockchain, fostering a continuous learning environment and business opportunities.
The goal is to gather students, experts, and entrepreneurs to explore the intersections between Artificial Intelligence (AI), Blockchain, and Cryptocurrencies. We aim to encourage hands-on learning, discussions about emerging innovations, and networking among participants.
The target audience for TechFusion includes:
Technology Professionals: Developers, software engineers, and AI and blockchain experts looking to stay updated on the latest trends.
Entrepreneurs and Startups: Founders and teams interested in applying blockchain or AI to enhance their products or services.
Investors and Financial Analysts: Those looking to gain a better understanding of investment opportunities in cryptocurrencies and emerging technologies.
Students and Academics: Young professionals and students interested in developing skills in AI, blockchain, and cryptocurrencies.
Technology Enthusiasts: Curious individuals who want to learn and explore the future of these disruptive technologies.
The Ticket: https://app.unlock-protocol.com/event/tech-fusion-2024
#### Benefits
By involving the DAO in my activities, key opportunities will be created for:
Visibility and positioning: The DAO will be directly associated with events that highlight technological innovation, increasing its recognition within the crypto and blockchain ecosystem.
Talent attraction: Through conferences and workshops, we will attract developers, researchers, and entrepreneurs who can join the DAO as active members or collaborators.
Community expansion: These events will attract new users and participants who align with the DAO's values and objectives, creating a stronger user base.
Collaboration opportunities: The events will facilitate the creation of strategic partnerships with related projects and organizations.
#### Risks
As with any growth initiative, there are certain risks, although I believe they are manageable:
Reputation: While I always strive to maintain high standards of quality in the events, there is a risk that a speaker or collaborator might not meet expectations, which could reflect negatively on the DAO. However, to mitigate this, I carefully select speakers and collaborators.
Low short-term return on investment: Tangible benefits, such as new collaborations or adoptions, may not be immediate, as building strong communities takes time.
#### Timeline and Implementation
1 - Get Snapshot approval from the DAO for the overall idea.
2 - Generate event Ticket
3 - Pre-TechFusion November 2024 (online): Event focused on the intersection of AI and Blockchain. (Dates: November 13 - 20).
4 - TechFusion November 2024 (in-person): A more interactive event focusing on networking and knowledge sharing. (November 22, 2024).
Total timeline is 2 weeks
#### Resources
Quoted in ARB token eq 250 usdc
Printed materials:
Protocol merchandise
75 ARB
Venue rental and technical equipment:
149.25 ARB
Marketing, design, and promotion:
149.25 ARB
Total: 373.5 ARB
price ARB token $0.67
Wallet address as a recipient: *0xD2BC5cb641aE6f7A880c3dD5Aee0450b5210BE23*
Due to time and the urgent need to cover organizational costs, Stella Achenbach has provided the requested funds in USDC, so she will be receiving the ARB tokens.
Here is the [transaction hash](https://basescan.org/tx/0x9e235555a513c3bfa62f622e24a7ad96a8701b0d8040c5888b74e028337d1c0f)
The exchange value in ARB which is $0.67, should be equivalent to 250 USDC
approximately 373.13 ARB
For Reference
[Snapshot temperature check for TechFusion 2024 Event](https://snapshot.org/#/unlock-dao.eth/proposal/0x55b493884276233c411d2bc58e64efc7f2303b6c5ca9efe8f162a584af3e0ac2)
#### Current situation of DAO's ARB Tokens
- total: ${ethers.formatUnits(balanceOf, decimals).toString()} ARB.
- DAO ALIAS Address (On Arbitrum): [${fromL2}](https://arbiscan.io/address/${fromL2})
#### 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
.formatUnits(tokenAmount, decimals)
.toString()} of token from the Timelock L2 Alias address \`${fromL2}\` to the [grants contract](https://arbiscan.io/address/0x00d5e0d31d37cc13c645d86410ab4cb7cb428cca) - \`transfer(${toL2},${ethers
.formatUnits(tokenAmount, decimals)
.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 = [
{
contractAddress: inboxAddress,
calldata: inboxCalldata,
value: ETHDeposit.toString(),
},
]

return {
proposalName,
calls,
}
}
141 changes: 141 additions & 0 deletions governance/proposals/udt/020-arbitrum-l1-l2-messaging-sdkv4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
const ethers = require('ethers')
const {
ParentToChildMessageGasEstimator,
ParentTransactionReceipt,
} = require('@arbitrum/sdk')
const { EthBridger, getArbitrumNetwork } = require('@arbitrum/sdk')
const { getBaseFee } = require('@arbitrum/sdk/dist/lib/utils/lib')
const { mainnet, arbitrum } = require('@unlock-protocol/networks')

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 on mainnet

// ARB Token Address on Arbitrum One
const { address: ARB_TOKEN_ADDRESS_ON_L2 } = arbitrum.tokens.find(
({ symbol }) => symbol === 'ARB'
)
const ERC20_ABI = require('@unlock-protocol/hardhat-helpers/dist/ABIs/erc20.json')
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',
},
]

const l1Provider = new ethers.JsonRpcProvider(mainnet.provider)
const l2Provider = new ethers.JsonRpcProvider(arbitrum.provider)

module.exports = async ({
tokenAddressL2 = ARB_TOKEN_ADDRESS_ON_L2,
fromL1 = L1_TIMELOCK_CONTRACT,
toL2 = GRANTS_CONTRACT_ADDRESS,
fromL2 = TIMELOCK_L2_ALIAS,
}) => {
console.log(
'Proposal For Executing L1 to L2 Messaging Using Arbitrum Delayed Inbox (Retryable Tickets)'
)

const l2Network = await getArbitrumNetwork(l2Provider)
const ethBridger = new EthBridger(l2Network)
const inboxAddress = ethBridger.childNetwork.ethBridge.inbox

const L2TokenContract = new ethers.Contract(
tokenAddressL2,
ERC20_ABI,
l2Provider
)
const decimals = await L2TokenContract.decimals()
const balanceOf = await L2TokenContract.balanceOf(fromL2)
const tokenAmount = ethers.utils.parseUnits('8200', decimals)

const erc20ContractInterface = new ethers.utils.Interface(ERC20_ABI)
const inboxContractInterface = new ethers.utils.Interface(INBOX_ABI)

const transferCalldata = erc20ContractInterface.encodeFunctionData(
'transfer',
[toL2, tokenAmount]
)

const gasEstimator = new ParentToChildMessageGasEstimator(l2Provider)
const gasEstimateParams = {
from: fromL1,
to: tokenAddressL2,
l2CallValue: 0,
excessFeeRefundAddress: fromL1,
callValueRefundAddress: fromL1,
data: transferCalldata,
}

const gasEstimates = await gasEstimator.estimateAll(
gasEstimateParams,
await getBaseFee(l1Provider),
l1Provider
)

const gasPriceBid = await l2Provider.getGasPrice()
const ETHDeposit = gasEstimates.deposit.toNumber() * 10 // Multiply by 10 to add buffer for fee changes before proposal is executed

const retryableTicketParams = [
gasEstimateParams.to,
gasEstimateParams.l2CallValue,
(gasEstimates.maxSubmissionCost.toNumber() * 10).toString(), // Multiply by 10 to add buffer for fee changes before proposal is executed
gasEstimateParams.excessFeeRefundAddress,
gasEstimateParams.callValueRefundAddress,
gasEstimates.gasLimit.toString(),
gasPriceBid.toString(),
gasEstimateParams.data,
]

const inboxCalldata = inboxContractInterface.encodeFunctionData(
'createRetryableTicket',
retryableTicketParams
)

const proposalName = `
# Transfer 8200 ARB to Unlock Protocol DAO's Ecosystem Grants Stack
This proposal includes creating a retryable ticket to transfer ${ethers.utils.formatUnits(
tokenAmount,
decimals
)} ARB from the L2 Timelock Alias to the Grants Contract.
`

const targets = [inboxAddress]
const values = [ETHDeposit.toString()]
const calldatas = [inboxCalldata]
const description = proposalName

const calls = [
{
contractAddress: inboxAddress,
calldata: inboxCalldata,
value: ETHDeposit.toString(),
},
]

return {
proposalName,
calls,
}
}

0 comments on commit f936bec

Please sign in to comment.