-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
feat(protocol): Add votes and snapshot plugins to BridgedERC20 #15715
Changes from 4 commits
798469e
7cfd7a0
039cb7a
c2ee32b
dbd0695
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,7 +40,15 @@ contract ERC721Airdrop is MerkleClaimable { | |
vault = _vault; | ||
} | ||
|
||
function _claimWithData(bytes calldata data) internal override { | ||
function _claimWithData( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ERC721Airdrop shall not be changed at all -- delegation shall not be something MerkleClaimable shall care. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then how do you achieve the desired one transaction per airdrop ? I already told you and Keng i prefer the 2 time transactions, because of errors too for example (UI does not consturcts sig things properly, etc.) |
||
bytes calldata data, | ||
address /*delegatee*/, | ||
uint256 /*nonce*/, | ||
uint256 /*expiry*/, | ||
uint8 /*v*/, | ||
bytes32 /*r*/, | ||
bytes32 /*s*/ | ||
) internal override { | ||
(address user, uint256[] memory tokenIds) = abi.decode(data, (address, uint256[])); | ||
|
||
for (uint256 i; i < tokenIds.length; ++i) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,17 @@ import { MerkleProofUpgradeable } from | |
"lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/MerkleProofUpgradeable.sol"; | ||
import "../../common/EssentialContract.sol"; | ||
|
||
interface Delegation { | ||
function delegateBySig( | ||
address delegatee, | ||
uint256 nonce, | ||
uint256 expiry, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) external; | ||
} | ||
|
||
/// @title MerkleClaimable | ||
/// Contract for managing Taiko token airdrop for eligible users | ||
abstract contract MerkleClaimable is EssentialContract { | ||
|
@@ -44,7 +55,13 @@ abstract contract MerkleClaimable is EssentialContract { | |
|
||
function claim( | ||
bytes calldata data, | ||
bytes32[] calldata proof | ||
bytes32[] calldata proof, | ||
address delegatee, | ||
uint256 nonce, | ||
uint256 expiry, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) | ||
external | ||
nonReentrant | ||
|
@@ -59,7 +76,15 @@ abstract contract MerkleClaimable is EssentialContract { | |
} | ||
|
||
isClaimed[hash] = true; | ||
_claimWithData(data); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems a bit like a strange setup where the claiming has an extra internal function to extend the functionality. More logical to me would be to have an external There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think from the op's perspective, we want to make sure if some one is in the airdrop list, the address must claim by itself, no way can claim for it, so we filter out dead addresses. And we also want to make sure whenever you claim, you must delegate to someone. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. However, the extra function shall go to ERC20Aridrop contracts, not in this parent contract. |
||
_claimWithData( | ||
data, | ||
delegatee, | ||
nonce, | ||
expiry, | ||
v, | ||
r, | ||
s | ||
); | ||
emit Claimed(hash); | ||
} | ||
|
||
|
@@ -85,5 +110,13 @@ abstract contract MerkleClaimable is EssentialContract { | |
} | ||
|
||
/// @dev Must revert in case of errors. | ||
function _claimWithData(bytes calldata data) internal virtual; | ||
function _claimWithData( | ||
bytes calldata data, | ||
address delegate, | ||
uint256 nonce, | ||
uint256 expiry, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) internal virtual; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,14 +17,22 @@ pragma solidity 0.8.24; | |
import | ||
"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; | ||
import "lib/openzeppelin-contracts/contracts/utils/Strings.sol"; | ||
|
||
import | ||
"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20SnapshotUpgradeable.sol"; | ||
import | ||
"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol"; | ||
import "./LibBridgedToken.sol"; | ||
import "./BridgedERC20Base.sol"; | ||
|
||
/// @title BridgedERC20 | ||
/// @notice An upgradeable ERC20 contract that represents tokens bridged from | ||
/// another chain. | ||
contract BridgedERC20 is BridgedERC20Base, IERC20MetadataUpgradeable, ERC20Upgradeable { | ||
contract BridgedERC20 is | ||
BridgedERC20Base, | ||
IERC20MetadataUpgradeable, | ||
ERC20SnapshotUpgradeable, | ||
ERC20VotesUpgradeable | ||
Comment on lines
+30
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The downside of having to do one size fits all, now all bridged tokens need to support the onchain voting functionality because we want it for TKO (will be nicer in the next protocol version!). :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, my proposal was a special check in Bridge -> if TKO then mint into a modified contract. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please see #15726 |
||
{ | ||
address public srcToken; // slot 1 | ||
uint8 private srcDecimals; | ||
uint256 public srcChainId; // slot 2 | ||
|
@@ -65,13 +73,21 @@ contract BridgedERC20 is BridgedERC20Base, IERC20MetadataUpgradeable, ERC20Upgra | |
// Initialize OwnerUUPSUpgradable and ERC20Upgradeable | ||
__Essential_init(_addressManager); | ||
__ERC20_init({ name_: _name, symbol_: _symbol }); | ||
__ERC20Snapshot_init(); | ||
__ERC20Votes_init(); | ||
__ERC20Permit_init(_name); | ||
|
||
// Set contract properties | ||
srcToken = _srcToken; | ||
srcChainId = _srcChainId; | ||
srcDecimals = _decimals; | ||
} | ||
|
||
/// @notice Creates a new token snapshot. | ||
function snapshot() public onlyOwner { | ||
adaki2004 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_snapshot(); | ||
} | ||
|
||
/// @notice Gets the name of the token. | ||
/// @return The name. | ||
function name() | ||
|
@@ -119,16 +135,49 @@ contract BridgedERC20 is BridgedERC20Base, IERC20MetadataUpgradeable, ERC20Upgra | |
_burn(from, amount); | ||
} | ||
|
||
/// @dev For ERC20SnapshotUpgradeable and ERC20VotesUpgradeable, need to implement the following | ||
/// functions | ||
function _beforeTokenTransfer( | ||
address, /*from*/ | ||
address from, | ||
address to, | ||
uint256 /*amount*/ | ||
uint256 amount | ||
) | ||
internal | ||
virtual | ||
override | ||
override(ERC20Upgradeable, ERC20SnapshotUpgradeable) | ||
adaki2004 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
if (to == address(this)) revert BTOKEN_CANNOT_RECEIVE(); | ||
if (paused()) revert INVALID_PAUSE_STATUS(); | ||
super._beforeTokenTransfer(from, to, amount); | ||
} | ||
|
||
function _afterTokenTransfer( | ||
address from, | ||
address to, | ||
uint256 amount | ||
) | ||
internal | ||
override(ERC20Upgradeable, ERC20VotesUpgradeable) | ||
{ | ||
super._afterTokenTransfer(from, to, amount); | ||
} | ||
|
||
function _mint( | ||
address to, | ||
uint256 amount | ||
) | ||
internal | ||
override(ERC20Upgradeable, ERC20VotesUpgradeable) | ||
{ | ||
super._mint(to, amount); | ||
} | ||
|
||
function _burn( | ||
address from, | ||
uint256 amount | ||
) | ||
internal | ||
override(ERC20Upgradeable, ERC20VotesUpgradeable) | ||
{ | ||
super._burn(from, 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.
If both ERC20Airdrop and ERC20Airdrop2 allow claiming, we shall create a parent contract and move shared code there.