-
Notifications
You must be signed in to change notification settings - Fork 39
Plasma Gho Launch, Remote GSM Launch #879
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
base: main
Are you sure you want to change the base?
Conversation
Compiling 420 files with Solc 0.8.27
Solc 0.8.27 finished in 152.57s
Compiler run successful!
2025-11-05T06:17:19.908746Z ERROR cheatcodes: non-empty stderr input=["npx", "@bgd-labs/[email protected]", "diff-snapshots", "./reports/AaveV3Ethereum_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part1_before.json", "./reports/AaveV3Ethereum_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part1_after.json", "-o", "./diffs/AaveV3Ethereum_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part1_before_AaveV3Ethereum_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part1_after.md"] stderr="npm warn exec The following package was not found and will be installed: @bgd-labs/[email protected]\n"
|
...ewards/AaveV3Ethereum_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part1.sol
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| function _registerOracles() internal { | ||
| AaveV3Ethereum.COLLECTOR.withdrawFromV3( |
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.
@efecarranza there can be 2-3 wei imprecision when withdrawing, after withdraw better to get current link balance of the executor and fund the robot accordingly
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 can withdraw + 5 wei just to make sure i have the 80, 'cause i have to fund 2 bots with specific amounts.
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.
Starting from the v3.5 version, all transfers are transferring at least the passed amount. For example, if Alice is transferring 5 weis aTokens to Bob (through transfer or transferFrom), then Alice's aToken balance will be decreased not less 5 weis and Bob's aToken balance will be increased not less 5 weis.
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.
@efecarranza you can use the returned value from the function, and to fund the first robot use the value from immutable and for the second use returnedLinkBalance - LINK_AMOUNT_ORACLE_FREEZER_KEEPER
| address public constant NEW_GSM_USDC = 0x3A3868898305f04beC7FEa77BecFf04C13444112; | ||
|
|
||
| // https://etherscan.io/address/0xc39ac061686C99b1B8B09B401e8C2f486894AD3c | ||
| address public constant USDC_ORACLE_SWAP_FREEZER = 0xc39ac061686C99b1B8B09B401e8C2f486894AD3c; |
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.
The addresses provider immutable on the USDC and USDT swap freezer is of the plasma network and needs to be re-deployed.
Furthermore, can you add tests for the new contracts added to validate the immutables, ownerships, misc deployment config and end some e2e tests so we don't miss anything.
...ewards/AaveV3Ethereum_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part2.sol
Outdated
Show resolved
Hide resolved
...ewards/AaveV3Ethereum_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part2.sol
Outdated
Show resolved
Hide resolved
...rRewards/AaveV3Plasma_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part1.sol
Outdated
Show resolved
Hide resolved
...rRewards/AaveV3Plasma_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part2.sol
Outdated
Show resolved
Hide resolved
...rRewards/AaveV3Plasma_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part2.sol
Outdated
Show resolved
Hide resolved
...rRewards/AaveV3Plasma_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part2.sol
Outdated
Show resolved
Hide resolved
...ewards/AaveV3Ethereum_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part1.sol
Outdated
Show resolved
Hide resolved
...ewards/AaveV3Ethereum_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part1.sol
Outdated
Show resolved
Hide resolved
...ewards/AaveV3Ethereum_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part1.sol
Outdated
Show resolved
Hide resolved
| function mint(address to, uint256 amount) external; | ||
| } | ||
|
|
||
| interface IAaveGhoCcipBridge { |
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.
IAaveGhoCcipBridge can be imported from aave-helpers directly
| import {CCIPChainSelectors} from '../helpers/gho-launch/constants/CCIPChainSelectors.sol'; | ||
|
|
||
| /** | ||
| * @title Add GHO and deploy GSM on Plasma. Migrate to new GSM on Ethereum |
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.
| * @title Add GHO and deploy GSM on Plasma. Migrate to new GSM on Ethereum | |
| * @title Add GHO and deploy GSM on Plasma. |
can you check and update at other places too
| // compose action | ||
| IPayloadsControllerCore.ExecutionAction[] | ||
| memory actions = new IPayloadsControllerCore.ExecutionAction[](2); | ||
| actions[0] = GovV3Helpers.buildAction(payload0); | ||
| actions[1] = GovV3Helpers.buildAction(payload1); | ||
|
|
||
| // register action at payloadsController | ||
| GovV3Helpers.createPayload(actions); |
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.
| // compose action | |
| IPayloadsControllerCore.ExecutionAction[] | |
| memory actions = new IPayloadsControllerCore.ExecutionAction[](2); | |
| actions[0] = GovV3Helpers.buildAction(payload0); | |
| actions[1] = GovV3Helpers.buildAction(payload1); | |
| // register action at payloadsController | |
| GovV3Helpers.createPayload(actions); | |
| GovV3Helpers.createPayload(GovV3Helpers.buildAction(payload0)); | |
| GovV3Helpers.createPayload(GovV3Helpers.buildAction(payload1)); |
@efecarranza we need to create two separate payloads as executing both atomically it will revert
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 would need to update the CreateProposal script accordingly too
| function _registerOracles() internal { | ||
| // Manual via Gelato for Plasma | ||
| } |
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.
| function _registerOracles() internal { | |
| // Manual via Gelato for Plasma | |
| } |
lets remove this method as it's empty, @efecarranza for better visibility we can add the link to the gelato task if it has been created by the dao account
| proposal = new AaveV3Plasma_LaunchGHOOnPlasmaSetACIAsEmissionsManagerForRewards_20250930_Part2(); | ||
|
|
||
| // Deal GHO that is going to be bridged from Mainnet | ||
| // 1 GHO for seed amount already sent to Collector |
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.
| // 1 GHO for seed amount already sent to Collector | |
| // 10 GHO for seed amount already sent to Collector |
| // compose action | ||
| IPayloadsControllerCore.ExecutionAction[] | ||
| memory actions = new IPayloadsControllerCore.ExecutionAction[](2); | ||
| actions[0] = GovV3Helpers.buildAction(payload0); | ||
| actions[1] = GovV3Helpers.buildAction(payload1); | ||
|
|
||
| // register action at payloadsController | ||
| GovV3Helpers.createPayload(actions); |
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.
| // compose action | |
| IPayloadsControllerCore.ExecutionAction[] | |
| memory actions = new IPayloadsControllerCore.ExecutionAction[](2); | |
| actions[0] = GovV3Helpers.buildAction(payload0); | |
| actions[1] = GovV3Helpers.buildAction(payload1); | |
| // register action at payloadsController | |
| GovV3Helpers.createPayload(actions); | |
| GovV3Helpers.createPayload(GovV3Helpers.buildAction(payload0)); | |
| GovV3Helpers.createPayload(GovV3Helpers.buildAction(payload1)); |
|
|
||
| uint128 public constant DEFAULT_RATE_LIMITER_CAPACITY = 1_500_000e18; | ||
| uint128 public constant DEFAULT_RATE_LIMITER_RATE = 300e18; | ||
| uint256 public constant PLASMA_BRIDGE_AMOUNT = 50_000_000 ether; |
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.
Perhaps a bit error-prone to have amounts in both of ether and e18 units, and better to be consistent throughout
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.
good point, bad copy/paste. thank you
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import {AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol'; |
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.
rm, clean imports across files pls
| IERC20(AaveV3EthereumAssets.GHO_UNDERLYING).approve(CCIP_BRIDGE, PLASMA_BRIDGE_AMOUNT); | ||
|
|
||
| // Bridge already has LINK to bridge, no need to send for fee | ||
| IAaveGhoCcipBridge(CCIP_BRIDGE).send( |
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.
How are you making sure this payload is executed after the other that increases the ccip rate limit? It's because this send will fail? I wonde if better to check outbound rate limit instead.
I believe it's better to increase rate limit and send in the same payload, and have a second separate payload to restore the initial rate limit. Apart from that, alternative approach would be 1 single payload to increase rate limit and send, and have gho stewards restoring (fine if we wanna avoid stewards overhead)
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.
@miguelmtzinf unfortunately it has to be done in this order because once the limit is increased, you need to wait at least 1 second in order for it to refill. that's why in part 1 the rate is also increased.
governance executes payloads sequentially, but also, this send() will indeed fail and won't execute until part 1 and at least 1 second goes by.
| // 50M GHO to be bridged, add 10% leeway initially in case other bridges take place | ||
| uint256 public constant NEW_CAPACITY = 55_000_000 ether; |
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.
| // 50M GHO to be bridged, add 10% leeway initially in case other bridges take place | |
| uint256 public constant NEW_CAPACITY = 55_000_000 ether; | |
| // 50M GHO bridge amount + 10% leeway in case of other bridges | |
| uint256 public constant TEMP_BRIDGE_CAPACITY = 55_000_000 ether; |
to get it aligned with the other payload
| import {IGsmRegistry} from 'src/interfaces/IGsmRegistry.sol'; | ||
| import {IAaveCLRobotOperator} from 'src/interfaces/IAaveCLRobotOperator.sol'; | ||
|
|
||
| interface IGhoReserve { |
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.
move to src/interfaces
| // https://plasmascan.to/address/0xd06114F714beCD6f373e5cE94E07278eF46eBF37 | ||
| address public constant NEW_GSM_USDT = 0xd06114F714beCD6f373e5cE94E07278eF46eBF37; |
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 is aUSDT indeed
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's stataUSDT
| address public constant GHO_RESERVE = 0xBAdA742e7Ff54595F9049eeF1Cc5AaF4364988B9; | ||
| uint256 public constant BRIDGED_AMOUNT = 50_000_000 ether; | ||
|
|
||
| // Capacities |
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.
| // Capacities | |
| // GSM |
i d put gsm address, fee strat and usdt capacity below
everything preffixed with GSM_USDT or GSM_AUSDT
| bytes32 public immutable LIQUIDATOR_ROLE = IGsm(NEW_GSM_USDT).LIQUIDATOR_ROLE(); | ||
| bytes32 public immutable SWAP_FREEZER_ROLE = IGsm(NEW_GSM_USDT).SWAP_FREEZER_ROLE(); |
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.
cannot be constant? can be rmed also
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 cannot if you're calling it like that, removed liquidator role
| uint256 public constant BRIDGED_AMOUNT = 50_000_000 ether; | ||
|
|
||
| // Capacities | ||
| uint128 public constant USDT_CAPACITY = 50_000_000 ether; |
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.
| uint128 public constant USDT_CAPACITY = 50_000_000 ether; | |
| uint128 public constant RESERVE_LIMIT_GSM_USDT = 50_000_000 ether; |
| IGsm(NEW_GSM_USDT).grantRole(IGsm(NEW_GSM_USDT).CONFIGURATOR_ROLE(), GHO_GSM_STEWARD); | ||
| } | ||
|
|
||
| function _updateFeeStrategy() internal { |
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 internal method feels unnecessary
| borrowableInIsolation: EngineFlags.DISABLED, | ||
| withSiloedBorrowing: EngineFlags.DISABLED, | ||
| flashloanable: EngineFlags.ENABLED, | ||
| ltv: 75_00, |
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 confirm that is set to be collateral outside of any emode? This would be the only market where GHO has collateral status
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.
updated after discussing but this is likely to go out post 3.6 where it can be 0
|
|
||
| function _postExecute() internal override { | ||
| AaveV3Plasma.COLLECTOR.transfer(IERC20(GhoPlasma.GHO_TOKEN), address(this), GHO_SEED_AMOUNT); | ||
| IERC20(GhoPlasma.GHO_TOKEN).forceApprove(address(AaveV3Plasma.POOL), GHO_SEED_AMOUNT); |
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.
collector only has 1 GHO, not 10
|
|
||
| AaveV3Plasma.COLLECTOR.transfer(IERC20(GhoPlasma.GHO_TOKEN), GHO_RESERVE, BRIDGED_AMOUNT); | ||
|
|
||
| // Restore bridge limits after GHO bridging |
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.
how do we ensure that restoring the rate limit happens after the other payload?
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 payload won't execute because it won't have the GHO needed to perform actions so it will revert. once part 1 is executed and the bridge goes through then this part will be executed
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import {AaveV3Ethereum, AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol'; |
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.
AaveV3EthereumAssets import is unused, please remove
| import {IERC20} from 'openzeppelin-contracts/contracts/token/ERC20/IERC20.sol'; | ||
| import {SafeERC20} from 'openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol'; | ||
| import {CCIPChainSelectors} from '../helpers/gho-launch/constants/CCIPChainSelectors.sol'; | ||
| import {AaveV3Ethereum, AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol'; |
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.
AaveV3Ethereum import is unused, please remove
| import {IERC20} from 'openzeppelin-contracts/contracts/token/ERC20/IERC20.sol'; | ||
| import {AaveV3Plasma, AaveV3PlasmaAssets} from 'aave-address-book/AaveV3Plasma.sol'; | ||
| import {GovernanceV3Plasma} from 'aave-address-book/GovernanceV3Plasma.sol'; |
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.
IERC20, AaveV3PlasmaAssets, and GovernanceV3Plasma all unused, please remove
| | LT | 78 % | | ||
| | Liquidation Bonus | 4.5 % | | ||
| | Liquidation Protocol Fee | 10 % | | ||
| | Reserve Factor | 10 % | |
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.
Proposal actually shows reserve factor should be 5% https://governance.aave.com/t/arfc-launch-gho-on-plasma-set-aci-as-emissions-manager-for-rewards/22994/6
| ltv: 75_00, | ||
| liqThreshold: 78_00, | ||
| liqBonus: 4_50, | ||
| reserveFactor: 10_00, |
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.
Proposal shows reserveFactor should be 5%, not 10%: https://governance.aave.com/t/arfc-launch-gho-on-plasma-set-aci-as-emissions-manager-for-rewards/22994/6
| eModeCategory: 7, | ||
| ltv: 84_40, | ||
| liqThreshold: 86_40, | ||
| liqBonus: EngineFlags.KEEP_CURRENT, |
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 add tests showing these e-mode configurations are correct according to the proposal? This should be 6%, and the liqBonus for the above should be 4.9%
|
|
||
| Will receive GHO incentives (~3.50%) such that the Total Supply yield (Native + Incentives) exceeds the native syrupUSDT yield by approximately 50bps. | ||
|
|
||
| The above incentive strategies create GHO Supply on Aave Protocol. Sourcing the GHO is expected to at least partially flow from through the remote GSM, which deposits USDT into Aave whereby the DAO earns the Supply yield. |
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.
| The above incentive strategies create GHO Supply on Aave Protocol. Sourcing the GHO is expected to at least partially flow from through the remote GSM, which deposits USDT into Aave whereby the DAO earns the Supply yield. | |
| The above incentive strategies create GHO Supply on Aave Protocol. Sourcing the GHO is expected to at least partially flow from through the remote GSM, which deposits USDT0 into Aave whereby the DAO earns the Supply yield. |
Maybe nbd, but proposal writes it like this
|
|
||
| With strong GHO supply expected from the GHO incentives, GHO demand is created via the revision of eMode 2 to include GHO as a debt asset. eMode 2 is to offer sUSDe and USDe as collateral with USDT and GHO as debt, the GHO debt will receive a x5 Sats multiplier from the Ethena team that matches what is currently available on the Ethereum Core and Prime instances. | ||
|
|
||
| This is expected to stimulate Demand for GHO on Aave Protocol with GHO expected to be a lower cost alternative to USDT due to the Borrow Rate configuration (150bps less than USDT at Uoptimal) and additional Sat incentives acting to offset the cost of capital for leverage users. |
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.
Here too
| This is expected to stimulate Demand for GHO on Aave Protocol with GHO expected to be a lower cost alternative to USDT due to the Borrow Rate configuration (150bps less than USDT at Uoptimal) and additional Sat incentives acting to offset the cost of capital for leverage users. | |
| This is expected to stimulate Demand for GHO on Aave Protocol with GHO expected to be a lower cost alternative to USDT0 due to the Borrow Rate configuration (150bps less than USDT at Uoptimal) and additional Sat incentives acting to offset the cost of capital for leverage users. |
| | Supply Cap (GHO) | 5,000,000 | | ||
| | Borrow Cap (GHO) | 4,500,000 | |
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.
According to https://governance.aave.com/t/arfc-launch-gho-on-plasma-set-aci-as-emissions-manager-for-rewards/22994/6 should be:
| | Supply Cap (GHO) | 5,000,000 | | |
| | Borrow Cap (GHO) | 4,500,000 | | |
| | Supply Cap (GHO) | 50,000,000 | | |
| | Borrow Cap (GHO) | 20,000,000 | |
| | Collateral | sUSDe, USDe | Yes | No | No | | ||
| | Borrowable | USDT, GHOd | No | Yes | Yes | |
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.
The sUSDe column should not have assets listed in it, but rather Yes or No
| } | ||
|
|
||
| function _updateFeeStrategy() internal { | ||
| IGsm(NEW_GSM_USDT).updateFeeStrategy(FEE_STRATEGY); |
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 does not seem the FEE_STRATEGY has the correct fees from checking the deployed contract on-chain. Please ensure the fees match what is written in the proposal
Note
Execution to be performed as follows:
Ethereum Part 1
Ethereum Part 2 (will revert until after a few seconds of part 1 being executed)
Wait for Bridge from Ethereum to go through, Plasma incoming bridge will likely fail because of the inbound rate limit, in which case it can be manually retried here: https://ccip.chain.link/. However, if the Plasma part 1 execution is done quickly (within 10 minutes from Ethereum Part 2), the bridge is likely to succeed as the Plasma check is done upon resolution.
Plasma Part 1
Plasma Part 2 (will revert until there is enough GHO from Part 1)
This proposal includes some buffer in case more GHO is bridged from Mainnet to Plasma in order for it to be included in the Merkle proof.
Changelog
Bridge GHO to Plasma.
Add new GSM on Plasma.
Add Gho to Aave on Plasma.
Test Bridging Transaction
Here