This document enumerates the known execution flows for the Staker
contract.
This document is used as part of the World Builder team's testing process: https://docs.google.com/document/d/1OEW46qwIq1_W3V8u8JDZvrM1ElxwiGEs6LLPdsYXndA/edit?usp=sharing
Any account should be able to deploy a Staker
contract. The constructor should not revert.
Staker
implements the ERC721 token standard. Specifically, it implements the following interfaces:
ERC721
ERC721Metadata
ERC721Enumerable
After deployment, its supportsInterface
method should return true
when queried with the following interface IDs:
0x80ac58cd
(interface ID forERC721
)0x5b5e139f
(interface ID forERC721Metadata
)0x780e9d63
(interface ID forERC721Enumerable
)
The ERC721 metadata must also be set correctly. The name()
method should return "Game7 Staker"
, and
the symbol()
method should return "G7STAKER"
.
Staker
uses special uint256
values to denote the different types of tokens it accepts as stakes.
These special values are:
1
for native token staking - this is signified by theNATIVE_TOKEN_TYPE()
method on theStaker
20
for ERC20 token staking - this is signified by theERC20_TOKEN_TYPE()
method on theStaker
721
for ERC721 token staking - this is signified by theERC721_TOKEN_TYPE()
method on theStaker
1155
for ERC1155 token staking - this is signified by theERC1155_TOKEN_TYPE()
method on theStaker
Any account should be able to create a staking pool for native tokens. That the staking pool is for native tokens should be reflected in the pool parameters.
The account which created the pool should be marked as the administrator of that pool on creation.
The creation of the staking pool should emit a StakingPoolCreated
event of the signature:
event StakingPoolCreated(
uint256 indexed poolID,
uint256 indexed tokenType,
address indexed tokenAddress,
uint256 tokenID
);
Any account should be able to create a staking pool for ERC20 tokens. That the staking pool is for ERC20 tokens should be reflected in the pool parameters.
The account which created the pool should be marked as the administrator of that pool on creation.
The creation of the staking pool should emit a StakingPoolCreated
event of the signature:
event StakingPoolCreated(
uint256 indexed poolID,
uint256 indexed tokenType,
address indexed tokenAddress,
uint256 tokenID
);
Any account should be able to create a staking pool for ERC721 tokens. That the staking pool is for ERC721 tokens should be reflected in the pool parameters.
The account which created the pool should be marked as the administrator of that pool on creation.
The creation of the staking pool should emit a StakingPoolCreated
event of the signature:
event StakingPoolCreated(
uint256 indexed poolID,
uint256 indexed tokenType,
address indexed tokenAddress,
uint256 tokenID
);
Any account should be able to create a staking pool for ERC1155 tokens. That the staking pool is for ERC1155 tokens should be reflected in the pool parameters.
The account which created the pool should be marked as the administrator of that pool on creation.
The creation of the staking pool should emit a StakingPoolCreated
event of the signature:
event StakingPoolCreated(
uint256 indexed poolID,
uint256 indexed tokenType,
address indexed tokenAddress,
uint256 tokenID
);
This behavior should not depend on the pool configuration.
If a user tries to call createPool
using a type that isn't one of 1
(native token), 20
(ERC20),
721
(ERC721), or 1155
(ERC1155), the message should revert with an error having the following signature:
error InvalidTokenType();
STAKER-10
: It should not be possible to create native token staking pools with non-zero token address or token ID
createPool
has the following signature:
function createPool(
uint256 tokenType,
address tokenAddress,
uint256 tokenID,
bool transferable,
uint256 lockupSeconds,
uint256 cooldownSeconds
) external;
If tokenType == 1
, then tokenAddress
and tokenID
must both be zero. If either one is non-zero, the
message should revert with an error having the following signature:
error InvalidConfiguration();
STAKER-11
: It should not be possible to create ERC20 token staking pools with zero token address or non-zero token ID
createPool
has the following signature:
function createPool(
uint256 tokenType,
address tokenAddress,
uint256 tokenID,
bool transferable,
uint256 lockupSeconds,
uint256 cooldownSeconds
) external;
If tokenType == 20
, then tokenAddress
must be non-zero and tokenID
must be zero. If either condition is violated,
the message should revert with an error having the following signature:
error InvalidConfiguration();
STAKER-12
: It should not be possible to create ERC721 token staking pools with zero token address or non-zero token ID
createPool
has the following signature:
function createPool(
uint256 tokenType,
address tokenAddress,
uint256 tokenID,
bool transferable,
uint256 lockupSeconds,
uint256 cooldownSeconds
) external;
If tokenType == 721
, then tokenAddress
must be non-zero and tokenID
must be zero. If either condition is violated,
the message should revert with an error having the following signature:
error InvalidConfiguration();
createPool
has the following signature:
function createPool(
uint256 tokenType,
address tokenAddress,
uint256 tokenID,
bool transferable,
uint256 lockupSeconds,
uint256 cooldownSeconds
) external;
If tokenType == 1155
, then tokenAddress
must be non-zero. If this condition is violated, the message
should revert with an error having the following signature:
error InvalidConfiguration();
STAKER-14
: It should be possible to create ERC1155 token staking pools in which the token ID is zero
This is a specific test that there is no check for the non-zeroness of the token ID being performed on the creation of ERC1155 staking pools.
STAKER-15
: An administrator should be able to modify any subset of the configuration parameters on a pool in a single transaction
The current configuration of the staking pool with ID poolID
can be viewed by calling Pools(poolID)
. The return value is
a struct of this form:
struct StakingPool {
address administrator;
uint256 tokenType;
address tokenAddress;
uint256 tokenID;
bool transferable;
uint256 lockupSeconds;
uint256 cooldownSeconds;
}
Administrators should be able to change the value of the following parameters:
transferable
lockupSeconds
cooldownSeconds
This should be possible using the following method:
function updatePoolConfiguration(
uint256 poolID,
bool changeTransferability,
bool transferable,
bool changeLockup,
uint256 lockupSeconds,
bool changeCooldown,
uint256 cooldownSeconds
) external;
Successful configuration changes should emit an event with the following signature:
event StakingPoolConfigured(
uint256 indexed poolID,
address indexed administrator,
bool transferable,
uint256 lockupSeconds,
uint256 cooldownSeconds
);
STAKER-16
: A non-administrator (of any pool) should not be able to change any of the parameters of a staking pool
Messages from a non-administrator to make such a change should revert with the following error:
error NonAdministrator();
STAKER-17
: A non-administrator (of any pool) should not be able to change any of the parameters of a staking pool, even if they are administrators of a different pool
Messages from a non-administrator to make such a change should revert with the following error:
error NonAdministrator();
STAKER-18
: An administrator of a staking pool should be able to transfer administration of that pool to another account
This should emit a StakingPoolConfigured
event, which has the following signature:
event StakingPoolConfigured(
uint256 indexed poolID,
address indexed administrator,
bool transferable,
uint256 lockupSeconds,
uint256 cooldownSeconds
);
The new administrator must be able to configure the pool.
The old administrator should no longer be able to configure the pool. After they have transferred ownership, any attempt they make to configure the pool should raise an error with signature:
error NonAdministrator();
STAKER-138
: A non-administrator (of any pool) should not be able to transfer administration of that pool to another account
Any attempt should revert with
error NonAdministrator();
STAKER-139
: A non-administrator of a staking pool should not be able to transfer administration of that pool to another account, even if they are an administrator of another pool
Any attempt should revert with
error NonAdministrator();
STAKER-19
: A holder should be able to stake any number of native tokens into a native token staking position.
The amount of native token staked should be transferred from the holder's account to the Staker
contract.
This should emit a Staked
event:
event Staked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
It should also emit an ERC721 Transfer
event representing the staking position token being minted to the holder.
STAKER-20
: A holder should be able to stake any number of ERC20 tokens into an ERC20 staking position.
The amount of ERC20 token staked should be transferred from the holder's account to the Staker
contract.
This should emit a Staked
event:
event Staked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
It should also emit an ERC721 Transfer
event representing the staking position token being minted to the holder.
The ERC721 token staked should be transferred from the holder's account to the Staker
contract.
This should emit a Staked
event:
event Staked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
It should also emit an ERC721 Transfer
event representing the staking position token being minted to the holder.
STAKER-22
: A holder should be able to stake any number of ERC1155 tokens into an ERC1155 staking position.
The amount of ERC1155 token staked should be transferred from the holder's account to the Staker
contract.
This should emit a Staked
event:
event Staked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
It should also emit an ERC721 Transfer
event representing the staking position token being minted to the holder.
If a staking pool is marked as transferable, the ERC721 tokens representing staking positions in that pool should be transferable.
If a staking pool is marked as non-transferable, the ERC721 tokens representing staking positions in that pool should not be transferable.
Any attempt to transfer such a token should fail with the following error:
error PositionNotTransferable(uint256 positionTokenID);
STAKER-25
: If a native token staking pool does not have a cooldown, the user who staked into that position should be able to unstake after the lockup period assuming they still hold the position token
Unstaking should transfer the position's amount worth of native tokens from the Staker
contract back to the holder.
The staking position ERC721 token should be burned in the process, emitting the appropriate ERC721 transfer event.
The unstake operation should emit the Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
STAKER-26
: If an ERC20 staking pool does not have a cooldown, the user who staked into that position should be able to unstake after the lockup period assuming they still hold the position token
Unstaking should transfer the position's amount worth of ERC20 tokens from the Staker
contract back to the holder.
The staking position ERC721 token should be burned in the process, emitting the appropriate ERC721 transfer event.
The unstake operation should emit the Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
STAKER-27
: If an ERC721 staking pool does not have a cooldown, the user who staked into that position should be able to unstake after the lockup period assuming they still hold the position token
Unstaking should transfer the position's amount worth of ERC721 tokens from the Staker
contract back to the holder.
The staking position ERC721 token should be burned in the process, emitting the appropriate ERC721 transfer event.
The unstake operation should emit the Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
STAKER-28
: If an ERC1155 staking pool does not have a cooldown, the user who staked into that position should be able to unstake after the lockup period assuming they still hold the position token
Unstaking should transfer the position's amount worth of ERC1155 tokens from the Staker
contract back to the holder.
The staking position ERC721 token should be burned in the process, emitting the appropriate ERC721 transfer event.
The unstake operation should emit the Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
STAKER-29
: If a native token staking pool does not have a cooldown, a user who holds the position token but who isn't the original holder should be able to unstake after the lockup period
Unstaking should transfer the position's amount worth of native tokens from the Staker
contract back to the holder.
The staking position ERC721 token should be burned in the process, emitting the appropriate ERC721 transfer event.
The unstake operation should emit the Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
STAKER-30
: If an ERC20 staking pool does not have a cooldown, a user who holds the position token but who isn't the original holder should be able to unstake after the lockup period
Unstaking should transfer the position's amount worth of ERC20 tokens from the Staker
contract back to the holder.
The staking position ERC721 token should be burned in the process, emitting the appropriate ERC721 transfer event.
The unstake operation should emit the Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
STAKER-31
: If an ERC721 staking pool does not have a cooldown, a user who holds the position token but who isn't the original holder should be able to unstake after the lockup period
Unstaking should transfer the position's amount worth of ERC721 tokens from the Staker
contract back to the holder.
The staking position ERC721 token should be burned in the process, emitting the appropriate ERC721 transfer event.
The unstake operation should emit the Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
STAKER-32
: If an ERC1155 staking pool does not have a cooldown, a user who holds the position token but who isn't the original holder should be able to unstake after the lockup period
Unstaking should transfer the position's amount worth of ERC1155 tokens from the Staker
contract back to the holder.
The staking position ERC721 token should be burned in the process, emitting the appropriate ERC721 transfer event.
The unstake operation should emit the Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
STAKER-33
: If a native token staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool even after the lockup period
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-34
: If an ERC20 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool even after the lockup period
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-35
: If an ERC721 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool even after the lockup period
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-36
: If an ERC1155 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool even after the lockup period
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-37
: If a native token staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool even after the lockup period, even if they were the original holder
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-38
: If an ERC20 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool even after the lockup period, even if they were the original holder
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-39
: If an ERC721 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool even after the lockup period, even if they were the original holder
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-40
: If an ERC1155 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool even after the lockup period, even if they were the original holder
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-49
: If a native token staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool before the lockup period expires
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-50
: If an ERC20 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool before the lockup period expires
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-51
: If an ERC721 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool before the lockup period expires
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-52
: If an ERC1155 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool before the lockup period expires
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-53
: If a native token staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool before the lockup period expires, even if they were the original holder
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-54
: If an ERC20 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool before the lockup period expires, even if they were the original holder
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-55
: If an ERC721 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool before the lockup period, even if they were the original holder
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-56
: If an ERC1155 staking pool does not have a cooldown, a user who doesn't hold the position token should not be able to unstake a position in that staking pool before the lockup period, even if they were the original holder
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-57
: If a native token staking pool does not have a cooldown, a user who holds the position token should not be able to unstake a position in that staking pool before the lockup period expires
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-58
: If an ERC20 staking pool does not have a cooldown, a user who holds the position token should not be able to unstake a position in that staking pool before the lockup period expires
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-59
: If an ERC721 staking pool does not have a cooldown, a user who holds the position token should not be able to unstake a position in that staking pool before the lockup period
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-60
: If an ERC1155 staking pool does not have a cooldown, a user who holds the position token should not be able to unstake a position in that staking pool before the lockup period
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-41
: If a native token staking pool has a cooldown, a position holder who did create the position and who has not initiated an unstake should not be able to unstake their position even after the lockup period
Any attempt to do so should result in the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-42
: If an ERC20 staking pool has a cooldown, a position holder who did create the position and who has not initiated an unstake should not be able to unstake their position even after the lockup period
Any attempt to do so should result in the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-43
: If an ERC721 staking pool has a cooldown, a position holder who did create the position and who has not initiated an unstake should not be able to unstake their position even after the lockup period
Any attempt to do so should result in the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-44
: If an ERC1155 staking pool has a cooldown, a position holder who did create the position and who has not initiated an unstake should not be able to unstake their position even after the lockup period
Any attempt to do so should result in the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-45
: If a native token staking pool has a cooldown, a position holder who didn't create the position and who has not initiated an unstake should not be able to unstake their position even after the lockup period
Any attempt to do so should result in the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-46
: If an ERC20 staking pool has a cooldown, a position holder who didn't create the position and who has not initiated an unstake should not be able to unstake their position even after the lockup period
Any attempt to do so should result in the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-47
: If an ERC721 staking pool has a cooldown, a position holder who didn't create the position and who has not initiated an unstake should not be able to unstake their position even after the lockup period
Any attempt to do so should result in the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-48
: If an ERC1155 staking pool has a cooldown, a position holder who didn't create the position and who has not initiated an unstake should not be able to unstake their position even after the lockup period
Any attempt to do so should result in the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-61
: If a native token staking pool has a cooldown, a position holder who didn't create the position should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error LockupNotExpired(uint256 expiresAt);
STAKER-62
: If an ERC20 staking pool has a cooldown, a position holder who didn't create the position should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error LockupNotExpired(uint256 expiresAt);
STAKER-63
: If an ERC721 staking pool has a cooldown, a position holder who didn't create the position should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error LockupNotExpired(uint256 expiresAt);
STAKER-64
: If an ERC1155 staking pool has a cooldown, a position holder who didn't create the position should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error LockupNotExpired(uint256 expiresAt);
STAKER-65
: If a native token staking pool has a cooldown, a position holder who did create the position should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error LockupNotExpired(uint256 expiresAt);
STAKER-66
: If an ERC20 staking pool has a cooldown, a position holder who did create the position should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error LockupNotExpired(uint256 expiresAt);
STAKER-67
: If an ERC721 staking pool has a cooldown, a position holder who did create the position should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error LockupNotExpired(uint256 expiresAt);
STAKER-68
: If an ERC1155 staking pool has a cooldown, a position holder who did create the position should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error LockupNotExpired(uint256 expiresAt);
STAKER-69
: If a native token staking pool has a cooldown, a position non-holder should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-70
: If an ERC20 staking pool has a cooldown, a position non-holder should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-71
: If an ERC721 staking pool has a cooldown, a position non-holder should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-72
: If an ERC1155 staking pool has a cooldown, a position non-holder should not be able to initiate an unstake before the lockup period has expired
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-73
: If a native token staking pool has a cooldown, a position non-holder should not be able to initiate an unstake after the lockup period has expired
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-74
: If an ERC20 staking pool has a cooldown, a position non-holder should not be able to initiate an unstake after the lockup period has expired
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-75
: If an ERC721 staking pool has a cooldown, a position non-holder should not be able to initiate an unstake after the lockup period has expired
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-76
: If an ERC1155 staking pool has a cooldown, a position non-holder should not be able to initiate an unstake after the lockup period has expired
Any attempt to do so should result in the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-77
: If a native token staking pool has a cooldown, a position holder should be able to initiate an unstake after the lockup period has expired
The position's unstakeInitiatedAt
member should reflect the block timestamp of when the unstake was initiated:
struct Position {
uint256 poolID;
uint256 amountOrTokenID;
uint256 stakeTimestamp;
uint256 unstakeInitiatedAt;
}
The transaction should emit an UnstakeInitiated
event:
event UnstakeInitiated(uint256 positionTokenID, address indexed owner);
STAKER-78
: If an ERC20 staking pool has a cooldown, a position holder should be able to initiate an unstake after the lockup period has expired
The position's unstakeInitiatedAt
member should reflect the block timestamp of when the unstake was initiated:
struct Position {
uint256 poolID;
uint256 amountOrTokenID;
uint256 stakeTimestamp;
uint256 unstakeInitiatedAt;
}
The transaction should emit an UnstakeInitiated
event:
event UnstakeInitiated(uint256 positionTokenID, address indexed owner);
STAKER-79
: If an ERC721 staking pool has a cooldown, a position holder should be able to initiate an unstake after the lockup period has expired
The position's unstakeInitiatedAt
member should reflect the block timestamp of when the unstake was initiated:
struct Position {
uint256 poolID;
uint256 amountOrTokenID;
uint256 stakeTimestamp;
uint256 unstakeInitiatedAt;
}
The transaction should emit an UnstakeInitiated
event:
event UnstakeInitiated(uint256 positionTokenID, address indexed owner);
STAKER-80
: If an ERC1155 staking pool has a cooldown, a position holder should be able to initiate an unstake after the lockup period has expired
The position's unstakeInitiatedAt
member should reflect the block timestamp of when the unstake was initiated:
struct Position {
uint256 poolID;
uint256 amountOrTokenID;
uint256 stakeTimestamp;
uint256 unstakeInitiatedAt;
}
The transaction should emit an UnstakeInitiated
event:
event UnstakeInitiated(uint256 positionTokenID, address indexed owner);
STAKER-81
: If a native token staking pool has a cooldown, if a position holder has successfully initiated an unstake but not completed that unstake, any further initiations of the unstake will be idempotent
This means that the unstakeInitiatedAt
member of the position will not change, and will reflect the block
timestamp of the original initiateUnstake
transaction. No UnstakeInitiated
event will be emitted.
STAKER-82
: If an ERC20 staking pool has a cooldown, if a position holder has successfully initiated an unstake but not completed that unstake, any further initiations of the unstake will be idempotent
This means that the unstakeInitiatedAt
member of the position will not change, and will reflect the block
timestamp of the original initiateUnstake
transaction. No UnstakeInitiated
event will be emitted.
STAKER-83
: If an ERC721 staking pool has a cooldown, if a position holder has successfully initiated an unstake but not completed that unstake, any further initiations of the unstake will be idempotent
This means that the unstakeInitiatedAt
member of the position will not change, and will reflect the block
timestamp of the original initiateUnstake
transaction. No UnstakeInitiated
event will be emitted.
STAKER-84
: If an ERC1155 staking pool has a cooldown, if a position holder has successfully initiated an unstake but not completed that unstake, any further initiations of the unstake will be idempotent
This means that the unstakeInitiatedAt
member of the position will not change, and will reflect the block
timestamp of the original initiateUnstake
transaction. No UnstakeInitiated
event will be emitted.
STAKER-85
: If a native token staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then the position holder cannot complete the unstake
Any attempt to do so should raise the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-86
: If an ERC20 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then the position holder cannot complete the unstake
Any attempt to do so should raise the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-87
: If an ERC721 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then the position holder cannot complete the unstake
Any attempt to do so should raise the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-88
: If an ERC1155 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then the position holder cannot complete the unstake
Any attempt to do so should raise the following error:
error InitiateUnstakeFirst(uint256 cooldownSeconds);
STAKER-89
: If a native token staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then a position non-holder cannot complete the unstake
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-90
: If an ERC20 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then a position non-holder cannot complete the unstake
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-91
: If an ERC721 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then a position non-holder cannot complete the unstake
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-92
: If an ERC1155 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then a position non-holder cannot complete the unstake
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-93
: If a native token staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then a position non-holder cannot complete the unstake, even if they were the original creator of the position
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-94
: If an ERC20 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then a position non-holder cannot complete the unstake, even if they were the original creator of the position
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-95
: If an ERC721 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then a position non-holder cannot complete the unstake, even if they were the original creator of the position
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-96
: If an ERC1155 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has not expired, then a position non-holder cannot complete the unstake, even if they were the original creator of the position
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-97
: If a native token staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then the position holder can unstake and the position token is burned when the staking position is transferable
The amount of native token staked into the position should be transferred from the Staker
contract to
the position holder.
The position token should be burned.
The transaction shoul emit an Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
The transaction should emit an ERC721 Transfer
event signifying that the poition token was burned.
STAKER-98
: If an ERC20 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then the position holder can unstake and the position token is burned when the staking position is transferable
The amount of ERC20 tokens staked into the position should be transferred from the Staker
contract to
the position holder.
The position token should be burned.
The transaction shoul emit an Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
The transaction should emit an ERC721 Transfer
event signifying that the poition token was burned.
STAKER-99
: If an ERC721 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then the position holder can unstake and the position token is burned when the staking position is transferable
The ERC721 token staked into the position should be transferred from the Staker
contract to
the position holder.
The position token should be burned.
The transaction shoul emit an Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
The transaction should emit an ERC721 Transfer
event signifying that the poition token was burned.
STAKER-100
: If an ERC1155 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then the position holder can unstake and the position token is burned when the staking position is transferable
The amount of ERC1155 tokens staked into the position should be transferred from the Staker
contract to
the position holder.
The position token should be burned.
The transaction shoul emit an Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
The transaction should emit an ERC721 Transfer
event signifying that the poition token was burned.
STAKER-101
: If a native token staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then the position holder can unstake and the position token is burned when the staking position is non-transferable
The amount of native token staked into the position should be transferred from the Staker
contract to
the position holder.
The position token should be burned.
The transaction shoul emit an Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
The transaction should emit an ERC721 Transfer
event signifying that the poition token was burned.
STAKER-102
: If an ERC20 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then the position holder can unstake and the position token is burned when the staking position is non-transferable
The amount of ERC20 tokens staked into the position should be transferred from the Staker
contract to
the position holder.
The position token should be burned.
The transaction shoul emit an Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
The transaction should emit an ERC721 Transfer
event signifying that the poition token was burned.
STAKER-103
: If an ERC721 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then the position holder can unstake and the position token is burned when the staking position is non-transferable
The ERC721 token staked into the position should be transferred from the Staker
contract to
the position holder.
The position token should be burned.
The transaction shoul emit an Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
The transaction should emit an ERC721 Transfer
event signifying that the poition token was burned.
STAKER-104
: If an ERC1155 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then the position holder can unstake and the position token is burned when the staking position is non-transferable
The amount of ERC1155 tokens staked into the position should be transferred from the Staker
contract to
the position holder.
The position token should be burned.
The transaction shoul emit an Unstaked
event:
event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID);
The transaction should emit an ERC721 Transfer
event signifying that the poition token was burned.
STAKER-105
: If a native token staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then a position non-holder cannot complete the unstake
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-106
: If an ERC20 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then a position non-holder cannot complete the unstake
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-107
: If an ERC721 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then a position non-holder cannot complete the unstake
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-108
: If an ERC1155 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then a position non-holder cannot complete the unstake
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-109
: If a native token staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then a position non-holder cannot complete the unstake, even if they were the original creator of the position
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-110
: If an ERC20 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then a position non-holder cannot complete the unstake, even if they were the original creator of the position
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-111
: If an ERC721 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then a position non-holder cannot complete the unstake, even if they were the original creator of the position
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-112
: If an ERC1155 staking pool has a cooldown, if a position holder has successfully initiated an unstake, and if the cooldown period has expired, then a position non-holder cannot complete the unstake, even if they were the original creator of the position
Any attempt to do so should raise the following error:
error UnauthorizedForPosition(address owner, address sender);
STAKER-113
: The ERC721 representing an ERC721 staking position have as its metadata URI a data URI representing an appropriate JSON object
The metadata should indicate:
- The pool ID under which the position was opened
- The token ID of the ERC721 token staked into the position
- The time at which the positon was opened
- The time at which the lockup on the position expires
STAKER-114
: The ERC721 representing a non-ERC721 staking position have as its metadata URI a data URI representing an appropriate JSON object
The metadata should indicate:
- The pool ID under which the position was opened
- The amount of tokens
- The time at which the positon was opened
- The time at which the lockup on the position expires
STAKER-115
: CurrentAmountInPool
and CurrentPositionsInPool
should accurate reflect the amount of tokens and number of positions currently open under a native token staking pool
These functions are called via CurrentAmountInPool(poolID)
and CurrentPositionsInPool(poolID)
.
STAKER-116
: CurrentAmountInPool
and CurrentPositionsInPool
should accurate reflect the amount of tokens and number of positions currently open under an ERC20 staking pool
These functions are called via CurrentAmountInPool(poolID)
and CurrentPositionsInPool(poolID)
.
STAKER-117
: CurrentAmountInPool
and CurrentPositionsInPool
should accurate reflect the amount of tokens and number of positions currently open under an ERC721 staking pool
These functions are called via CurrentAmountInPool(poolID)
and CurrentPositionsInPool(poolID)
.
STAKER-118
: CurrentAmountInPool
and CurrentPositionsInPool
should accurately reflect the amount of tokens and number of positions currently open under an ERC1155 staking pool
These functions are called via CurrentAmountInPool(poolID)
and CurrentPositionsInPool(poolID)
.
STAKER-119
: CurrentAmountInPool
and CurrentPositionsInPool
should not be affected by positions opened under other pools
This should be true for all pairs of possible pools.
It can be tested with a single pair of pools.
STAKER-120
: For pools without cooldowns, changes to the lockupSeconds
setting apply to all unstaked users
This tests that when an administrator changes a configuration on a staking pool, the change applies to all open positions immediately.
STAKER-121
: For pools with cooldowns, for users who have not yet initiated a cooldown, changes to the lockupSeconds
setting apply to determine when it is possible for them to initiateUnstake
This tests that when an administrator changes a configuration on a staking pool, the change applies to all open positions immediately.
STAKER-122
: For pools with cooldowns, for users who have initiated a cooldown already, changes to the cooldownSeconds
setting apply to their final unstake
This tests that when an administrator changes a configuration on a staking pool, the change applies to all open positions immediately.
STAKER-123
: If an administrator changes transferable
from true
to false
, position tokens are no longer transferable even if they were transferable, and were transferred! before
This tests that when an administrator changes a configuration on a staking pool, the change applies to all open positions immediately.
STAKER-124
: If an administrator changes transferable
from true
to false
, position tokens that were not transferable before become transferable if so configured
This tests that when an administrator changes a configuration on a staking pool, the change applies to all open positions immediately.
Because Staker
positions are ERC721 tokens, as long as the pool under which a position has been opened is transferable,
the position can be staked back into the contract.
If a pool has a tokenType
which doesn't match the stake*
method that a user is calling, the contract
should revert with:
error IncorrectTokenType(uint256 poolID, uint256 poolTokenType, uint256 tokenTypeArg);
Otherwise, their transaction should revert with:
error NothingToStake();
Otherwise, their transaction should revert with:
error NothingToStake();
Otherwise, their transaction should revert with:
error NothingToStake();
With an ERC721NonExistentToken
error:
error ERC721NonexistentToken(uint256 tokenId);
STAKER-131
: If a user who holds a position in a pool with cooldownSeconds = 0
calls initiateUnstake
after the lockup period has expired, the unstakeInitiatedAt
parameter of the position is updated
Even though it is not necessary for the user to initiate the unstake for a position in a pool with no cooldown, the behavior of the initiateUnstake
function does not change.
STAKER-132
: If a user who holds a position in a pool with cooldownSeconds = 0
calls initiateUnstake
before the lockup period has expired, the transaction reverts
With the following error:
error LockupNotExpired(uint256 expiresAt);
Even though it is not necessary for the user to initiate the unstake for a position in a pool with no cooldown, the behavior of the initiateUnstake
function does not change.
STAKER-133
: It should not be possible to re-enter the Staker
(on the stake*
or unstake
methods) when staking into a native pool
Any attempt to reenter should result in the following error:
error ReentrancyGuardReentrantCall();
STAKER-134
: It should not be possible to re-enter the Staker
(on the stake*
or unstake
methods) when staking into a native pool
Any attempt to reenter should result in the following error:
error ReentrancyGuardReentrantCall();
STAKER-135
: It should not be possible to re-enter the Staker
(on the stake*
or unstake
methods) when staking into a native pool
Any attempt to reenter should result in the following error:
error ReentrancyGuardReentrantCall();
STAKER-136
: It should not be possible to re-enter the Staker
(on the stake*
or unstake
methods) when staking into a native pool
Any attempt to reenter should result in the following error:
error ReentrancyGuardReentrantCall();
STAKER-137
: It should not be possible to re-enter the Staker
(on the stake*
or unstake
methods) when unstaking a position
Any attempt to reenter should result in the following error:
error ReentrancyGuardReentrantCall();
Label the new flows using the syntax TAG-modifier
with STAKER
as the TAG
and *
as the modifier.
Then run graffiti
on this file using:
graffiti number -i web3/flows/staker.md -o web3/flows/staker.md -t STAKER
This will automatically number the new flows while preserving the numbering of the existing flows.