--- tags: WPOKT, proposal title: ⚔️ WPOKT UX/UI Smart Contract Scoping Document ⚔️ --- # WPOKT UX/UI Smart Contract Scoping Document ## Overview The Pocket Foundation needs a capable ERC20 in order to bridge their native POKT token to EVM compatible chains. ## Tech Stack - Foundry - OpenZeppelin SC Library - wPOKT - ERC20 - IERC20 - ERC20Permit - AccessControl - Minter Contract - Ownable - IwPOKT Interface ### wPOKT Core Functions (18 hours) - AccessControl Wallets: - DEFAULT_ADMIN_ROLE: granted to a Safe multisig controlled by POKT Foundation + POKT community members - MINTER_ROLE: granted to Minter contract which is owned by the Copper sharded wallet - PAUSER_ROLE: granted to POKT Foundation member - Custom AccessControl Functions: - `mint(address user, uint256 amount, uint256 nonce) external onlyRole(MINTER_ROLE)` only callable by MINTER_ROLE contract. Increments `mapping(address => uint256) private _userNonces;` and enforces `require(nonce == _userNonces[user]++)` - `_userNonces[user] = nonce++;` prevents accidental double minting from the backend by preventing any duplicate data from successfully minting. Checks `feeFlag` and if `feeFlag == true` mints a portion of the new tokens to the `feeCollector` address. Reverts if `mintPaused == true` - `batchMint(address[] users, uint256[] amounts, uint256[] nonces) external onlyRole(MINTER_ROLE)` calls the `mint` function in a loop - `changeFee(uint256 newFeePoints, address feeCollector) external onlyRole(DEFAULT_ADMIN_ROLE)` only callable by DEFAULT_ADMIN_ROLE and is bounded by `MAX_FEE` `if (newFeePoints > 0)` `feeFlag = true;` `if (newFeePoints == 0)` - `feeFlag = false;` - `pauseMint(bool status) external onlyRole(PAUSER_ROLE)` only callable by PAUSER_ROLE wallets. Sets the `mintPaused = status;` flag to block or allow minting - `setMintCooldown(uint256 newLimit, uint256 newLimitIncreasePerSecond) external onlyRole(DEFAULT_ADMIN_ROLE` only callable by the DEFAULT_ADMIN_ROLE. Sets `newLimit` which is the maximum number of tokens that can be minted after complete cooldown. Sets `newLimitIncreasePerSecond` which is the rate that new tokens can be minted per second. We changed from the LIDO implementation because it assumes that it's contract is deployed to Ethereum mainnet - block times can vary widely crosschain so we should be using `block.timestamp` rather than the `block.number` - Custom Mutative Public functions: - `burn(uint256 amount, address receiver)` emits receiver address log data for consumption at the Copper backend - Custom View Functions: - `calculateFee(uint256 amount) public view returns (uint256 fee)` uses `BASIS_POINTS` and `feePoints` by `fee = (amount * feePoints) / BASIS_POINTS`. Requires that `amount % BASIS_POINTS == 0` to prevent rounding errors and "dust" accumulation - `getCurrentLimit() public view returns (uint256 limit)` derives the current mintable token limit at the current timestamp ### Minter Contract (6 hours) - Sets `IwPKT immutable wPKT;` interface in constructor. - Custom onlyOwner functions: - `callMint(address user, uint256 amount, uint256 nonce) public onlyOwner` and simply passes the data into the wPKT token's mint function `require(wPKT.mint(user, amount, nonce);` - `batchMint(address[] users, uint256[] amounts, uint256[] nonces) external onlyOwner` requires that the length of all arrays match then makes call to wPKT token's mint function in a loop ### Audit Readiness (26 hours) - Foundry test coverage > 90% - Deployment script - Fuzz testing - Invariant testing - Full Audit Readiness - Testnet deployment