-
Notifications
You must be signed in to change notification settings - Fork 0
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
add base XPToken with IXPProvider interface #10
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
4262994
feat(XPToken): add base XPToken with IXPProvider interface
gravityblast c9e44de
chore: update libs
gravityblast 5b1d529
chore(XPToken): use XP Contribution for providers functions
gravityblast 92ae1d6
test(XPToken): add tests
gravityblast bae9fec
chore(XPToken): add certora base config
gravityblast b963336
chore(XPToken): use share instead of contribution in IXPProvider func…
gravityblast c4dba08
chore(XPToken): rename local variables to use the suffix share instea…
gravityblast c77c795
chore: update gas reports
gravityblast 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 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
This file contains 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 |
---|---|---|
@@ -1,24 +1,38 @@ | ||
IntegrationTest:testStake() (gas: 1378213) | ||
IntegrationTest:testStake() (gas: 1378182) | ||
RewardsStreamerTest:testStake() (gas: 869874) | ||
StakeTest:test_StakeMultipleAccounts() (gas: 438756) | ||
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 586002) | ||
StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 449214) | ||
StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 470881) | ||
StakeTest:test_StakeOneAccount() (gas: 267795) | ||
StakeTest:test_StakeOneAccountAndRewards() (gas: 415039) | ||
StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 284120) | ||
StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 284152) | ||
StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 284196) | ||
UnstakeTest:test_StakeMultipleAccounts() (gas: 438778) | ||
UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 586002) | ||
UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 449214) | ||
UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 470903) | ||
UnstakeTest:test_StakeOneAccount() (gas: 267795) | ||
UnstakeTest:test_StakeOneAccountAndRewards() (gas: 415061) | ||
UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 284120) | ||
UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 284152) | ||
UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 284196) | ||
UnstakeTest:test_UnstakeMultipleAccounts() (gas: 616327) | ||
UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 937593) | ||
UnstakeTest:test_UnstakeOneAccount() (gas: 446306) | ||
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 557157) | ||
StakeTest:test_StakeMultipleAccounts() (gas: 438733) | ||
StakeTest:test_StakeMultipleAccountsAndRewards() (gas: 586000) | ||
StakeTest:test_StakeMultipleAccountsMPIncreasesPotentialMPDecreases() (gas: 761311) | ||
StakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 449348) | ||
StakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 471037) | ||
StakeTest:test_StakeOneAccount() (gas: 267794) | ||
StakeTest:test_StakeOneAccountAndRewards() (gas: 415103) | ||
StakeTest:test_StakeOneAccountMPIncreasesPotentialMPDecreases() (gas: 484709) | ||
StakeTest:test_StakeOneAccountReachingMPLimit() (gas: 446674) | ||
StakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 284253) | ||
StakeTest:test_StakeOneAccountWithMinLockUp() (gas: 284263) | ||
StakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 284307) | ||
UnstakeTest:test_StakeMultipleAccounts() (gas: 438755) | ||
UnstakeTest:test_StakeMultipleAccountsAndRewards() (gas: 586045) | ||
UnstakeTest:test_StakeMultipleAccountsMPIncreasesPotentialMPDecreases() (gas: 761245) | ||
UnstakeTest:test_StakeMultipleAccountsWithMinLockUp() (gas: 449348) | ||
UnstakeTest:test_StakeMultipleAccountsWithRandomLockUp() (gas: 471059) | ||
UnstakeTest:test_StakeOneAccount() (gas: 267794) | ||
UnstakeTest:test_StakeOneAccountAndRewards() (gas: 415125) | ||
UnstakeTest:test_StakeOneAccountMPIncreasesPotentialMPDecreases() (gas: 484709) | ||
UnstakeTest:test_StakeOneAccountReachingMPLimit() (gas: 446696) | ||
UnstakeTest:test_StakeOneAccountWithMaxLockUp() (gas: 284276) | ||
UnstakeTest:test_StakeOneAccountWithMinLockUp() (gas: 284263) | ||
UnstakeTest:test_StakeOneAccountWithRandomLockUp() (gas: 284352) | ||
UnstakeTest:test_UnstakeMultipleAccounts() (gas: 616281) | ||
UnstakeTest:test_UnstakeMultipleAccountsAndRewards() (gas: 937677) | ||
UnstakeTest:test_UnstakeOneAccount() (gas: 446369) | ||
UnstakeTest:test_UnstakeOneAccountAndRewards() (gas: 557220) | ||
XPTokenTest:testAddXPProviderOnlyOwner() (gas: 285732) | ||
XPTokenTest:testBalanceOf() (gas: 210530) | ||
XPTokenTest:testBalanceOfWithNoSystemTotalXP() (gas: 45808) | ||
XPTokenTest:testRemoveXPProviderIndexOutOfBounds() (gas: 36277) | ||
XPTokenTest:testRemoveXPProviderOnlyOwner() (gas: 72074) | ||
XPTokenTest:testSetTotalSupplyOnlyOwner() (gas: 70544) | ||
XPTokenTest:testTotalSupply() (gas: 10507) | ||
XPTokenTest:testTransfersNotAllowed() (gas: 20634) |
This file contains 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 |
---|---|---|
|
@@ -11,4 +11,3 @@ | |
"@openzeppelin=lib/openzeppelin-contracts" | ||
] | ||
} | ||
|
This file contains 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,13 @@ | ||
{ | ||
"files": ["src/XPToken.sol"], | ||
"msg": "Verifying XPToken.sol", | ||
"rule_sanity": "basic", | ||
"verify": "XPToken:certora/specs/XPToken.spec", | ||
"wait_for_results": "all", | ||
"optimistic_loop": true, | ||
"loop_iter": "3", | ||
"packages": [ | ||
"forge-std=lib/forge-std/src", | ||
"@openzeppelin=lib/openzeppelin-contracts" | ||
] | ||
} |
This file contains 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 |
---|---|---|
@@ -1,3 +1,3 @@ | ||
rule checkIdOutputIsAlwaysEqualToInput { | ||
rule test { | ||
assert true; | ||
} |
This file contains 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,3 @@ | ||
rule test { | ||
assert true; | ||
} |
Submodule forge-std
updated
21 files
+1 −1 | README.md | |
+1 −1 | package.json | |
+12 −1 | scripts/vm.py | |
+4 −0 | src/StdChains.sol | |
+3 −3 | src/StdCheats.sol | |
+104 −0 | src/StdJson.sol | |
+104 −0 | src/StdToml.sol | |
+148 −16 | src/Vm.sol | |
+471 −463 | src/console.sol | |
+2 −2 | src/interfaces/IERC4626.sol | |
+1 −1 | test/StdAssertions.t.sol | |
+14 −12 | test/StdChains.t.sol | |
+10 −10 | test/StdCheats.t.sol | |
+12 −12 | test/StdError.t.sol | |
+1 −1 | test/StdJson.t.sol | |
+4 −14 | test/StdMath.t.sol | |
+5 −5 | test/StdStorage.t.sol | |
+1 −1 | test/StdStyle.t.sol | |
+1 −1 | test/StdToml.t.sol | |
+12 −12 | test/StdUtils.t.sol | |
+9 −6 | test/Vm.t.sol |
Submodule openzeppelin-contracts
updated
453 files
This file contains 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
This file contains 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,76 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.26; | ||
|
||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; | ||
import { IXPProvider } from "./interfaces/IXPProvider.sol"; | ||
|
||
contract XPToken is Ownable { | ||
gravityblast marked this conversation as resolved.
Show resolved
Hide resolved
|
||
string public constant name = "XP Token"; | ||
string public constant symbol = "XP"; | ||
uint256 public constant decimals = 18; | ||
|
||
uint256 public totalSupply; | ||
|
||
IXPProvider[] public xpProviders; | ||
|
||
error XPToken__TransfersNotAllowed(); | ||
error XPProvider__IndexOutOfBounds(); | ||
|
||
constructor(uint256 _totalSupply) Ownable(msg.sender) { | ||
totalSupply = _totalSupply; | ||
} | ||
|
||
function setTotalSupply(uint256 _totalSupply) external onlyOwner { | ||
totalSupply = _totalSupply; | ||
} | ||
gravityblast marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
function addXPProvider(IXPProvider provider) external onlyOwner { | ||
xpProviders.push(provider); | ||
} | ||
|
||
function removeXPProvider(uint256 index) external onlyOwner { | ||
if (index >= xpProviders.length) { | ||
revert XPProvider__IndexOutOfBounds(); | ||
} | ||
|
||
xpProviders[index] = xpProviders[xpProviders.length - 1]; | ||
xpProviders.pop(); | ||
} | ||
|
||
function getXPProviders() external view returns (IXPProvider[] memory) { | ||
return xpProviders; | ||
} | ||
|
||
function balanceOf(address account) public view returns (uint256) { | ||
uint256 userTotalXPShare = 0; | ||
uint256 totalXPShares = 0; | ||
|
||
for (uint256 i = 0; i < xpProviders.length; i++) { | ||
IXPProvider provider = xpProviders[i]; | ||
userTotalXPShare += provider.getUserXPShare(account); | ||
totalXPShares += provider.getTotalXPShares(); | ||
} | ||
|
||
if (totalXPShares == 0) { | ||
return 0; | ||
} | ||
|
||
return (totalSupply * userTotalXPShare) / totalXPShares; | ||
} | ||
|
||
function transfer(address, uint256) external pure returns (bool) { | ||
revert XPToken__TransfersNotAllowed(); | ||
} | ||
|
||
function approve(address, uint256) external pure returns (bool) { | ||
revert XPToken__TransfersNotAllowed(); | ||
} | ||
|
||
function transferFrom(address, address, uint256) external pure returns (bool) { | ||
revert XPToken__TransfersNotAllowed(); | ||
} | ||
|
||
function allowance(address, address) external pure returns (uint256) { | ||
return 0; | ||
} | ||
} |
This file contains 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,7 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.26; | ||
|
||
interface IXPProvider { | ||
function getTotalXPShares() external view returns (uint256); | ||
function getUserXPShare(address user) external view returns (uint256); | ||
} |
This file contains 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,126 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.26; | ||
|
||
import { Test } from "forge-std/Test.sol"; | ||
import { XPToken } from "../src/XPToken.sol"; | ||
import { XPProviderMock } from "./mocks/XPProviderMock.sol"; | ||
import { IXPProvider } from "../src/interfaces/IXPProvider.sol"; | ||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; | ||
|
||
contract XPTokenTest is Test { | ||
XPToken xpToken; | ||
address owner = address(0x1); | ||
address alice = address(0x2); | ||
address bob = address(0x3); | ||
|
||
XPProviderMock provider1; | ||
XPProviderMock provider2; | ||
|
||
function setUp() public { | ||
vm.prank(owner); | ||
xpToken = new XPToken(1000e18); | ||
|
||
provider1 = new XPProviderMock(); | ||
provider2 = new XPProviderMock(); | ||
|
||
vm.prank(owner); | ||
xpToken.addXPProvider(provider1); | ||
|
||
vm.prank(owner); | ||
xpToken.addXPProvider(provider2); | ||
} | ||
|
||
function testAddXPProviderOnlyOwner() public { | ||
XPProviderMock provider3 = new XPProviderMock(); | ||
|
||
vm.prank(alice); | ||
vm.expectPartialRevert(Ownable.OwnableUnauthorizedAccount.selector); | ||
xpToken.addXPProvider(provider3); | ||
|
||
vm.prank(owner); | ||
xpToken.addXPProvider(provider3); | ||
|
||
IXPProvider[] memory providers = xpToken.getXPProviders(); | ||
assertEq(providers.length, 3); | ||
assertEq(address(providers[0]), address(provider1)); | ||
assertEq(address(providers[1]), address(provider2)); | ||
assertEq(address(providers[2]), address(provider3)); | ||
} | ||
|
||
function testRemoveXPProviderOnlyOwner() public { | ||
vm.prank(alice); | ||
vm.expectPartialRevert(Ownable.OwnableUnauthorizedAccount.selector); | ||
xpToken.removeXPProvider(0); | ||
|
||
vm.prank(owner); | ||
xpToken.removeXPProvider(0); | ||
|
||
IXPProvider[] memory providers = xpToken.getXPProviders(); | ||
assertEq(providers.length, 1); | ||
assertEq(address(providers[0]), address(provider2)); | ||
} | ||
|
||
function testRemoveXPProviderIndexOutOfBounds() public { | ||
vm.prank(owner); | ||
vm.expectRevert(XPToken.XPProvider__IndexOutOfBounds.selector); | ||
xpToken.removeXPProvider(10); | ||
} | ||
|
||
function testTotalSupply() public view { | ||
uint256 totalSupply = xpToken.totalSupply(); | ||
assertEq(totalSupply, 1000 ether); | ||
} | ||
|
||
function testBalanceOfWithNoSystemTotalXP() public view { | ||
uint256 aliceBalance = xpToken.balanceOf(alice); | ||
assertEq(aliceBalance, 0); | ||
|
||
uint256 bobBalance = xpToken.balanceOf(bob); | ||
assertEq(bobBalance, 0); | ||
} | ||
|
||
function testBalanceOf() public { | ||
provider1.setUserXPShare(alice, 100e18); | ||
provider1.setTotalXPShares(1000e18); | ||
|
||
provider2.setUserXPShare(alice, 200e18); | ||
provider2.setTotalXPShares(2000e18); | ||
|
||
// Expected balance calculation | ||
uint256 userTotalXP = 100e18 + 200e18; | ||
uint256 systemTotalXP = 1000e18 + 2000e18; | ||
|
||
uint256 expectedBalance = (xpToken.totalSupply() * userTotalXP) / systemTotalXP; | ||
|
||
uint256 balance = xpToken.balanceOf(alice); | ||
assertEq(balance, expectedBalance); | ||
} | ||
|
||
function testSetTotalSupplyOnlyOwner() public { | ||
uint256 totalSupply = xpToken.totalSupply(); | ||
assertEq(totalSupply, 1000e18); | ||
|
||
vm.prank(alice); | ||
vm.expectPartialRevert(Ownable.OwnableUnauthorizedAccount.selector); | ||
xpToken.setTotalSupply(2000e18); | ||
|
||
vm.prank(owner); | ||
xpToken.setTotalSupply(2000e18); | ||
totalSupply = xpToken.totalSupply(); | ||
assertEq(totalSupply, 2000e18); | ||
} | ||
|
||
function testTransfersNotAllowed() public { | ||
vm.expectRevert(XPToken.XPToken__TransfersNotAllowed.selector); | ||
xpToken.transfer(alice, 100e18); | ||
|
||
vm.expectRevert(XPToken.XPToken__TransfersNotAllowed.selector); | ||
xpToken.approve(alice, 100e18); | ||
|
||
vm.expectRevert(XPToken.XPToken__TransfersNotAllowed.selector); | ||
xpToken.transferFrom(alice, bob, 100e18); | ||
|
||
uint256 allowance = xpToken.allowance(alice, bob); | ||
assertEq(allowance, 0); | ||
} | ||
} |
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.
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.
We might want to introduce separate CI tasks for these in the github action. But can do that in a follow-up PR