-
Notifications
You must be signed in to change notification settings - Fork 20
Feature: Bridge GoodDollar using OFT adapter via LayerZero Endpoint v2 #289
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
Open
blueogin
wants to merge
9
commits into
master
Choose a base branch
from
feat/oft-adapter-v2
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
a76f010
chore: added dependencies
blueogin e8176fb
feat: GD MinterBurner & OFTAdapter
blueogin 9404a5a
feat: bridge oft xdc to celo
blueogin 1ae0878
feat: add minter role granting script
blueogin 856367f
feat: bridge script
blueogin 0bbcd5f
feat: GoodDollarMinterBurner updated with pausing logic
blueogin 7caea78
feat: add mint/burn limits and bridge configuration for GoodDollarMin…
blueogin c211bff
docs: update .env.example with mint/burn limits for GoodDollarMinterB…
blueogin 9559926
feat: add mint and burn event emissions to GoodDollarMinterBurner; up…
blueogin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| PRIVATE_KEY= | ||
| PUBLIC_KEY= | ||
|
|
||
| ETHERSCAN_KEY= | ||
| ALCHEMY_KEY= | ||
|
|
||
| FORK_CHAIN_ID= | ||
| XDC_RPC_URL= | ||
|
|
||
| # OFT (Omnichain Fungible Token) Mint/Burn Limits for GoodDollarMinterBurner | ||
| # These limits control the maximum amount of G$ tokens that can be minted or burned | ||
| # per week/month via the OFT bridge. Values are in G$ (18 decimals). | ||
| # Example: WEEKLY_MINT_LIMIT=30 means 30 G$ per week | ||
| WEEKLY_MINT_LIMIT=30 | ||
| MONTHLY_MINT_LIMIT=100 | ||
| WEEKLY_BURN_LIMIT=30 | ||
| MONTHLY_BURN_LIMIT=100 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,261 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity >=0.8; | ||
|
|
||
| import {ISuperGoodDollar} from "../superfluid/ISuperGoodDollar.sol"; | ||
| import "../../utils/DAOUpgradeableContract.sol"; | ||
|
|
||
| /** | ||
| * @title GoodDollarMinterBurner | ||
| * @dev DAO-upgradeable contract that handles minting and burning of GoodDollar tokens for OFT | ||
| * | ||
| * This contract is used by the GoodDollarOFTAdapter to mint and burn tokens during | ||
| * cross-chain transfers via LayerZero. It is upgradeable and controlled by the DAO. | ||
| * | ||
| * Key functionalities: | ||
| * - Mint tokens when receiving cross-chain transfers | ||
| * - Burn tokens when sending cross-chain transfers | ||
| * - Manage operators (like OFT adapter) that can mint/burn | ||
| * - Weekly and monthly mint/burn limits (configurable by DAO, 0 to disable) | ||
| * - Automatic period reset when limits are checked | ||
| * - Pause functionality for emergency situations | ||
| * - Upgradeable via DAO governance | ||
| */ | ||
| contract GoodDollarMinterBurner is DAOUpgradeableContract { | ||
| ISuperGoodDollar public token; | ||
| mapping(address => bool) public operators; | ||
|
|
||
| bool public paused; | ||
|
|
||
| // Weekly and monthly limits | ||
| uint256 public weeklyMintLimit; | ||
| uint256 public monthlyMintLimit; | ||
| uint256 public weeklyBurnLimit; | ||
| uint256 public monthlyBurnLimit; | ||
|
|
||
| // Current period tracking | ||
| uint256 public weeklyMinted; | ||
| uint256 public monthlyMinted; | ||
| uint256 public weeklyBurned; | ||
| uint256 public monthlyBurned; | ||
|
|
||
| // Period start timestamps | ||
| uint256 public currentWeekStart; | ||
| uint256 public currentMonthStart; | ||
|
|
||
| // Constants for period duration | ||
| uint256 public constant WEEK_DURATION = 7 days; | ||
| uint256 public constant MONTH_DURATION = 30 days; | ||
|
|
||
| event OperatorSet(address indexed operator, bool status); | ||
| event Paused(address indexed account); | ||
| event Unpaused(address indexed account); | ||
| event WeeklyMintLimitSet(uint256 oldLimit, uint256 newLimit); | ||
| event MonthlyMintLimitSet(uint256 oldLimit, uint256 newLimit); | ||
| event WeeklyBurnLimitSet(uint256 oldLimit, uint256 newLimit); | ||
| event MonthlyBurnLimitSet(uint256 oldLimit, uint256 newLimit); | ||
| event TokensMinted(address indexed to, uint256 amount, address indexed operator); | ||
| event TokensBurned(address indexed from, uint256 amount, address indexed operator); | ||
|
|
||
| modifier onlyOperators() { | ||
| require(operators[msg.sender] || msg.sender == avatar, "Not authorized"); | ||
| require(!paused, "Contract is paused"); | ||
| _; | ||
| } | ||
|
|
||
| /** | ||
| * @dev Initialize the MinterBurner contract | ||
| * @param _token The address of the GoodDollar token contract | ||
| * @param _nameService The NameService contract for DAO integration | ||
| */ | ||
| function initialize( | ||
| ISuperGoodDollar _token, | ||
| INameService _nameService | ||
| ) public initializer { | ||
| require(address(_token) != address(0), "Token address cannot be zero"); | ||
| token = _token; | ||
| setDAO(_nameService); | ||
| currentWeekStart = block.timestamp; | ||
| currentMonthStart = block.timestamp; | ||
| } | ||
|
|
||
| /** | ||
| * @dev Set or remove an operator that can mint/burn tokens | ||
| * @param _operator The address of the operator (e.g., OFT adapter) | ||
| * @param _status True to enable, false to disable | ||
| * | ||
| * Only the DAO avatar can call this function. | ||
| */ | ||
| function setOperator(address _operator, bool _status) external { | ||
| _onlyAvatar(); | ||
| operators[_operator] = _status; | ||
| emit OperatorSet(_operator, _status); | ||
| } | ||
|
|
||
| /** | ||
| * @dev Set the weekly mint limit | ||
| * @param _limit The new weekly mint limit (0 to disable) | ||
| * | ||
| * Only the DAO avatar can call this function. | ||
| */ | ||
| function setWeeklyMintLimit(uint256 _limit) external { | ||
| _onlyAvatar(); | ||
| uint256 oldLimit = weeklyMintLimit; | ||
| weeklyMintLimit = _limit; | ||
| emit WeeklyMintLimitSet(oldLimit, _limit); | ||
| } | ||
|
|
||
| /** | ||
| * @dev Set the monthly mint limit | ||
| * @param _limit The new monthly mint limit (0 to disable) | ||
| * | ||
| * Only the DAO avatar can call this function. | ||
| */ | ||
| function setMonthlyMintLimit(uint256 _limit) external { | ||
| _onlyAvatar(); | ||
| uint256 oldLimit = monthlyMintLimit; | ||
| monthlyMintLimit = _limit; | ||
| emit MonthlyMintLimitSet(oldLimit, _limit); | ||
| } | ||
|
|
||
| /** | ||
| * @dev Set the weekly burn limit | ||
| * @param _limit The new weekly burn limit (0 to disable) | ||
| * | ||
| * Only the DAO avatar can call this function. | ||
| */ | ||
| function setWeeklyBurnLimit(uint256 _limit) external { | ||
| _onlyAvatar(); | ||
| uint256 oldLimit = weeklyBurnLimit; | ||
| weeklyBurnLimit = _limit; | ||
| emit WeeklyBurnLimitSet(oldLimit, _limit); | ||
| } | ||
|
|
||
| /** | ||
| * @dev Set the monthly burn limit | ||
| * @param _limit The new monthly burn limit (0 to disable) | ||
| * | ||
| * Only the DAO avatar can call this function. | ||
| */ | ||
| function setMonthlyBurnLimit(uint256 _limit) external { | ||
| _onlyAvatar(); | ||
| uint256 oldLimit = monthlyBurnLimit; | ||
| monthlyBurnLimit = _limit; | ||
| emit MonthlyBurnLimitSet(oldLimit, _limit); | ||
| } | ||
|
|
||
| /** | ||
| * @dev Internal function to reset weekly period if needed | ||
| */ | ||
| function _resetWeeklyIfNeeded() internal { | ||
| if (block.timestamp >= currentWeekStart + WEEK_DURATION) { | ||
| weeklyMinted = 0; | ||
| weeklyBurned = 0; | ||
| currentWeekStart = block.timestamp; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @dev Internal function to reset monthly period if needed | ||
| */ | ||
| function _resetMonthlyIfNeeded() internal { | ||
| if (block.timestamp >= currentMonthStart + MONTH_DURATION) { | ||
| monthlyMinted = 0; | ||
| monthlyBurned = 0; | ||
| currentMonthStart = block.timestamp; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @dev Burn tokens from an address | ||
| * @param _from The address to burn tokens from | ||
| * @param _amount The amount of tokens to burn | ||
| * @return success True if the burn was successful | ||
| * | ||
| * Only authorized operators (like OFT adapter) or the DAO avatar can call this. | ||
| * Enforces weekly and monthly burn limits if set. | ||
| */ | ||
| function burn(address _from, uint256 _amount) external onlyOperators returns (bool) { | ||
| // Reset periods if needed | ||
| _resetWeeklyIfNeeded(); | ||
| _resetMonthlyIfNeeded(); | ||
|
|
||
| // Check weekly limit (0 means no limit) | ||
| if (weeklyBurnLimit > 0) { | ||
| require(weeklyBurned + _amount <= weeklyBurnLimit, "Weekly burn limit exceeded"); | ||
| } | ||
|
|
||
| // Check monthly limit (0 means no limit) | ||
| if (monthlyBurnLimit > 0) { | ||
| require(monthlyBurned + _amount <= monthlyBurnLimit, "Monthly burn limit exceeded"); | ||
| } | ||
|
|
||
| // Update counters | ||
| weeklyBurned += _amount; | ||
| monthlyBurned += _amount; | ||
|
|
||
| token.burnFrom(_from, _amount); | ||
|
|
||
| emit TokensBurned(_from, _amount, msg.sender); | ||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * @dev Mint tokens to an address | ||
| * @param _to The address to mint tokens to | ||
| * @param _amount The amount of tokens to mint | ||
| * @return success True if the mint was successful | ||
| * | ||
| * Only authorized operators (like OFT adapter) or the DAO avatar can call this. | ||
| * Enforces weekly and monthly mint limits if set. | ||
| */ | ||
| function mint(address _to, uint256 _amount) external onlyOperators returns (bool) { | ||
| // Reset periods if needed | ||
| _resetWeeklyIfNeeded(); | ||
| _resetMonthlyIfNeeded(); | ||
|
|
||
| // Check weekly limit (0 means no limit) | ||
| if (weeklyMintLimit > 0) { | ||
| require(weeklyMinted + _amount <= weeklyMintLimit, "Weekly mint limit exceeded"); | ||
| } | ||
|
|
||
| // Check monthly limit (0 means no limit) | ||
| if (monthlyMintLimit > 0) { | ||
| require(monthlyMinted + _amount <= monthlyMintLimit, "Monthly mint limit exceeded"); | ||
| } | ||
|
|
||
| // Update counters | ||
| weeklyMinted += _amount; | ||
| monthlyMinted += _amount; | ||
|
|
||
| bool success = token.mint(_to, _amount); | ||
| if (success) { | ||
| emit TokensMinted(_to, _amount, msg.sender); | ||
| } | ||
| return success; | ||
| } | ||
|
|
||
| /** | ||
| * @dev Pause all mint and burn operations | ||
| * | ||
| * Only the DAO avatar can call this. Useful for emergency situations. | ||
| */ | ||
| function pause() external { | ||
| _onlyAvatar(); | ||
| require(!paused, "Already paused"); | ||
| paused = true; | ||
| emit Paused(msg.sender); | ||
| } | ||
|
|
||
| /** | ||
| * @dev Unpause mint and burn operations | ||
| * | ||
| * Only the DAO avatar can call this. | ||
| */ | ||
| function unpause() external { | ||
| _onlyAvatar(); | ||
| require(paused, "Not paused"); | ||
| paused = false; | ||
| emit Unpaused(msg.sender); | ||
| } | ||
|
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity >=0.8.0; | ||
|
|
||
| import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; | ||
| import { MintBurnOFTAdapter } from "@layerzerolabs/oft-evm/contracts/MintBurnOFTAdapter.sol"; | ||
| import { IMintableBurnable } from "@layerzerolabs/oft-evm/contracts/interfaces/IMintableBurnable.sol"; | ||
|
|
||
| contract GoodDollarOFTAdapter is MintBurnOFTAdapter { | ||
| constructor( | ||
| address _token, // Your existing ERC20 token with mint/burn exposed | ||
| IMintableBurnable _minterBurner, // Contract with mint/burn privileges | ||
| address _lzEndpoint, // Local LayerZero endpoint | ||
| address _owner // Contract owner | ||
| ) MintBurnOFTAdapter(_token, _minterBurner, _lzEndpoint, _owner) { | ||
| _transferOwnership(_owner); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.