-
Notifications
You must be signed in to change notification settings - Fork 2
Staking v2 #10
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
ra-phael
wants to merge
18
commits into
main
Choose a base branch
from
staking-v2
base: main
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
Staking v2 #10
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
019f572
add first option for staking
ra-phael ca96311
rename tokenHolder to tokenOwner
ra-phael ec50633
introduce second option for staking
ra-phael 9d99752
small change
ra-phael 737f3dc
fix typos
ra-phael 5848a76
add comment
ra-phael 87119b0
decrease stakeholder stake when burning
ra-phael 7bb7e08
add test
ra-phael 6146807
update rules for burning
ra-phael 800f273
remove stakable option
ra-phael 7dd90d5
update holdable
ra-phael 747ddee
update with burnHeldTokens
ra-phael fe9c54b
update holdable mocks
ra-phael 45ebece
update tests
ra-phael c55b583
move event burn acknowledgment event
ra-phael d1590c6
update tests around burning
ra-phael 6915a1b
add tests for burn notification and minor improvements
ra-phael 8f7b1db
add comments
ra-phael 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,89 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity ^0.8.0; | ||
|
|
||
| import "../ERC1238.sol"; | ||
| import "./IERC1238Holdable.sol"; | ||
| import "./IERC1238Holder.sol"; | ||
|
|
||
| /** | ||
| * @dev Proposal for ERC1238 tokens extension that allow addresses | ||
| * to hold tokens on behalf of others. | ||
| */ | ||
| abstract contract ERC1238Holdable is IERC1238Holdable, ERC1238 { | ||
| using Address for address; | ||
|
|
||
| // Mapping holder => id => balance | ||
| mapping(address => mapping(uint256 => uint256)) private _heldBalances; | ||
|
|
||
| function heldBalance(address holder, uint256 id) public view override returns (uint256) { | ||
| return _heldBalances[holder][id]; | ||
| } | ||
|
|
||
| /** | ||
| * @dev Hooks into the minting flow to set the token recipient as first holder | ||
| * by default when tokens are minted. | ||
| */ | ||
| function _beforeMint( | ||
| address, | ||
| address to, | ||
| uint256 id, | ||
| uint256 amount, | ||
| bytes memory | ||
| ) internal virtual override { | ||
| _heldBalances[to][id] += amount; | ||
| } | ||
|
|
||
| /** | ||
| * @dev Burns `amount` of tokens that are held by `holder` and owned by `from`. | ||
| * If `holder` is a smart contract and inherits {IERC1238Holder}, it notifies it to give it a chance to | ||
| * react to the burn and handle the operation how it sees fit. | ||
| * | ||
| * Requirements: | ||
| * - `holder` should hold at least the `amount` of tokens with the `id` passed | ||
| */ | ||
| function _burnHeldTokens( | ||
|
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 would still just call this a |
||
| address burner, | ||
| address holder, | ||
| address from, | ||
| uint256 id, | ||
| uint256 amount | ||
| ) internal virtual { | ||
| require(_heldBalances[holder][id] >= amount, "ERC1238Holdable: Amount to burn exceeds amount held"); | ||
|
|
||
| if (holder.isContract()) { | ||
| try IERC1238Holder(holder).onBurn(id, amount) returns (bool isBurnAcknowledged) { | ||
| if (!isBurnAcknowledged) emit BurnAcknowledgmentFailed(holder, burner, from, id, amount); | ||
| } catch { | ||
| emit BurnAcknowledgmentFailed(holder, burner, from, id, amount); | ||
| } | ||
| } | ||
|
|
||
| super._burn(from, id, amount); | ||
|
|
||
| _heldBalances[holder][id] -= amount; | ||
| } | ||
|
|
||
| /** | ||
| * @dev Lets sender entrusts `to` with `amount` | ||
| * of tokens which gets transferred between their respective heldBalances | ||
| */ | ||
| function _entrust( | ||
| address to, | ||
| uint256 id, | ||
| uint256 amount | ||
| ) internal virtual { | ||
| address from = msg.sender; | ||
|
|
||
| uint256 fromBalance = _heldBalances[from][id]; | ||
| require(fromBalance >= amount, "ERC1238Holdable: amount exceeds balance held"); | ||
|
|
||
| _heldBalances[from][id] -= amount; | ||
| _heldBalances[to][id] += amount; | ||
|
|
||
| emit Entrust(from, to, id, amount); | ||
| } | ||
|
|
||
| // TODO: Add a function to provide a safer alternative which | ||
| // makes sure the recipient is a IERC1238Holder contract (same as idea as in IERC1238Receiver) | ||
| } | ||
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,37 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity ^0.8.0; | ||
|
|
||
| import "../IERC1238.sol"; | ||
|
|
||
| /** | ||
| * @dev Proposal of an interface for ERC1238 tokens that can be held by another address than | ||
| * than their owner or staked in a smart contract. | ||
| */ | ||
| interface IERC1238Holdable is IERC1238 { | ||
| /** | ||
| * @dev Event emitted when `from` entrusts `to` with `amount` of tokens with token `id`. | ||
| */ | ||
| event Entrust(address from, address to, uint256 indexed id, uint256 amount); | ||
|
|
||
| /** | ||
| * @dev Event emitted when tokens are burnt and the holder fails to acknowledge the burn. | ||
| */ | ||
| event BurnAcknowledgmentFailed(address holder, address burner, address from, uint256 indexed id, uint256 amount); | ||
|
|
||
| /** | ||
| * @dev Returns the balance of a token holder for a given `id`. | ||
| */ | ||
| function heldBalance(address holder, uint256 id) external view returns (uint256); | ||
|
|
||
| /** | ||
| * @dev Lets sender entrusts `to` with `amount` | ||
| * of tokens which gets transferred between their respective balances | ||
| * of tokens held. | ||
| */ | ||
| function entrust( | ||
| address to, | ||
| uint256 id, | ||
| uint256 amount | ||
| ) external; | ||
| } |
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,15 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import "../IERC1238.sol"; | ||
| import "../IERC1238Receiver.sol"; | ||
|
|
||
| /** | ||
| * @dev Interface proposal for contracts that need to hold ERC1238 tokens. | ||
| */ | ||
| interface IERC1238Holder is IERC1238Receiver { | ||
| /** | ||
| * @dev This function is called when tokens with id `id` are burnt. | ||
| */ | ||
| function onBurn(uint256 id, uint256 amount) external returns (bool); | ||
| } |
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,66 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity ^0.8.0; | ||
|
|
||
| import "../ERC1238/ERC1238.sol"; | ||
| import "../ERC1238/extensions/ERC1238Holdable.sol"; | ||
|
|
||
| /** | ||
| * @dev Mock contract for ERC1238 tokens using ERC1238Holdable extension | ||
| */ | ||
| contract ERC1238HoldableMock is ERC1238, ERC1238Holdable { | ||
| constructor(string memory uri) ERC1238(uri) {} | ||
|
|
||
| function _beforeMint( | ||
| address minter, | ||
| address to, | ||
| uint256 id, | ||
| uint256 amount, | ||
| bytes memory data | ||
| ) internal override(ERC1238, ERC1238Holdable) { | ||
| super._beforeMint(minter, to, id, amount, data); | ||
| } | ||
|
|
||
| function mintToContract( | ||
| address to, | ||
| uint256 id, | ||
| uint256 amount, | ||
| bytes memory data | ||
| ) public { | ||
| _mintToContract(to, id, amount, data); | ||
| } | ||
|
|
||
| function mintBatchToContract( | ||
| address to, | ||
| uint256[] memory ids, | ||
| uint256[] memory amounts, | ||
| bytes memory data | ||
| ) public { | ||
| _mintBatchToContract(to, ids, amounts, data); | ||
| } | ||
|
|
||
| function burnHeldTokens( | ||
| address holder, | ||
| address from, | ||
| uint256 id, | ||
| uint256 amount | ||
| ) public { | ||
| _burnHeldTokens(msg.sender, holder, from, id, amount); | ||
| } | ||
|
|
||
| function burnBatch( | ||
| address owner, | ||
| uint256[] memory ids, | ||
| uint256[] memory amounts | ||
| ) public { | ||
| _burnBatch(owner, ids, amounts); | ||
| } | ||
|
|
||
| function entrust( | ||
| address to, | ||
| uint256 id, | ||
| uint256 amount | ||
| ) public override { | ||
| _entrust(to, id, amount); | ||
| } | ||
| } |
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,65 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity ^0.8.0; | ||
|
|
||
| import "../ERC1238/IERC1238Receiver.sol"; | ||
| import "../ERC1238/extensions/IERC1238Holdable.sol"; | ||
| import "../ERC1238/extensions/IERC1238Holder.sol"; | ||
|
|
||
| import "./ERC1238HoldableMock.sol"; | ||
|
|
||
| // This is a dummy example of a ERC1238Holder with arbitrary rules. | ||
| // It will reject non-transferable tokens if the token id is 0 in the case of a single token mint | ||
| // or if the first token id is 0 for a batch mint. | ||
| // | ||
| // It will also acknowledge and emit an event when tokens are burnt. | ||
| contract ERC1238HolderMock is IERC1238Receiver, IERC1238Holder { | ||
| // bytes4(keccak256("onERC1238Mint(address,uint256,uint256,bytes)")) | ||
| bytes4 public constant ERC1238_ON_MINT = 0x45ed75d5; | ||
|
|
||
| // bytes4(keccak256("onERC1238BatchMint(address,uint256[],uint256[],bytes)")) | ||
| bytes4 public constant ERC1238_ON_BATCH_MINT = 0xc0bfec68; | ||
|
|
||
| event TokenBurnt(uint256 id, uint256 amount); | ||
|
|
||
| function onERC1238Mint( | ||
| address, | ||
| uint256 id, | ||
| uint256, | ||
| bytes calldata | ||
| ) external pure override returns (bytes4) { | ||
| if (id == 0) { | ||
| return bytes4(0); | ||
| } | ||
|
|
||
| return ERC1238_ON_MINT; | ||
| } | ||
|
|
||
| function onERC1238BatchMint( | ||
| address, | ||
| uint256[] calldata ids, | ||
| uint256[] calldata, | ||
| bytes calldata | ||
| ) external pure override returns (bytes4) { | ||
| if (ids[0] == 0) { | ||
| return bytes4(0); | ||
| } | ||
|
|
||
| return ERC1238_ON_BATCH_MINT; | ||
| } | ||
|
|
||
| function entrust( | ||
| address targetContract, | ||
| address to, | ||
| uint256 id, | ||
| uint256 amount | ||
| ) external { | ||
| IERC1238Holdable(targetContract).entrust(to, id, amount); | ||
| } | ||
|
|
||
| function onBurn(uint256 id, uint256 amount) public override returns (bool) { | ||
| emit TokenBurnt(id, amount); | ||
|
|
||
| return true; | ||
| } | ||
| } |
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,63 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity ^0.8.0; | ||
|
|
||
| import "../ERC1238/IERC1238Receiver.sol"; | ||
| import "../ERC1238/extensions/IERC1238Holdable.sol"; | ||
|
|
||
| import "./ERC1238HoldableMock.sol"; | ||
|
|
||
| // This is a dummy example of a ERC1238Receiver with arbitrary rules. | ||
| // It will reject non-transferable tokens if the token id is 0 in the case of a single token mint | ||
| // or if the first token id is 0 for a batch mint. | ||
| contract ERC1238ReceiverHoldableMock is IERC1238Receiver { | ||
| // bytes4(keccak256("onERC1238Mint(address,uint256,uint256,bytes)")) | ||
| bytes4 public constant ERC1238_ON_MINT = 0x45ed75d5; | ||
|
|
||
| // bytes4(keccak256("onERC1238BatchMint(address,uint256[],uint256[],bytes)")) | ||
| bytes4 public constant ERC1238_ON_BATCH_MINT = 0xc0bfec68; | ||
|
|
||
| function onERC1238Mint( | ||
| address, | ||
| uint256 id, | ||
| uint256, | ||
| bytes calldata | ||
| ) external pure override returns (bytes4) { | ||
| if (id == 0) { | ||
| return bytes4(0); | ||
| } | ||
|
|
||
| return ERC1238_ON_MINT; | ||
| } | ||
|
|
||
| function onERC1238BatchMint( | ||
| address, | ||
| uint256[] calldata ids, | ||
| uint256[] calldata, | ||
| bytes calldata | ||
| ) external pure override returns (bytes4) { | ||
| if (ids[0] == 0) { | ||
| return bytes4(0); | ||
| } | ||
|
|
||
| return ERC1238_ON_BATCH_MINT; | ||
| } | ||
|
|
||
| function entrust( | ||
| address targetContract, | ||
| address to, | ||
| uint256 id, | ||
| uint256 amount | ||
| ) external { | ||
| IERC1238Holdable(targetContract).entrust(to, id, amount); | ||
| } | ||
|
|
||
| function burnHeldTokens( | ||
| address targetContract, | ||
| address holder, | ||
| uint256 id, | ||
| uint256 amount | ||
| ) external { | ||
| ERC1238HoldableMock(targetContract).burnHeldTokens(holder, address(this), id, amount); | ||
| } | ||
| } |
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.
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.
Should we add another mapping for discoverability?
As a user/application I would want an easy way to check who might be a holder of a particular token. This mapping just gives us the balances of a specific holder we might be interested in.