diff --git a/.gitmodules b/.gitmodules index a200560..f3336b0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,6 @@ [submodule "packages/contracts/lib/openzeppelin-contracts-v4"] path = packages/contracts/lib/openzeppelin-contracts-v4 url = https://github.com/OpenZeppelin/openzeppelin-contracts - [submodule "packages/contracts/lib/superfluid-protocol-monorepo"] path = packages/contracts/lib/superfluid-protocol-monorepo url = https://github.com/superfluid-finance/protocol-monorepo @@ -17,3 +16,16 @@ [submodule "packages/contracts/lib/openzeppelin-contracts-upgradeable"] path = packages/contracts/lib/openzeppelin-contracts-upgradeable url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable +[submodule "packages/contracts/lib/swap-router-contracts"] + path = packages/contracts/lib/swap-router-contracts + url = https://github.com/Uniswap/swap-router-contracts +[submodule "packages/contracts/lib/uniswap-v3-periphery"] + path = packages/contracts/lib/uniswap-v3-periphery + url = https://github.com/Uniswap/v3-periphery +[submodule "lib/uniswap-v3-periphery"] + branch = 0.8 +[submodule "packages/contracts/lib/uniswap-v3-core"] + path = packages/contracts/lib/uniswap-v3-core + url = https://github.com/Uniswap/v3-core +[submodule "lib/uniswap-v3-core"] + branch = 0.8 diff --git a/audit/2025.07.06 - Final - Superfluid Public Best Efforts Audit Contest Report.pdf b/audit/2025.07.06 - Final - Superfluid Public Best Efforts Audit Contest Report.pdf new file mode 100644 index 0000000..9de1d01 Binary files /dev/null and b/audit/2025.07.06 - Final - Superfluid Public Best Efforts Audit Contest Report.pdf differ diff --git a/docs/OPERATIONAL_GUIDELINES.md b/docs/OPERATIONAL_GUIDELINES.md new file mode 100644 index 0000000..c148e3d --- /dev/null +++ b/docs/OPERATIONAL_GUIDELINES.md @@ -0,0 +1,151 @@ +# SPR SUP Locker System - Operational Guidelines + +## Overview + +This document provides operational guidelines for governance and system administrators of the SPR SUP Locker System. It focuses on the core operational processes for managing ecosystem partner programs, funding campaigns, and maintaining system parameters. + +## System Governance Structure + +### Contract Ownership + +| Contract | Owner | Purpose | +| ----------------------- | ------------------- | -------------------------------------- | +| FluidLockerFactory | Governance Multisig | Locker creation and factory management | +| StakingRewardController | Governance Multisig | Staking rewards and tax distribution | +| FluidEPProgramManager | Governance Multisig | Ecosystem partner programs | +| SupVestingFactory | Governance Multisig | SUP token vesting management | + +### Governance Process + +- **Program Creation**: Requires governance vote and approval +- **Funding Allocation**: Governance determines funding amounts +- **Parameter Updates**: Governance approval for critical parameters + +## Program Management Operations + +### 1. Creating New Programs + +#### Program Creation & Funding Procedure + +**Required Parameters:** + +- Program ID: Unique identifier assigned by governance +- Program Admin: Authorized to modify Stack signer & attribute GDA pool units +- Stack Signer: Address authorized to sign reward claims +- Pool Name: Descriptive name for the program +- Pool Symbol: Descriptive symbol for the program +- Funding Amount: Governance-approved SUP allocation +- Duration: Program duration in seconds (typically 90 days) + +#### Program Creation & Funding Pre-requisites + +- [ ] Governance proposal approved +- [ ] Funding amount defined by governance +- [ ] Duration defined (typically 90 days) + +#### Program Creation & Funding Checklist + +- [ ] Create Stack Program +- [ ] Execute transaction `FluidEPProgramManager::createProgram` +- [ ] Bootstrap GDA Pool units for the created program + - [ ] Allocate 1 Stack point unit to the Foundation Locker + - [ ] Claim units for the created program on behalf of the Foundation Locker +- [ ] Execute transaction `MacroForwarder::runMacro` + - Params: `FluidEPProgramManager.paramsGivePermission` +- [ ] Execute transaction `FluidEPProgramManager::startFunding` + +### 2. Stopping Program Funding (Nominal Scenarios) + +#### When to Stop Funding + +- **Program Completion**: Starting from 4 days before the set duration + +#### Normal Stop Procedure + +**Important Consideration:** + +Anyone can stop the funding flow to the program pool once the program completion date is reached. + +**Stop Program Actions:** + +- Stop the funding flow to the program pool +- Calculate compensation for remaining duration + +#### Stop Program Checklist + +- [ ] Execute transaction `FluidEPProgramManager::stopFunding` + +### 4. Canceling Campaign Funding (Degraded Scenarios) + +#### When to Cancel Funding + +- **Security Issues**: Suspected vulnerability or attack +- **Program Malfunction**: Technical issues affecting users +- **Compliance Issues**: Regulatory or legal concerns +- **Emergency Situations**: Critical system issues +- **Program Setting Mistake**: Program was created with incorrect parameters + +#### Emergency Cancel Procedure + +**Emergency Cancel Actions:** + +- Immediately stop the given program funding +- Return remaining funds to treasury + +#### Emergency Cancel Checklist + +- [ ] Governance approval for emergency cancellation +- [ ] Execute transaction `FluidEPProgramManager::cancelFunding` + +## Parameter Management + +### 1. Setting Locker Factory Fee + +#### Fee Setting Process + +**Governance Approval Required:** + +- Fee changes require governance vote +- No minimum fee applies + +#### Fee Update Procedure + +**Fee Update Steps:** + +1. Submit governance proposal +2. Allow community discussion period +3. Execute governance vote +4. Update fee parameter + +#### Fee Update Checklist + +- [ ] Governance vote completed +- [ ] Execute transaction `FluidLockerFactory::setLockerCreationFee` + +### 2. Setting Tax Allocation Split + +#### Tax Allocation Overview + +The tax allocation determines how penalty fees from token unlocks are distributed: + +- **Staker Allocation**: Percentage of penalties distributed to SUP token stakers +- **LP Allocation**: Percentage of penalties distributed to liquidity providers +- **Total**: Must equal 100% (10,000 basis points) + +#### Allocation Update Procedure + +**Allocation Update Steps:** + +1. Submit allocation change proposal +2. Allow community discussion period +3. Execute governance vote +4. Update allocation parameters + +#### Allocation Update Checklist + +- [ ] Governance vote completed +- [ ] Execute transaction `StakingRewardController::setTaxAllocation` + +--- + +_These operational guidelines provide a structured approach to managing the SPR SUP Locker System with governance-driven decision making and clear procedures for all critical operations._ diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md new file mode 100644 index 0000000..fe8ab41 --- /dev/null +++ b/docs/USER_GUIDE.md @@ -0,0 +1,208 @@ +# SPR SUP Reserve System - User Guide + +## Overview + +This document provides a technical overview of the Reserve mechanism. + +## Definitions + +- [SUP Token](https://forum.superfluid.org/t/superfluid-dao-governance-and-tokenomics/69) +- [SPR](https://forum.superfluid.org/t/superfluid-dao-governance-and-tokenomics/69) +- [Reserves](https://forum.superfluid.org/t/superfluid-dao-governance-and-tokenomics/69) +- [Community Charge](https://forum.superfluid.org/t/superfluid-dao-governance-and-tokenomics/69) + +## System Architecture + +The SPR SUP Reserve System consists of several key components: + +### Core Contracts + +1. **FluidLockerFactory** - Creates individual reserve contracts for users +2. **FluidLocker** - Personal reserve where users store and manage their SUP tokens +3. **StakingRewardController** - Manages staking rewards and Community Charge distribution +4. **FluidEPProgramManager** - Administers ecosystem partner reward programs +5. **Fontaine** - Handles gradual token withdrawal through streaming + +### Key Features + +- **Reward Programs**: Participate in ecosystem partner programs +- **Liquidity Provision**: Provide liquidity to earn rewards & trading fees +- **Staking**: Earn rewards by staking SUP tokens +- **Streaming**: Withdraw tokens over time with reduced community charge +- **Draining**: Withdraw tokens instantly with high community charge +- **Token Locking**: Get yield from your SUP tokens + +## Getting Started + +### Step 1: Create Your Reserve + +Before you can use the SPR SUP Reserve System, you need to create your personal reserve. + +**Cost**: A small fee is required to create a reserve (set by governance) + +**Result**: You get a unique reserve contract address that only you can control + +### Step 2: Participate in Reward Programs + +You can participate in reward programs to earn SUP tokens. Use the ecosystem partner apps and claim your SUP flow rate daily. + +### Step 3: Lock Your SUP Tokens (optional) + +Once you have a reserve, you can lock additional SUP tokens to earn additional rewards + +**Benefits of Locking**: + +- You can stake them to earn rewards +- You can provide liquidity + +## Core Functions + +### Reward Programs + +The system supports ecosystem partner programs where you can earn SUP tokens. +You can participate in the currently live campaigns on [Superfluid Claim App](https://claim.superfluid.org). +As your participation in the campaigns increases, you are entitled to claim a higher SUP flow rate by claiming it daily. + +### Withdrawing SUP Tokens from the Reserve + +You can withdraw your SUP tokens in two ways: + +#### 1. Drain (High Community Charge) + +You can withdraw your SUP tokens instantly. Chosing this option will allow you to get your SUP tokens instantly to your wallet, however you will have to pay a high community charge. + +**Community Charge**: 80% of the withdrawn amount goes to stakers and liquidity providers + +#### 2. Stream (No Community Charge) + +You can withdraw your SUP tokens gradually. Chosing this option will allow you to get your SUP tokens streamed to your wallet over 12 months. + +### Staking + +Staking allows you to earn rewards from the community charges collected when other users withdraw their tokens. + +#### How to Stake + +**Requirements**: + +- You must have available SUP tokens in your Reserve + +**Note**: After staking, there's a 30-days Minimum Staking Period before you can unstake +**Note**: The 30-days Minimum Staking Period is reset at every staking event +**Note**: As staked SUP remain in your Reserve, delegation power is unchanged + +#### How to Unstake + +**Requirements**: + +- 30-day cooldown period must have elapsed + +#### How to Claim Staking Rewards + +Staking rewards are accrued directly to your Reserve. You do not have to claim them, however, you may have to stake them to increase your share of the rewards. + +### Liquidity Provision + +You can provide liquidity to the ETH/SUP Uniswap V3 pool to earn trading fees and a share of the community charge collected when other users withdraw their tokens. + +#### How to Provide Liquidity + +You can provide liquidity by sending ETH to your Reserve and calling the provide liquidity function. +Every time you provide liquidity a new Uniswap V3 position is created. The corresponding NFT is stored in your Reserve. + +**Requirements**: + +- Send the required ETH amount along with the transaction +- Have enough SUP tokens in your Reserve + +**Note**: After providing liquidity, there's a 7-day cooldown before you can withdraw your liquidity +**Note**: The 7-days cooldown is position specific (i.e. different positions may have different cooldown end dates) + +#### How to Collect Fees + +You can collect fees from your liquidity positions at any time. The fees generated from your liquidity position are instantly transferred to your wallet. + +#### How to Withdraw Liquidity + +You can withdraw your Reserve's Uniswap V3 position either partially or fully. + +**Requirements**: + +- 7-day cooldown period must have elapsed + +##### Community Charge-Free Withdrawals (Liquidity Provision) + +After providing liquidity for 180 days, you can withdraw your position and get both your SUP and ETH tokens directly to your wallet without paying the Reserve Community Charge. + +###### How Community Charge-Free Withdrawals Work + +When you provide liquidity to the ETH/SUP Uniswap V3 pool through your Reserve, a timestamp is recorded for that position. After 180 days (6 months) from the initial liquidity provision, you become eligible for Community Charge-free withdrawals. + +**Key Benefits:** + +- **No Community Charge**: Withdraw your SUP tokens without paying the usual Community Charge +- **Full Value**: Get the complete value of your position without deductions +- **Reward Retention**: Keep all accumulated trading fees and rewards + +**Requirements:** + +- Position must have been created at least 180 days ago +- You must be the owner of the Reserve that created the position +- Position must still exist and be active + +**Important Notes:** + +- The 180-day timer starts from when you first provide liquidity to a position +- Each position has its own independent 180-day timer +- Community Charge-free withdrawal only applies to the SUP tokens in your liquidity position, not to staked tokens +- You can still collect trading fees at any time without affecting the Community Charge-free withdrawal eligibility + +**Example Timeline:** + +1. **Day 0**: Provide liquidity to ETH/SUP pool +2. **Day 1-179**: Collect trading fees, position not eligible for Community Charge-free withdrawal +3. **Day 180+**: Position becomes eligible for Community Charge-free withdrawal +4. **Any time after Day 180**: Withdraw your SUP tokens directly to your wallet without paying the Community Charge + +## Token Management + +### Available Balance + +Your available balance is the amount of SUP tokens you can use for: + +- Staking +- Providing liquidity +- Withdrawing from the reserve (Drain or Stream) + +### Staked Balance + +Your staked balance represents tokens that are earning staking rewards but cannot be used for other purposes until unstaked. + +### Liquidity Balance + +Your liquidity balance represents the size of all your Reserves' liquidity positions in the ETH/SUP pool. + +## Important Considerations + +### Security + +- Only you can control your Reserve +- All operations on your Reserve require your signature + +### Fees and Community Charge + +- **Reserve Creation**: One-time fee set by governance +- **Draining**: 80% community charge +- **Streaming**: Variable community charge based on duration + +### Limitations + +- **Minimum Withdraw Amount**: 10 SUP tokens +- **Stream Period**: 365 days +- **Minimum Staking Period**: 30 days after last staking event +- **Liquidity Provision Cooldown**: 7 days after providing liquidity +- **Liquidity Provision Community Charge-free withdrawal**: 180 days after providing liquidity + +--- + +_This guide covers the main user interactions with the SPR SUP Reserve System. For technical details and contract specifications, refer to the contract source code and interfaces._ diff --git a/docs/design/SUP_TOKEN_STATE_MACHINE.drawio b/docs/design/SUP_TOKEN_STATE_MACHINE.drawio new file mode 100644 index 0000000..c544618 --- /dev/null +++ b/docs/design/SUP_TOKEN_STATE_MACHINE.drawio @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/contracts/abis/interfaces/IBridgedSuperToken.json b/packages/contracts/abis/interfaces/IBridgedSuperToken.json new file mode 100644 index 0000000..617c3a5 --- /dev/null +++ b/packages/contracts/abis/interfaces/IBridgedSuperToken.json @@ -0,0 +1,2318 @@ +[ + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "POOL_ADMIN_NFT", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IPoolAdminNFT" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "POOL_MEMBER_NFT", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IPoolMemberNFT" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "authorizeOperator", + "inputs": [ + { + "name": "operator", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "balance", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "_user", + "type": "address", + "internalType": "address" + }, + { + "name": "_amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burningCurrentLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burningMaxLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "changeAdmin", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "createAgreement", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "data", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decreaseAllowance", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "subtractedValue", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "defaultOperators", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "downgrade", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "downgradeTo", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "eip712Domain", + "inputs": [], + "outputs": [ + { + "name": "fields", + "type": "bytes1", + "internalType": "bytes1" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "version", + "type": "string", + "internalType": "string" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "verifyingContract", + "type": "address", + "internalType": "address" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "extensions", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAccountActiveAgreements", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "activeAgreements", + "type": "address[]", + "internalType": "contract ISuperAgreement[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAdmin", + "inputs": [], + "outputs": [ + { + "name": "admin", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAgreementData", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "dataLength", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "data", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAgreementStateSlot", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "slotId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "dataLength", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "slotData", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getHost", + "inputs": [], + "outputs": [ + { + "name": "host", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUnderlyingDecimals", + "inputs": [], + "outputs": [ + { + "name": "underlyingDecimals", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUnderlyingToken", + "inputs": [], + "outputs": [ + { + "name": "tokenAddr", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "granularity", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "increaseAllowance", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "addedValue", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "underlyingToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "underlyingDecimals", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "n", + "type": "string", + "internalType": "string" + }, + { + "name": "s", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeWithAdmin", + "inputs": [ + { + "name": "underlyingToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "underlyingDecimals", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "n", + "type": "string", + "internalType": "string" + }, + { + "name": "s", + "type": "string", + "internalType": "string" + }, + { + "name": "admin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isAccountCritical", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "isCritical", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isAccountCriticalNow", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "isCritical", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isAccountSolvent", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "isSolvent", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isAccountSolventNow", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "isSolvent", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isOperatorFor", + "inputs": [ + { + "name": "operator", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenHolder", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "makeLiquidationPayoutsV2", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "liquidationTypeData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "liquidatorAccount", + "type": "address", + "internalType": "address" + }, + { + "name": "useDefaultRewardAccount", + "type": "bool", + "internalType": "bool" + }, + { + "name": "targetAccount", + "type": "address", + "internalType": "address" + }, + { + "name": "rewardAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "targetAccountBalanceDelta", + "type": "int256", + "internalType": "int256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "_user", + "type": "address", + "internalType": "address" + }, + { + "name": "_amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mintingCurrentLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mintingMaxLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "operationApprove", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationDecreaseAllowance", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "subtractedValue", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationDowngrade", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationDowngradeTo", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationIncreaseAllowance", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "addedValue", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationSend", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationTransferFrom", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationUpgrade", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationUpgradeTo", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operatorBurn", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "operatorData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operatorSend", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "operatorData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "realtimeBalanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "availableBalance", + "type": "int256", + "internalType": "int256" + }, + { + "name": "deposit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owedDeposit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "realtimeBalanceOfNow", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "availableBalance", + "type": "int256", + "internalType": "int256" + }, + { + "name": "deposit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owedDeposit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "revokeOperator", + "inputs": [ + { + "name": "operator", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "selfApproveFor", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "selfBurn", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "selfMint", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "selfTransferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "send", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLimits", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + }, + { + "name": "_mintingLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_burningLimit", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLockbox", + "inputs": [ + { + "name": "_lockbox", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "settleBalance", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "delta", + "type": "int256", + "internalType": "int256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "terminateAgreement", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "dataLength", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "toUnderlyingAmount", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "underlyingAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "adjustedAmount", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalSupply", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferAll", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateAgreementData", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "data", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateAgreementStateSlot", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "slotId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "slotData", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgrade", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeTo", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "AdminChanged", + "inputs": [ + { + "name": "oldAdmin", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newAdmin", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementCreated", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "data", + "type": "bytes32[]", + "indexed": false, + "internalType": "bytes32[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementLiquidated", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "penaltyAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "rewardAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "rewardAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementLiquidatedBy", + "inputs": [ + { + "name": "liquidatorAccount", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "penaltyAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "bondAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "rewardAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "bailoutAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementLiquidatedV2", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "liquidatorAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "targetAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "rewardAmountReceiver", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "rewardAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "targetAccountBalanceDelta", + "type": "int256", + "indexed": false, + "internalType": "int256" + }, + { + "name": "liquidationTypeData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementStateUpdated", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "slotId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementTerminated", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementUpdated", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "data", + "type": "bytes32[]", + "indexed": false, + "internalType": "bytes32[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AuthorizedOperator", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "tokenHolder", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Bailout", + "inputs": [ + { + "name": "bailoutAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "bailoutAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "BridgeLimitsSet", + "inputs": [ + { + "name": "_mintingLimit", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "_burningLimit", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "_bridge", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Burned", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "operatorData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "EIP712DomainChanged", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "LockboxSet", + "inputs": [ + { + "name": "_lockbox", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Minted", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "operatorData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PoolAdminNFTCreated", + "inputs": [ + { + "name": "poolAdminNFT", + "type": "address", + "indexed": true, + "internalType": "contract IPoolAdminNFT" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PoolMemberNFTCreated", + "inputs": [ + { + "name": "poolMemberNFT", + "type": "address", + "indexed": true, + "internalType": "contract IPoolMemberNFT" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RevokedOperator", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "tokenHolder", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Sent", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "operatorData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokenDowngraded", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokenUpgraded", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "IXERC20_NotHighEnoughLimits", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_AGREEMENT_ALREADY_EXISTS", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_AGREEMENT_DOES_NOT_EXIST", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_BURN_INSUFFICIENT_BALANCE", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_MOVE_INSUFFICIENT_BALANCE", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_ONLY_HOST", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_ONLY_LISTED_AGREEMENT", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_APPROVE_FROM_ZERO_ADDRESS", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_APPROVE_TO_ZERO_ADDRESS", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_BURN_FROM_ZERO_ADDRESS", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_CALLER_IS_NOT_OPERATOR_FOR_HOLDER", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_INFLATIONARY_DEFLATIONARY_NOT_SUPPORTED", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_MINT_TO_ZERO_ADDRESS", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_NFT_PROXY_ADDRESS_CHANGED", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_NOT_ERC777_TOKENS_RECIPIENT", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_NO_UNDERLYING_TOKEN", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_ONLY_ADMIN", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_ONLY_GOV_OWNER", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_ONLY_SELF", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_PERMIT_EXPIRED_SIGNATURE", + "inputs": [ + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SUPER_TOKEN_PERMIT_INVALID_SIGNER", + "inputs": [ + { + "name": "signer", + "type": "address", + "internalType": "address" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SUPER_TOKEN_TRANSFER_FROM_ZERO_ADDRESS", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_TRANSFER_TO_ZERO_ADDRESS", + "inputs": [] + } +] diff --git a/packages/contracts/abis/interfaces/IEPProgramManager.json b/packages/contracts/abis/interfaces/IEPProgramManager.json new file mode 100644 index 0000000..43ad418 --- /dev/null +++ b/packages/contracts/abis/interfaces/IEPProgramManager.json @@ -0,0 +1,341 @@ +[ + { + "type": "function", + "name": "batchUpdateUnits", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "newUnits", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "batchUpdateUserUnits", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "newUnits", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "createProgram", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "programAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "signer", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "contract ISuperToken" + }, + { + "name": "poolName", + "type": "string", + "internalType": "string" + }, + { + "name": "poolSymbol", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "distributionPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getNextValidNonce", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "validNonce", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getProgramPool", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "programPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "updateProgramSigner", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "newSigner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateUnits", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "newUnits", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateUserUnits", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "newUnits", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ProgramCreated", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "programAdmin", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "signer", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "distributionPool", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProgramSignerUpdated", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newSigner", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UserUnitsUpdated", + "inputs": [ + { + "name": "user", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "programId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newUnits", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "INVALID_PARAMETER", + "inputs": [] + }, + { + "type": "error", + "name": "INVALID_SIGNATURE", + "inputs": [ + { + "name": "reason", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "NOT_PROGRAM_ADMIN", + "inputs": [] + }, + { + "type": "error", + "name": "PROGRAM_ALREADY_CREATED", + "inputs": [] + }, + { + "type": "error", + "name": "PROGRAM_NOT_FOUND", + "inputs": [] + } +] diff --git a/packages/contracts/abis/interfaces/IFluidLocker.json b/packages/contracts/abis/interfaces/IFluidLocker.json new file mode 100644 index 0000000..4af75a9 --- /dev/null +++ b/packages/contracts/abis/interfaces/IFluidLocker.json @@ -0,0 +1,642 @@ +[ + { + "type": "function", + "name": "claim", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "totalProgramUnits", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "claim", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "totalProgramUnits", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "collectFees", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "collectedWeth", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "collectedSup", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "connect", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disconnect", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disconnect", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disconnectAndClaim", + "inputs": [ + { + "name": "programIdsToDisconnect", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "programIdsToClaim", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "totalProgramUnits", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getAvailableBalance", + "inputs": [], + "outputs": [ + { + "name": "aBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getFlowRatePerProgram", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [ + { + "name": "flowRates", + "type": "int96[]", + "internalType": "int96[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getFlowRatePerProgram", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "flowRate", + "type": "int96", + "internalType": "int96" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getFontaineBeaconImplementation", + "inputs": [], + "outputs": [ + { + "name": "fontaineBeaconImpl", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLiquidityBalance", + "inputs": [], + "outputs": [ + { + "name": "lBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPositionLiquidity", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "liquidity", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getStakedBalance", + "inputs": [], + "outputs": [ + { + "name": "sBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUnitsPerProgram", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "units", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUnitsPerProgram", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [ + { + "name": "units", + "type": "uint128[]", + "internalType": "uint128[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "lock", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "provideLiquidity", + "inputs": [ + { + "name": "supAmount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "stake", + "inputs": [ + { + "name": "amountToStake", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "unlock", + "inputs": [ + { + "name": "unlockAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "unlockPeriod", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "unstake", + "inputs": [ + { + "name": "amountToUnstake", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdrawDustETH", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdrawLiquidity", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidityToRemove", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "amount0ToRemove", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1ToRemove", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "FluidLocked", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FluidStaked", + "inputs": [ + { + "name": "newTotalStakedBalance", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "addedAmount", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FluidStreamClaimed", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "totalProgramUnits", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FluidStreamsClaimed", + "inputs": [ + { + "name": "programId", + "type": "uint256[]", + "indexed": true, + "internalType": "uint256[]" + }, + { + "name": "totalProgramUnits", + "type": "uint256[]", + "indexed": true, + "internalType": "uint256[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FluidUnlocked", + "inputs": [ + { + "name": "unlockPeriod", + "type": "uint128", + "indexed": true, + "internalType": "uint128" + }, + { + "name": "availableBalance", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "fontaine", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FluidUnstaked", + "inputs": [ + { + "name": "newTotalStakedBalance", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "removedAmount", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LiquidityPositionBurned", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LiquidityPositionCreated", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "FORBIDDEN", + "inputs": [] + }, + { + "type": "error", + "name": "INSUFFICIENT_AVAILABLE_BALANCE", + "inputs": [] + }, + { + "type": "error", + "name": "INSUFFICIENT_BALANCE", + "inputs": [] + }, + { + "type": "error", + "name": "INSUFFICIENT_ETH_SENT", + "inputs": [] + }, + { + "type": "error", + "name": "INSUFFICIENT_STAKED_BALANCE", + "inputs": [] + }, + { + "type": "error", + "name": "INSUFFICIENT_UNLOCK_AMOUNT", + "inputs": [] + }, + { + "type": "error", + "name": "INVALID_UNLOCK_PERIOD", + "inputs": [] + }, + { + "type": "error", + "name": "LIQUIDITY_POOL_NOT_APPROVED", + "inputs": [] + }, + { + "type": "error", + "name": "LOCKER_HAS_NO_POSITION", + "inputs": [] + }, + { + "type": "error", + "name": "LP_COOLDOWN_NOT_ELAPSED", + "inputs": [] + }, + { + "type": "error", + "name": "LP_DISTRIBUTION_POOL_HAS_NO_UNITS", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_LOCKER_OWNER", + "inputs": [] + }, + { + "type": "error", + "name": "NO_FLUID_TO_UNLOCK", + "inputs": [] + }, + { + "type": "error", + "name": "NO_FLUID_TO_UNSTAKE", + "inputs": [] + }, + { + "type": "error", + "name": "STAKER_DISTRIBUTION_POOL_HAS_NO_UNITS", + "inputs": [] + }, + { + "type": "error", + "name": "STAKING_COOLDOWN_NOT_ELAPSED", + "inputs": [] + }, + { + "type": "error", + "name": "TTE_NOT_ACTIVATED", + "inputs": [] + } +] diff --git a/packages/contracts/abis/interfaces/IFluidLockerFactory.json b/packages/contracts/abis/interfaces/IFluidLockerFactory.json new file mode 100644 index 0000000..259cb25 --- /dev/null +++ b/packages/contracts/abis/interfaces/IFluidLockerFactory.json @@ -0,0 +1,188 @@ +[ + { + "type": "function", + "name": "createLockerContract", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "lockerInstance", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "createLockerContract", + "inputs": [], + "outputs": [ + { + "name": "lockerInstance", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "getLockerAddress", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "lockerAddress", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLockerBeaconImplementation", + "inputs": [], + "outputs": [ + { + "name": "lockerBeaconImpl", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUserLocker", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "isCreated", + "type": "bool", + "internalType": "bool" + }, + { + "name": "lockerAddress", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "setGovernor", + "inputs": [ + { + "name": "newGovernor", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLockerCreationFee", + "inputs": [ + { + "name": "newLockerCreationFee", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeTo", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdrawETH", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "GovernorUpdated", + "inputs": [ + { + "name": "newGovernor", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LockerCreated", + "inputs": [ + { + "name": "lockerOwner", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "lockerAddress", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "INVALID_FEE", + "inputs": [] + }, + { + "type": "error", + "name": "LOCKER_CREATION_PAUSED", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_GOVERNOR", + "inputs": [] + } +] diff --git a/packages/contracts/abis/interfaces/IFontaine.json b/packages/contracts/abis/interfaces/IFontaine.json new file mode 100644 index 0000000..749a969 --- /dev/null +++ b/packages/contracts/abis/interfaces/IFontaine.json @@ -0,0 +1,52 @@ +[ + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "unlockRecipient", + "type": "address", + "internalType": "address" + }, + { + "name": "unlockFlowRate", + "type": "int96", + "internalType": "int96" + }, + { + "name": "unlockPeriod", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "terminateUnlock", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "error", + "name": "CANNOT_UNLOCK_TO_SUPERAPP", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_CONNECTED_LOCKER", + "inputs": [] + }, + { + "type": "error", + "name": "NO_ACTIVE_UNLOCK", + "inputs": [] + }, + { + "type": "error", + "name": "TOO_EARLY_TO_TERMINATE_UNLOCK", + "inputs": [] + } +] diff --git a/packages/contracts/abis/interfaces/IOPBridgedSuperToken.json b/packages/contracts/abis/interfaces/IOPBridgedSuperToken.json new file mode 100644 index 0000000..881af83 --- /dev/null +++ b/packages/contracts/abis/interfaces/IOPBridgedSuperToken.json @@ -0,0 +1,2363 @@ +[ + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "POOL_ADMIN_NFT", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IPoolAdminNFT" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "POOL_MEMBER_NFT", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IPoolMemberNFT" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "authorizeOperator", + "inputs": [ + { + "name": "operator", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "balance", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "bridge", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "_from", + "type": "address", + "internalType": "address" + }, + { + "name": "_amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burningCurrentLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burningMaxLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "changeAdmin", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "createAgreement", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "data", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decreaseAllowance", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "subtractedValue", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "defaultOperators", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "downgrade", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "downgradeTo", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "eip712Domain", + "inputs": [], + "outputs": [ + { + "name": "fields", + "type": "bytes1", + "internalType": "bytes1" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "version", + "type": "string", + "internalType": "string" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "verifyingContract", + "type": "address", + "internalType": "address" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "extensions", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAccountActiveAgreements", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "activeAgreements", + "type": "address[]", + "internalType": "contract ISuperAgreement[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAdmin", + "inputs": [], + "outputs": [ + { + "name": "admin", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAgreementData", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "dataLength", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "data", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAgreementStateSlot", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "slotId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "dataLength", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "slotData", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getHost", + "inputs": [], + "outputs": [ + { + "name": "host", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUnderlyingDecimals", + "inputs": [], + "outputs": [ + { + "name": "underlyingDecimals", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUnderlyingToken", + "inputs": [], + "outputs": [ + { + "name": "tokenAddr", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "granularity", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "increaseAllowance", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "addedValue", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "underlyingToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "underlyingDecimals", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "n", + "type": "string", + "internalType": "string" + }, + { + "name": "s", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeWithAdmin", + "inputs": [ + { + "name": "underlyingToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "underlyingDecimals", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "n", + "type": "string", + "internalType": "string" + }, + { + "name": "s", + "type": "string", + "internalType": "string" + }, + { + "name": "admin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isAccountCritical", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "isCritical", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isAccountCriticalNow", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "isCritical", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isAccountSolvent", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "isSolvent", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isAccountSolventNow", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "isSolvent", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isOperatorFor", + "inputs": [ + { + "name": "operator", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenHolder", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "makeLiquidationPayoutsV2", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "liquidationTypeData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "liquidatorAccount", + "type": "address", + "internalType": "address" + }, + { + "name": "useDefaultRewardAccount", + "type": "bool", + "internalType": "bool" + }, + { + "name": "targetAccount", + "type": "address", + "internalType": "address" + }, + { + "name": "rewardAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "targetAccountBalanceDelta", + "type": "int256", + "internalType": "int256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "_to", + "type": "address", + "internalType": "address" + }, + { + "name": "_amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mintingCurrentLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mintingMaxLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "operationApprove", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationDecreaseAllowance", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "subtractedValue", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationDowngrade", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationDowngradeTo", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationIncreaseAllowance", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "addedValue", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationSend", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationTransferFrom", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationUpgrade", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operationUpgradeTo", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operatorBurn", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "operatorData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "operatorSend", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "operatorData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "realtimeBalanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "availableBalance", + "type": "int256", + "internalType": "int256" + }, + { + "name": "deposit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owedDeposit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "realtimeBalanceOfNow", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "availableBalance", + "type": "int256", + "internalType": "int256" + }, + { + "name": "deposit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owedDeposit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "remoteToken", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "revokeOperator", + "inputs": [ + { + "name": "operator", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "selfApproveFor", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "selfBurn", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "selfMint", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "selfTransferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "send", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLimits", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + }, + { + "name": "_mintingLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_burningLimit", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLockbox", + "inputs": [ + { + "name": "_lockbox", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "settleBalance", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "delta", + "type": "int256", + "internalType": "int256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "terminateAgreement", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "dataLength", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "toUnderlyingAmount", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "underlyingAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "adjustedAmount", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalSupply", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferAll", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateAgreementData", + "inputs": [ + { + "name": "id", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "data", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateAgreementStateSlot", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "slotId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "slotData", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgrade", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeTo", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "AdminChanged", + "inputs": [ + { + "name": "oldAdmin", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newAdmin", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementCreated", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "data", + "type": "bytes32[]", + "indexed": false, + "internalType": "bytes32[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementLiquidated", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "penaltyAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "rewardAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "rewardAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementLiquidatedBy", + "inputs": [ + { + "name": "liquidatorAccount", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "penaltyAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "bondAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "rewardAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "bailoutAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementLiquidatedV2", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "liquidatorAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "targetAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "rewardAmountReceiver", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "rewardAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "targetAccountBalanceDelta", + "type": "int256", + "indexed": false, + "internalType": "int256" + }, + { + "name": "liquidationTypeData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementStateUpdated", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "slotId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementTerminated", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AgreementUpdated", + "inputs": [ + { + "name": "agreementClass", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "data", + "type": "bytes32[]", + "indexed": false, + "internalType": "bytes32[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AuthorizedOperator", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "tokenHolder", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Bailout", + "inputs": [ + { + "name": "bailoutAccount", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "bailoutAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "BridgeLimitsSet", + "inputs": [ + { + "name": "_mintingLimit", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "_burningLimit", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "_bridge", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Burned", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "operatorData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "EIP712DomainChanged", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "LockboxSet", + "inputs": [ + { + "name": "_lockbox", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Minted", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "operatorData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PoolAdminNFTCreated", + "inputs": [ + { + "name": "poolAdminNFT", + "type": "address", + "indexed": true, + "internalType": "contract IPoolAdminNFT" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PoolMemberNFTCreated", + "inputs": [ + { + "name": "poolMemberNFT", + "type": "address", + "indexed": true, + "internalType": "contract IPoolMemberNFT" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RevokedOperator", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "tokenHolder", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Sent", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "operatorData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokenDowngraded", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokenUpgraded", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "IXERC20_NotHighEnoughLimits", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_AGREEMENT_ALREADY_EXISTS", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_AGREEMENT_DOES_NOT_EXIST", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_BURN_INSUFFICIENT_BALANCE", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_MOVE_INSUFFICIENT_BALANCE", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_ONLY_HOST", + "inputs": [] + }, + { + "type": "error", + "name": "SF_TOKEN_ONLY_LISTED_AGREEMENT", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_APPROVE_FROM_ZERO_ADDRESS", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_APPROVE_TO_ZERO_ADDRESS", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_BURN_FROM_ZERO_ADDRESS", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_CALLER_IS_NOT_OPERATOR_FOR_HOLDER", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_INFLATIONARY_DEFLATIONARY_NOT_SUPPORTED", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_MINT_TO_ZERO_ADDRESS", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_NFT_PROXY_ADDRESS_CHANGED", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_NOT_ERC777_TOKENS_RECIPIENT", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_NO_UNDERLYING_TOKEN", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_ONLY_ADMIN", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_ONLY_GOV_OWNER", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_ONLY_SELF", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_PERMIT_EXPIRED_SIGNATURE", + "inputs": [ + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SUPER_TOKEN_PERMIT_INVALID_SIGNER", + "inputs": [ + { + "name": "signer", + "type": "address", + "internalType": "address" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SUPER_TOKEN_TRANSFER_FROM_ZERO_ADDRESS", + "inputs": [] + }, + { + "type": "error", + "name": "SUPER_TOKEN_TRANSFER_TO_ZERO_ADDRESS", + "inputs": [] + } +] diff --git a/packages/contracts/abis/interfaces/IOptimismMintableERC20.json b/packages/contracts/abis/interfaces/IOptimismMintableERC20.json new file mode 100644 index 0000000..b4cd708 --- /dev/null +++ b/packages/contracts/abis/interfaces/IOptimismMintableERC20.json @@ -0,0 +1,83 @@ +[ + { + "type": "function", + "name": "bridge", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "_from", + "type": "address", + "internalType": "address" + }, + { + "name": "_amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "_to", + "type": "address", + "internalType": "address" + }, + { + "name": "_amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "remoteToken", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + } +] diff --git a/packages/contracts/abis/interfaces/IStakingRewardController.json b/packages/contracts/abis/interfaces/IStakingRewardController.json new file mode 100644 index 0000000..7e01937 --- /dev/null +++ b/packages/contracts/abis/interfaces/IStakingRewardController.json @@ -0,0 +1,301 @@ +[ + { + "type": "function", + "name": "approveLocker", + "inputs": [ + { + "name": "lockerAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getTaxAllocation", + "inputs": [], + "outputs": [ + { + "name": "stakerAllocationBP", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "liquidityProviderAllocationBP", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "lpDistributionPool", + "inputs": [], + "outputs": [ + { + "name": "lpDistributionPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "refreshTaxDistributionFlow", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLockerFactory", + "inputs": [ + { + "name": "lockerFactoryAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setTaxAllocation", + "inputs": [ + { + "name": "stakerAllocationBP", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "liquidityProviderAllocationBP", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setupLPDistributionPool", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "taxDistributionPool", + "inputs": [], + "outputs": [ + { + "name": "taxDistributionPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "updateLiquidityProviderUnits", + "inputs": [ + { + "name": "lockerLiquidityBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateStakerUnits", + "inputs": [ + { + "name": "lockerStakedBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeTo", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "LockerApproved", + "inputs": [ + { + "name": "approvedLocker", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LockerFactoryAddressUpdated", + "inputs": [ + { + "name": "newLockerFactoryAddress", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProgramManagerAddressUpdated", + "inputs": [ + { + "name": "newProgramManagerAddress", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SubsidyFlowRateUpdated", + "inputs": [ + { + "name": "newSubsidyFlowRate", + "type": "int96", + "indexed": true, + "internalType": "int96" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TaxAllocationUpdated", + "inputs": [ + { + "name": "stakerAllocationBP", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "liquidityProviderAllocationBP", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TaxDistributionFlowUpdated", + "inputs": [ + { + "name": "liquidityProviderFlowRate", + "type": "int96", + "indexed": false, + "internalType": "int96" + }, + { + "name": "stakerFlowRate", + "type": "int96", + "indexed": false, + "internalType": "int96" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UpdatedLiquidityProviderUnits", + "inputs": [ + { + "name": "liquidityProvider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "totalLiquidityProviderUnits", + "type": "uint128", + "indexed": true, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UpdatedStakersUnits", + "inputs": [ + { + "name": "staker", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "totalStakerUnits", + "type": "uint128", + "indexed": true, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "INVALID_PARAMETER", + "inputs": [] + }, + { + "type": "error", + "name": "LP_DISTRIBUTION_POOL_ALREADY_SET", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_APPROVED_LOCKER", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_LOCKER_FACTORY", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_PROGRAM_MANAGER", + "inputs": [] + } +] diff --git a/packages/contracts/abis/interfaces/ISupVesting.json b/packages/contracts/abis/interfaces/ISupVesting.json new file mode 100644 index 0000000..38da54d --- /dev/null +++ b/packages/contracts/abis/interfaces/ISupVesting.json @@ -0,0 +1,27 @@ +[ + { + "type": "function", + "name": "emergencyWithdraw", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "VestingDeleted", + "inputs": [ + { + "name": "transferredAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "FORBIDDEN", + "inputs": [] + } +] diff --git a/packages/contracts/abis/interfaces/ISupVestingFactory.json b/packages/contracts/abis/interfaces/ISupVestingFactory.json new file mode 100644 index 0000000..cf0fc18 --- /dev/null +++ b/packages/contracts/abis/interfaces/ISupVestingFactory.json @@ -0,0 +1,184 @@ +[ + { + "type": "function", + "name": "admin", + "inputs": [], + "outputs": [ + { + "name": "admin", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "vestingReceiver", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "unvestedBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "createSupVestingContract", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "recipientVestingIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cliffAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cliffDate", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "endDate", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [ + { + "name": "newSupVestingContract", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setAdmin", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setTreasury", + "inputs": [ + { + "name": "newTreasury", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "totalSupply", + "inputs": [], + "outputs": [ + { + "name": "supply", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "treasury", + "inputs": [], + "outputs": [ + { + "name": "treasury", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "SupVestingCreated", + "inputs": [ + { + "name": "recipient", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newSupVestingContract", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "FORBIDDEN", + "inputs": [] + }, + { + "type": "error", + "name": "VESTING_DUPLICATED", + "inputs": [] + } +] diff --git a/packages/contracts/abis/interfaces/IXERC20.json b/packages/contracts/abis/interfaces/IXERC20.json new file mode 100644 index 0000000..9498e42 --- /dev/null +++ b/packages/contracts/abis/interfaces/IXERC20.json @@ -0,0 +1,193 @@ +[ + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "_user", + "type": "address", + "internalType": "address" + }, + { + "name": "_amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burningCurrentLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burningMaxLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "_user", + "type": "address", + "internalType": "address" + }, + { + "name": "_amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mintingCurrentLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mintingMaxLimitOf", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "setLimits", + "inputs": [ + { + "name": "_bridge", + "type": "address", + "internalType": "address" + }, + { + "name": "_mintingLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_burningLimit", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLockbox", + "inputs": [ + { + "name": "_lockbox", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "BridgeLimitsSet", + "inputs": [ + { + "name": "_mintingLimit", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "_burningLimit", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "_bridge", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LockboxSet", + "inputs": [ + { + "name": "_lockbox", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "IXERC20_NotHighEnoughLimits", + "inputs": [] + } +] diff --git a/packages/contracts/abis/main/EPProgramManager.json b/packages/contracts/abis/main/EPProgramManager.json new file mode 100644 index 0000000..139eb55 --- /dev/null +++ b/packages/contracts/abis/main/EPProgramManager.json @@ -0,0 +1,375 @@ +[ + { + "type": "function", + "name": "batchUpdateUnits", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "newUnits", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "batchUpdateUserUnits", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "newUnits", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "createProgram", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "programAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "signer", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "contract ISuperToken" + }, + { + "name": "poolName", + "type": "string", + "internalType": "string" + }, + { + "name": "poolSymbol", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "distributionPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getNextValidNonce", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "validNonce", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getProgramPool", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "programPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "programs", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "programAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "stackSigner", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "contract ISuperToken" + }, + { + "name": "distributionPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "updateProgramSigner", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "newSigner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateUnits", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "newUnits", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateUserUnits", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "newUnits", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ProgramCreated", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "programAdmin", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "signer", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "distributionPool", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProgramSignerUpdated", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newSigner", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UserUnitsUpdated", + "inputs": [ + { + "name": "user", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "programId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newUnits", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "INVALID_PARAMETER", + "inputs": [] + }, + { + "type": "error", + "name": "INVALID_SIGNATURE", + "inputs": [ + { + "name": "reason", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "NOT_PROGRAM_ADMIN", + "inputs": [] + }, + { + "type": "error", + "name": "PROGRAM_ALREADY_CREATED", + "inputs": [] + }, + { + "type": "error", + "name": "PROGRAM_NOT_FOUND", + "inputs": [] + } +] diff --git a/packages/contracts/abis/main/FluidEPProgramManager.json b/packages/contracts/abis/main/FluidEPProgramManager.json new file mode 100644 index 0000000..dead4e1 --- /dev/null +++ b/packages/contracts/abis/main/FluidEPProgramManager.json @@ -0,0 +1,1066 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "taxDistributionPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "EARLY_PROGRAM_END", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "TAX_DISTRIBUTION_POOL", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "batchUpdateUnits", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "newUnits", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "batchUpdateUserUnits", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "newUnits", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "buildBatchOperations", + "inputs": [ + { + "name": "host", + "type": "address", + "internalType": "contract ISuperfluid" + }, + { + "name": "params", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "operations", + "type": "tuple[]", + "internalType": "struct ISuperfluid.Operation[]", + "components": [ + { + "name": "operationType", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "calculateAllowances", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "plannedFundingAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "plannedProgramDuration", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [ + { + "name": "depositAllowance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "flowRateAllowance", + "type": "int96", + "internalType": "int96" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "cancelProgram", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "createProgram", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "programAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "signer", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "contract ISuperToken" + }, + { + "name": "poolName", + "type": "string", + "internalType": "string" + }, + { + "name": "poolSymbol", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "distributionPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "emergencyWithdraw", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "contract ISuperToken" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "fluidLockerFactory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IFluidLockerFactory" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "fluidTreasury", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNextValidNonce", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "validNonce", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getProgramDetails", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "details", + "type": "tuple", + "internalType": "struct FluidEPProgramManager.FluidProgramDetails", + "components": [ + { + "name": "fundingFlowRate", + "type": "int96", + "internalType": "int96" + }, + { + "name": "subsidyFlowRate", + "type": "int96", + "internalType": "int96" + }, + { + "name": "fundingStartDate", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "duration", + "type": "uint32", + "internalType": "uint32" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getProgramPool", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "programPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "treasury", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "manualPoolUpdate", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackPoints", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "users", + "type": "address[]", + "internalType": "address[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "manualPoolUpdate", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackPoints", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "paramsGivePermission", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "duration", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "postCheck", + "inputs": [ + { + "name": "host", + "type": "address", + "internalType": "contract ISuperfluid" + }, + { + "name": "params", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "msgSender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "programs", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "programAdmin", + "type": "address", + "internalType": "address" + }, + { + "name": "stackSigner", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "contract ISuperToken" + }, + { + "name": "distributionPool", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLockerFactory", + "inputs": [ + { + "name": "lockerFactoryAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setSubsidyRate", + "inputs": [ + { + "name": "subsidyRate", + "type": "uint96", + "internalType": "uint96" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setTreasury", + "inputs": [ + { + "name": "treasuryAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "startFunding", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "totalAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "programDuration", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "stopFunding", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "subsidyFundingRate", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint96", + "internalType": "uint96" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateProgramSigner", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "newSigner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateUnits", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "newUnits", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateUserUnits", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "newUnits", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeTo", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProgramCancelled", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "returnedDeposit", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProgramCreated", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "programAdmin", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "signer", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "distributionPool", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProgramFunded", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "fundingAmount", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "subsidyAmount", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "earlyEndDate", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "endDate", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProgramSignerUpdated", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newSigner", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProgramStopped", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "fundingCompensationAmount", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "subsidyCompensationAmount", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UserUnitsUpdated", + "inputs": [ + { + "name": "user", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "programId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newUnits", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CFA_INVALID_FLOW_RATE", + "inputs": [] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, + { + "type": "error", + "name": "FailedInnerCall", + "inputs": [] + }, + { + "type": "error", + "name": "INVALID_PARAMETER", + "inputs": [] + }, + { + "type": "error", + "name": "INVALID_SIGNATURE", + "inputs": [ + { + "name": "reason", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "LOCKER_NOT_FOUND", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_PROGRAM_ADMIN", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "OwnableInvalidOwner", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OwnableUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "POOL_HAS_NO_UNITS", + "inputs": [] + }, + { + "type": "error", + "name": "PROGRAM_ALREADY_CREATED", + "inputs": [] + }, + { + "type": "error", + "name": "PROGRAM_NOT_FOUND", + "inputs": [] + }, + { + "type": "error", + "name": "SafeCastOverflowedIntDowncast", + "inputs": [ + { + "name": "bits", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "value", + "type": "int256", + "internalType": "int256" + } + ] + }, + { + "type": "error", + "name": "TOO_EARLY_TO_END_PROGRAM", + "inputs": [] + } +] diff --git a/packages/contracts/abis/main/FluidLocker.json b/packages/contracts/abis/main/FluidLocker.json new file mode 100644 index 0000000..a872bd8 --- /dev/null +++ b/packages/contracts/abis/main/FluidLocker.json @@ -0,0 +1,1062 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "fluid", + "type": "address", + "internalType": "contract ISuperToken" + }, + { + "name": "programManager", + "type": "address", + "internalType": "contract IEPProgramManager" + }, + { + "name": "stakingRewardController", + "type": "address", + "internalType": "contract IStakingRewardController" + }, + { + "name": "fontaineBeacon", + "type": "address", + "internalType": "address" + }, + { + "name": "isUnlockAvailable", + "type": "bool", + "internalType": "bool" + }, + { + "name": "nonfungiblePositionManager", + "type": "address", + "internalType": "contract INonfungiblePositionManager" + }, + { + "name": "ethSupPool", + "type": "address", + "internalType": "contract IUniswapV3Pool" + }, + { + "name": "swapRouter", + "type": "address", + "internalType": "contract IV3SwapRouter" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "fallback", + "stateMutability": "payable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "BP_PUMP_RATIO", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "BP_SLIPPAGE_TOLERANCE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "EP_PROGRAM_MANAGER", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IEPProgramManager" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "ETH_SUP_POOL", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IUniswapV3Pool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "FLUID", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISuperToken" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "FONTAINE_BEACON", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract UpgradeableBeacon" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "LP_DISTRIBUTION_POOL", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "LP_OPERATION_DEADLINE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "MIN_UNLOCK_AMOUNT", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "NONFUNGIBLE_POSITION_MANAGER", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract INonfungiblePositionManager" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "STAKER_DISTRIBUTION_POOL", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "STAKING_REWARD_CONTROLLER", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IStakingRewardController" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SWAP_ROUTER", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IV3SwapRouter" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "TAX_FREE_WITHDRAW_DELAY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UNLOCK_AVAILABLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "activePositionCount", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "claim", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "totalProgramUnits", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "claim", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "totalProgramUnits", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "collectFees", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "collectedWeth", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "collectedSup", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "connect", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disconnect", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disconnect", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disconnectAndClaim", + "inputs": [ + { + "name": "programIdsToDisconnect", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "programIdsToClaim", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "totalProgramUnits", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "stackSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "fontaineCount", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint16", + "internalType": "uint16" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "fontaines", + "inputs": [ + { + "name": "unlockId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "fontaine", + "type": "address", + "internalType": "contract IFontaine" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAvailableBalance", + "inputs": [], + "outputs": [ + { + "name": "aBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getFlowRatePerProgram", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [ + { + "name": "flowRates", + "type": "int96[]", + "internalType": "int96[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getFlowRatePerProgram", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "flowRate", + "type": "int96", + "internalType": "int96" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getFontaineBeaconImplementation", + "inputs": [], + "outputs": [ + { + "name": "fontaineBeaconImpl", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLiquidityBalance", + "inputs": [], + "outputs": [ + { + "name": "lBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPositionLiquidity", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "liquidity", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getStakedBalance", + "inputs": [], + "outputs": [ + { + "name": "sBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUnitsPerProgram", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "units", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUnitsPerProgram", + "inputs": [ + { + "name": "programIds", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [ + { + "name": "units", + "type": "uint128[]", + "internalType": "uint128[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "lock", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "lockerOwner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "lpCooldownTimestamps", + "inputs": [ + { + "name": "positionTokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "lpCooldownTimestamp", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "provideLiquidity", + "inputs": [ + { + "name": "supAmount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "stake", + "inputs": [ + { + "name": "amountToStake", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "stakingUnlocksAt", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint80", + "internalType": "uint80" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "taxFreeExitTimestamps", + "inputs": [ + { + "name": "positionTokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "taxFreeWithdrawTimestamp", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "unlock", + "inputs": [ + { + "name": "unlockAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "unlockPeriod", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "unstake", + "inputs": [ + { + "name": "amountToUnstake", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdrawDustETH", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdrawLiquidity", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidityToRemove", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "amount0ToRemove", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1ToRemove", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "FluidLocked", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FluidStaked", + "inputs": [ + { + "name": "newTotalStakedBalance", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "addedAmount", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FluidStreamClaimed", + "inputs": [ + { + "name": "programId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "totalProgramUnits", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FluidStreamsClaimed", + "inputs": [ + { + "name": "programId", + "type": "uint256[]", + "indexed": true, + "internalType": "uint256[]" + }, + { + "name": "totalProgramUnits", + "type": "uint256[]", + "indexed": true, + "internalType": "uint256[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FluidUnlocked", + "inputs": [ + { + "name": "unlockPeriod", + "type": "uint128", + "indexed": true, + "internalType": "uint128" + }, + { + "name": "availableBalance", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "fontaine", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FluidUnstaked", + "inputs": [ + { + "name": "newTotalStakedBalance", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "removedAmount", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LiquidityPositionBurned", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LiquidityPositionCreated", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "FORBIDDEN", + "inputs": [] + }, + { + "type": "error", + "name": "INSUFFICIENT_AVAILABLE_BALANCE", + "inputs": [] + }, + { + "type": "error", + "name": "INSUFFICIENT_BALANCE", + "inputs": [] + }, + { + "type": "error", + "name": "INSUFFICIENT_ETH_SENT", + "inputs": [] + }, + { + "type": "error", + "name": "INSUFFICIENT_STAKED_BALANCE", + "inputs": [] + }, + { + "type": "error", + "name": "INSUFFICIENT_UNLOCK_AMOUNT", + "inputs": [] + }, + { + "type": "error", + "name": "INVALID_UNLOCK_PERIOD", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "LIQUIDITY_POOL_NOT_APPROVED", + "inputs": [] + }, + { + "type": "error", + "name": "LOCKER_HAS_NO_POSITION", + "inputs": [] + }, + { + "type": "error", + "name": "LP_COOLDOWN_NOT_ELAPSED", + "inputs": [] + }, + { + "type": "error", + "name": "LP_DISTRIBUTION_POOL_HAS_NO_UNITS", + "inputs": [] + }, + { + "type": "error", + "name": "MathOverflowedMulDiv", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_LOCKER_OWNER", + "inputs": [] + }, + { + "type": "error", + "name": "NO_FLUID_TO_UNLOCK", + "inputs": [] + }, + { + "type": "error", + "name": "NO_FLUID_TO_UNSTAKE", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "Reentrancy", + "inputs": [] + }, + { + "type": "error", + "name": "STAKER_DISTRIBUTION_POOL_HAS_NO_UNITS", + "inputs": [] + }, + { + "type": "error", + "name": "STAKING_COOLDOWN_NOT_ELAPSED", + "inputs": [] + }, + { + "type": "error", + "name": "SafeCastOverflowedIntDowncast", + "inputs": [ + { + "name": "bits", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "value", + "type": "int256", + "internalType": "int256" + } + ] + }, + { + "type": "error", + "name": "TTE_NOT_ACTIVATED", + "inputs": [] + } +] diff --git a/packages/contracts/abis/main/FluidLockerFactory.json b/packages/contracts/abis/main/FluidLockerFactory.json new file mode 100644 index 0000000..aea8c00 --- /dev/null +++ b/packages/contracts/abis/main/FluidLockerFactory.json @@ -0,0 +1,355 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "lockerBeacon", + "type": "address", + "internalType": "address" + }, + { + "name": "stakingRewardController", + "type": "address", + "internalType": "contract IStakingRewardController" + }, + { + "name": "pauseStatus", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "IS_PAUSED", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "LOCKER_BEACON", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract UpgradeableBeacon" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "STAKING_REWARD_CONTROLLER", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IStakingRewardController" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "createLockerContract", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "lockerInstance", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "createLockerContract", + "inputs": [], + "outputs": [ + { + "name": "lockerInstance", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "getLockerAddress", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "lockerAddress", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLockerBeaconImplementation", + "inputs": [], + "outputs": [ + { + "name": "lockerBeaconImpl", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUserLocker", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "isCreated", + "type": "bool", + "internalType": "bool" + }, + { + "name": "lockerAddress", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "governor", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "_governor", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "lockerCreationFee", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "setGovernor", + "inputs": [ + { + "name": "newGovernor", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLockerCreationFee", + "inputs": [ + { + "name": "newLockerCreationFee", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeTo", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdrawETH", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "GovernorUpdated", + "inputs": [ + { + "name": "newGovernor", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LockerCreated", + "inputs": [ + { + "name": "lockerOwner", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "lockerAddress", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, + { + "type": "error", + "name": "FailedInnerCall", + "inputs": [] + }, + { + "type": "error", + "name": "INVALID_FEE", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "LOCKER_CREATION_PAUSED", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_GOVERNOR", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + } +] diff --git a/packages/contracts/abis/main/Fontaine.json b/packages/contracts/abis/main/Fontaine.json new file mode 100644 index 0000000..928f926 --- /dev/null +++ b/packages/contracts/abis/main/Fontaine.json @@ -0,0 +1,156 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "fluid", + "type": "address", + "internalType": "contract ISuperToken" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "EARLY_END", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "FLUID", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISuperToken" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "endDate", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "unlockRecipient", + "type": "address", + "internalType": "address" + }, + { + "name": "targetUnlockFlowRate", + "type": "int96", + "internalType": "int96" + }, + { + "name": "unlockPeriod", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "recipient", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "terminateUnlock", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "unlockFlowRate", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint96", + "internalType": "uint96" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "CANNOT_UNLOCK_TO_SUPERAPP", + "inputs": [] + }, + { + "type": "error", + "name": "CFA_INVALID_FLOW_RATE", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_CONNECTED_LOCKER", + "inputs": [] + }, + { + "type": "error", + "name": "NO_ACTIVE_UNLOCK", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "TOO_EARLY_TO_TERMINATE_UNLOCK", + "inputs": [] + } +] diff --git a/packages/contracts/abis/main/StakingRewardController.json b/packages/contracts/abis/main/StakingRewardController.json new file mode 100644 index 0000000..8d19ea9 --- /dev/null +++ b/packages/contracts/abis/main/StakingRewardController.json @@ -0,0 +1,527 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "fluid", + "type": "address", + "internalType": "contract ISuperToken" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "FLUID", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISuperToken" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approveLocker", + "inputs": [ + { + "name": "lockerAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getTaxAllocation", + "inputs": [], + "outputs": [ + { + "name": "stakerAllocationBP", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "liquidityProviderAllocationBP", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "lockerFactory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "lpDistributionPool", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "refreshTaxDistributionFlow", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLockerFactory", + "inputs": [ + { + "name": "lockerFactoryAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setTaxAllocation", + "inputs": [ + { + "name": "stakerAllocationBP", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "liquidityProviderAllocationBP", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setupLPDistributionPool", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "taxAllocation", + "inputs": [], + "outputs": [ + { + "name": "stakerAllocationBP", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "liquidityProviderAllocationBP", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "taxDistributionPool", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISuperfluidPool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateLiquidityProviderUnits", + "inputs": [ + { + "name": "lockerLiquidityBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateStakerUnits", + "inputs": [ + { + "name": "lockerStakedBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeTo", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LockerApproved", + "inputs": [ + { + "name": "approvedLocker", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LockerFactoryAddressUpdated", + "inputs": [ + { + "name": "newLockerFactoryAddress", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProgramManagerAddressUpdated", + "inputs": [ + { + "name": "newProgramManagerAddress", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SubsidyFlowRateUpdated", + "inputs": [ + { + "name": "newSubsidyFlowRate", + "type": "int96", + "indexed": true, + "internalType": "int96" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TaxAllocationUpdated", + "inputs": [ + { + "name": "stakerAllocationBP", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "liquidityProviderAllocationBP", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TaxDistributionFlowUpdated", + "inputs": [ + { + "name": "liquidityProviderFlowRate", + "type": "int96", + "indexed": false, + "internalType": "int96" + }, + { + "name": "stakerFlowRate", + "type": "int96", + "indexed": false, + "internalType": "int96" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UpdatedLiquidityProviderUnits", + "inputs": [ + { + "name": "liquidityProvider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "totalLiquidityProviderUnits", + "type": "uint128", + "indexed": true, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UpdatedStakersUnits", + "inputs": [ + { + "name": "staker", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "totalStakerUnits", + "type": "uint128", + "indexed": true, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, + { + "type": "error", + "name": "FailedInnerCall", + "inputs": [] + }, + { + "type": "error", + "name": "INVALID_PARAMETER", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "LP_DISTRIBUTION_POOL_ALREADY_SET", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_APPROVED_LOCKER", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_LOCKER_FACTORY", + "inputs": [] + }, + { + "type": "error", + "name": "NOT_PROGRAM_MANAGER", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "OwnableInvalidOwner", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OwnableUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SafeCastOverflowedIntDowncast", + "inputs": [ + { + "name": "bits", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "value", + "type": "int256", + "internalType": "int256" + } + ] + } +] diff --git a/packages/contracts/abis/token/OPBridgedSuperToken.json b/packages/contracts/abis/token/OPBridgedSuperToken.json new file mode 100644 index 0000000..0975b25 --- /dev/null +++ b/packages/contracts/abis/token/OPBridgedSuperToken.json @@ -0,0 +1,438 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "nativeBridge_", + "type": "address", + "internalType": "address" + }, + { + "name": "remoteToken_", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "fallback", + "stateMutability": "payable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "bridge", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "bridges", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "minterParams", + "type": "tuple", + "internalType": "struct IXERC20.BridgeParameters", + "components": [ + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ratePerSecond", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "currentLimit", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "burnerParams", + "type": "tuple", + "internalType": "struct IXERC20.BridgeParameters", + "components": [ + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ratePerSecond", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "currentLimit", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burningCurrentLimitOf", + "inputs": [ + { + "name": "bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burningMaxLimitOf", + "inputs": [ + { + "name": "bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "factory", + "type": "address", + "internalType": "contract ISuperTokenFactory" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "initialSupply", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeProxy", + "inputs": [ + { + "name": "initialAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mintingCurrentLimitOf", + "inputs": [ + { + "name": "bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mintingMaxLimitOf", + "inputs": [ + { + "name": "bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "remoteToken", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLimits", + "inputs": [ + { + "name": "bridge", + "type": "address", + "internalType": "address" + }, + { + "name": "mintingLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "burningLimit", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLockbox", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "BridgeLimitsSet", + "inputs": [ + { + "name": "_mintingLimit", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "_burningLimit", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "_bridge", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LockboxSet", + "inputs": [ + { + "name": "_lockbox", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "IXERC20_LimitsTooHigh", + "inputs": [] + }, + { + "type": "error", + "name": "IXERC20_NoLockBox", + "inputs": [] + }, + { + "type": "error", + "name": "IXERC20_NotHighEnoughLimits", + "inputs": [] + } +] diff --git a/packages/contracts/abis/token/SupToken.json b/packages/contracts/abis/token/SupToken.json new file mode 100644 index 0000000..c36a0dd --- /dev/null +++ b/packages/contracts/abis/token/SupToken.json @@ -0,0 +1,878 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "treasury", + "type": "address", + "internalType": "address" + }, + { + "name": "totalSupply", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "CLOCK_MODE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "checkpoints", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "pos", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct Checkpoints.Checkpoint208", + "components": [ + { + "name": "_key", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "_value", + "type": "uint208", + "internalType": "uint208" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "clock", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "delegate", + "inputs": [ + { + "name": "delegatee", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "delegateBySig", + "inputs": [ + { + "name": "delegatee", + "type": "address", + "internalType": "address" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "expiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "delegates", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "eip712Domain", + "inputs": [], + "outputs": [ + { + "name": "fields", + "type": "bytes1", + "internalType": "bytes1" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "version", + "type": "string", + "internalType": "string" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "verifyingContract", + "type": "address", + "internalType": "address" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "extensions", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPastTotalSupply", + "inputs": [ + { + "name": "timepoint", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPastVotes", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "timepoint", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getVotes", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "numCheckpoints", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint32", + "internalType": "uint32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalSupply", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "DelegateChanged", + "inputs": [ + { + "name": "delegator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "fromDelegate", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "toDelegate", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "DelegateVotesChanged", + "inputs": [ + { + "name": "delegate", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "previousVotes", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newVotes", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "EIP712DomainChanged", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "CheckpointUnorderedInsertion", + "inputs": [] + }, + { + "type": "error", + "name": "ECDSAInvalidSignature", + "inputs": [] + }, + { + "type": "error", + "name": "ECDSAInvalidSignatureLength", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ECDSAInvalidSignatureS", + "inputs": [ + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ERC20ExceededSafeSupply", + "inputs": [ + { + "name": "increasedSupply", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cap", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ERC20InsufficientAllowance", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "allowance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ERC20InsufficientBalance", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "balance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ERC20InvalidApprover", + "inputs": [ + { + "name": "approver", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC20InvalidReceiver", + "inputs": [ + { + "name": "receiver", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC20InvalidSender", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC20InvalidSpender", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC2612ExpiredSignature", + "inputs": [ + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ERC2612InvalidSigner", + "inputs": [ + { + "name": "signer", + "type": "address", + "internalType": "address" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC5805FutureLookup", + "inputs": [ + { + "name": "timepoint", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "clock", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "type": "error", + "name": "ERC6372InconsistentClock", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidAccountNonce", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "currentNonce", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidShortString", + "inputs": [] + }, + { + "type": "error", + "name": "SafeCastOverflowedUintDowncast", + "inputs": [ + { + "name": "bits", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "StringTooLong", + "inputs": [ + { + "name": "str", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "VotesExpiredSignature", + "inputs": [ + { + "name": "expiry", + "type": "uint256", + "internalType": "uint256" + } + ] + } +] diff --git a/packages/contracts/abis/token/SupTokenL2.json b/packages/contracts/abis/token/SupTokenL2.json new file mode 100644 index 0000000..0975b25 --- /dev/null +++ b/packages/contracts/abis/token/SupTokenL2.json @@ -0,0 +1,438 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "nativeBridge_", + "type": "address", + "internalType": "address" + }, + { + "name": "remoteToken_", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "fallback", + "stateMutability": "payable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "bridge", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "bridges", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "minterParams", + "type": "tuple", + "internalType": "struct IXERC20.BridgeParameters", + "components": [ + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ratePerSecond", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "currentLimit", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "burnerParams", + "type": "tuple", + "internalType": "struct IXERC20.BridgeParameters", + "components": [ + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "ratePerSecond", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "currentLimit", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burningCurrentLimitOf", + "inputs": [ + { + "name": "bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burningMaxLimitOf", + "inputs": [ + { + "name": "bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "factory", + "type": "address", + "internalType": "contract ISuperTokenFactory" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "initialSupply", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeProxy", + "inputs": [ + { + "name": "initialAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mintingCurrentLimitOf", + "inputs": [ + { + "name": "bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mintingMaxLimitOf", + "inputs": [ + { + "name": "bridge", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "limit", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "remoteToken", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLimits", + "inputs": [ + { + "name": "bridge", + "type": "address", + "internalType": "address" + }, + { + "name": "mintingLimit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "burningLimit", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLockbox", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "BridgeLimitsSet", + "inputs": [ + { + "name": "_mintingLimit", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "_burningLimit", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "_bridge", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LockboxSet", + "inputs": [ + { + "name": "_lockbox", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "IXERC20_LimitsTooHigh", + "inputs": [] + }, + { + "type": "error", + "name": "IXERC20_NoLockBox", + "inputs": [] + }, + { + "type": "error", + "name": "IXERC20_NotHighEnoughLimits", + "inputs": [] + } +] diff --git a/packages/contracts/abis/vesting/SupVesting.json b/packages/contracts/abis/vesting/SupVesting.json new file mode 100644 index 0000000..f0db370 --- /dev/null +++ b/packages/contracts/abis/vesting/SupVesting.json @@ -0,0 +1,125 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vestingScheduler", + "type": "address", + "internalType": "contract IVestingSchedulerV2" + }, + { + "name": "sup", + "type": "address", + "internalType": "contract ISuperToken" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "cliffDate", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "flowRate", + "type": "int96", + "internalType": "int96" + }, + { + "name": "cliffAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "endDate", + "type": "uint32", + "internalType": "uint32" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "FACTORY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISupVestingFactory" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "RECIPIENT", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SUP", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISuperToken" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "VESTING_SCHEDULER", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IVestingSchedulerV2" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "emergencyWithdraw", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "VestingDeleted", + "inputs": [ + { + "name": "transferredAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "CFA_INVALID_FLOW_RATE", + "inputs": [] + }, + { + "type": "error", + "name": "FORBIDDEN", + "inputs": [] + } +] diff --git a/packages/contracts/abis/vesting/SupVestingFactory.json b/packages/contracts/abis/vesting/SupVestingFactory.json new file mode 100644 index 0000000..cb9eca3 --- /dev/null +++ b/packages/contracts/abis/vesting/SupVestingFactory.json @@ -0,0 +1,331 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vestingScheduler", + "type": "address", + "internalType": "contract IVestingSchedulerV2" + }, + { + "name": "token", + "type": "address", + "internalType": "contract ISuperToken" + }, + { + "name": "treasuryAddress", + "type": "address", + "internalType": "address" + }, + { + "name": "adminAddress", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "MIN_CLIFF_PERIOD", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "SUP", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISuperToken" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "VESTING_SCHEDULER", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IVestingSchedulerV2" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "admin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "vestingReceiver", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "unvestedBalance", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "createSupVestingContract", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "recipientVestingIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cliffAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "cliffDate", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "endDate", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [ + { + "name": "newSupVestingContract", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "recipients", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "setAdmin", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setTreasury", + "inputs": [ + { + "name": "newTreasury", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supVestings", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "supVesting", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalSupply", + "inputs": [], + "outputs": [ + { + "name": "supply", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "treasury", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "SupVestingCreated", + "inputs": [ + { + "name": "recipient", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newSupVestingContract", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "FORBIDDEN", + "inputs": [] + }, + { + "type": "error", + "name": "VESTING_DUPLICATED", + "inputs": [] + } +] diff --git a/packages/contracts/foundry.toml b/packages/contracts/foundry.toml index 3ccd1e2..dd66855 100644 --- a/packages/contracts/foundry.toml +++ b/packages/contracts/foundry.toml @@ -1,5 +1,5 @@ [profile.default] -solc_version = "0.8.23" +solc_version = "0.8.24" src = "src" out = "out" libs = ["lib"] diff --git a/packages/contracts/lib/superfluid-protocol-monorepo b/packages/contracts/lib/superfluid-protocol-monorepo index 264d158..4e3bf87 160000 --- a/packages/contracts/lib/superfluid-protocol-monorepo +++ b/packages/contracts/lib/superfluid-protocol-monorepo @@ -1 +1 @@ -Subproject commit 264d158d4d5ce919c0467512c6153175d353e571 +Subproject commit 4e3bf877b6b7043a2ce1be17af5fd335d0a8018d diff --git a/packages/contracts/lib/swap-router-contracts b/packages/contracts/lib/swap-router-contracts new file mode 160000 index 0000000..c696aad --- /dev/null +++ b/packages/contracts/lib/swap-router-contracts @@ -0,0 +1 @@ +Subproject commit c696aada49b33c8e764e6f0bd0a0a56bd8aa455f diff --git a/packages/contracts/lib/uniswap-v3-core b/packages/contracts/lib/uniswap-v3-core new file mode 160000 index 0000000..6562c52 --- /dev/null +++ b/packages/contracts/lib/uniswap-v3-core @@ -0,0 +1 @@ +Subproject commit 6562c52e8f75f0c10f9deaf44861847585fc8129 diff --git a/packages/contracts/lib/uniswap-v3-periphery b/packages/contracts/lib/uniswap-v3-periphery new file mode 160000 index 0000000..b325bb0 --- /dev/null +++ b/packages/contracts/lib/uniswap-v3-periphery @@ -0,0 +1 @@ +Subproject commit b325bb0905d922ae61fcc7df85ee802e8df5e96c diff --git a/packages/contracts/remappings.txt b/packages/contracts/remappings.txt index 9584992..bc71826 100644 --- a/packages/contracts/remappings.txt +++ b/packages/contracts/remappings.txt @@ -4,3 +4,6 @@ @superfluid-finance/ethereum-contracts/=lib/superfluid-protocol-monorepo/packages/ethereum-contracts/ @superfluid-finance/solidity-semantic-money/=lib/superfluid-protocol-monorepo/packages/solidity-semantic-money/ @superfluid-finance/automation-contracts/=lib/superfluid-protocol-monorepo/packages/automation-contracts/ +@uniswap/v3-core/=lib/uniswap-v3-core/ +@uniswap/v3-periphery/=lib/uniswap-v3-periphery/ +@uniswap/swap-router-contracts/=lib/swap-router-contracts/ diff --git a/packages/contracts/script/Deploy.s.sol b/packages/contracts/script/Deploy.s.sol index 83debdf..0df905b 100644 --- a/packages/contracts/script/Deploy.s.sol +++ b/packages/contracts/script/Deploy.s.sol @@ -19,6 +19,11 @@ import { FluidLockerFactory } from "../src/FluidLockerFactory.sol"; import { Fontaine } from "../src/Fontaine.sol"; import { StakingRewardController, IStakingRewardController } from "../src/StakingRewardController.sol"; +/* Uniswap V3 Interfaces */ +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; +import { INonfungiblePositionManager } from "@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol"; +import { IV3SwapRouter } from "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol"; + struct DeploySettings { ISuperToken fluid; address governor; @@ -26,13 +31,16 @@ struct DeploySettings { address treasury; bool factoryPauseStatus; bool unlockStatus; + IV3SwapRouter swapRouter; + INonfungiblePositionManager nonfungiblePositionManager; + IUniswapV3Pool ethSupPool; } -function _deployFontaineBeacon(ISuperToken fluid, ISuperfluidPool taxDistributionPool, address governor) +function _deployFontaineBeacon(ISuperToken fluid, address governor) returns (address fontaineLogicAddress, address fontaineBeaconAddress) { // Deploy the Fontaine Implementation and associated Beacon contract - fontaineLogicAddress = address(new Fontaine(fluid, taxDistributionPool)); + fontaineLogicAddress = address(new Fontaine(fluid)); UpgradeableBeacon fontaineBeacon = new UpgradeableBeacon(fontaineLogicAddress); fontaineBeaconAddress = address(fontaineBeacon); @@ -42,7 +50,6 @@ function _deployFontaineBeacon(ISuperToken fluid, ISuperfluidPool taxDistributio function _deployLockerBeacon( DeploySettings memory settings, - ISuperfluidPool taxDistributionPool, address programManagerAddress, address stakingRewardControllerAddress, address fontaineBeaconAddress @@ -51,11 +58,13 @@ function _deployLockerBeacon( lockerLogicAddress = address( new FluidLocker( settings.fluid, - taxDistributionPool, IEPProgramManager(programManagerAddress), IStakingRewardController(stakingRewardControllerAddress), fontaineBeaconAddress, - settings.unlockStatus + settings.unlockStatus, + settings.nonfungiblePositionManager, + settings.ethSupPool, + settings.swapRouter ) ); UpgradeableBeacon lockerBeacon = new UpgradeableBeacon(lockerLogicAddress); @@ -75,7 +84,11 @@ function _deployStakingRewardController(ISuperToken fluid, address owner) ERC1967Proxy stakingRewardControllerProxy = new ERC1967Proxy( stakingRewardControllerLogicAddress, abi.encodeWithSelector(StakingRewardController.initialize.selector, owner) ); + stakingRewardControllerProxyAddress = address(stakingRewardControllerProxy); + + StakingRewardController(stakingRewardControllerProxyAddress).setupLPDistributionPool(); + StakingRewardController(stakingRewardControllerProxyAddress).setTaxAllocation(1000, 9000); } function _deployFluidEPProgramManager(address owner, address treasury, ISuperfluidPool taxDistributionPool) @@ -110,56 +123,63 @@ function _deployLockerFactory( lockerFactoryProxyAddress = address(lockerFactoryProxy); } -function _deployAll(DeploySettings memory settings) - returns ( - address programManagerLogicAddress, - address programManagerProxyAddress, - address stakingRewardControllerLogicAddress, - address stakingRewardControllerProxyAddress, - address lockerFactoryLogicAddress, - address lockerFactoryProxyAddress, - address lockerLogicAddress, - address lockerBeaconAddress, - address fontaineLogicAddress, - address fontaineBeaconAddress - ) -{ - (stakingRewardControllerLogicAddress, stakingRewardControllerProxyAddress) = +struct DeployedContracts { + address programManagerLogicAddress; + address programManagerProxyAddress; + address stakingRewardControllerLogicAddress; + address stakingRewardControllerProxyAddress; + address lockerFactoryLogicAddress; + address lockerFactoryProxyAddress; + address lockerLogicAddress; + address lockerBeaconAddress; + address fontaineLogicAddress; + address fontaineBeaconAddress; +} + +function _deployAll(DeploySettings memory settings) returns (DeployedContracts memory deployedContracts) { + (deployedContracts.stakingRewardControllerLogicAddress, deployedContracts.stakingRewardControllerProxyAddress) = _deployStakingRewardController(settings.fluid, settings.deployer); - ISuperfluidPool taxDistributionPool = - StakingRewardController(stakingRewardControllerProxyAddress).taxDistributionPool(); + ISuperfluidPool stakerDistributionPool = + StakingRewardController(deployedContracts.stakingRewardControllerProxyAddress).taxDistributionPool(); - // Deploy Ecosystem Partner Program Manager - (programManagerLogicAddress, programManagerProxyAddress) = - _deployFluidEPProgramManager(settings.deployer, settings.treasury, taxDistributionPool); + (deployedContracts.programManagerLogicAddress, deployedContracts.programManagerProxyAddress) = + _deployFluidEPProgramManager(settings.deployer, settings.treasury, stakerDistributionPool); // Deploy the Fontaine Implementation and associated Beacon contract - (fontaineLogicAddress, fontaineBeaconAddress) = - _deployFontaineBeacon(settings.fluid, taxDistributionPool, settings.governor); + (deployedContracts.fontaineLogicAddress, deployedContracts.fontaineBeaconAddress) = + _deployFontaineBeacon(settings.fluid, settings.governor); // Deploy the Fluid Locker Implementation and associated Beacon contract - (lockerLogicAddress, lockerBeaconAddress) = _deployLockerBeacon( + (deployedContracts.lockerLogicAddress, deployedContracts.lockerBeaconAddress) = _deployLockerBeacon( settings, - taxDistributionPool, - programManagerProxyAddress, - stakingRewardControllerProxyAddress, - fontaineBeaconAddress + deployedContracts.programManagerProxyAddress, + deployedContracts.stakingRewardControllerProxyAddress, + deployedContracts.fontaineBeaconAddress ); - (lockerFactoryLogicAddress, lockerFactoryProxyAddress) = _deployLockerFactory( - settings.factoryPauseStatus, settings.governor, lockerBeaconAddress, stakingRewardControllerProxyAddress + (deployedContracts.lockerFactoryLogicAddress, deployedContracts.lockerFactoryProxyAddress) = _deployLockerFactory( + settings.factoryPauseStatus, + settings.governor, + deployedContracts.lockerBeaconAddress, + deployedContracts.stakingRewardControllerProxyAddress ); // Sets the FluidLockerFactory address in the StakingRewardController - StakingRewardController(stakingRewardControllerProxyAddress).setLockerFactory(lockerFactoryProxyAddress); + StakingRewardController(deployedContracts.stakingRewardControllerProxyAddress).setLockerFactory( + deployedContracts.lockerFactoryProxyAddress + ); // Sets the FluidLockerFactory address in the ProgramManager - FluidEPProgramManager(programManagerProxyAddress).setLockerFactory(lockerFactoryProxyAddress); + FluidEPProgramManager(deployedContracts.programManagerProxyAddress).setLockerFactory( + deployedContracts.lockerFactoryProxyAddress + ); // Transfer ownership of the contracts to the governor - StakingRewardController(stakingRewardControllerProxyAddress).transferOwnership(settings.governor); - FluidEPProgramManager(programManagerProxyAddress).transferOwnership(settings.governor); + StakingRewardController(deployedContracts.stakingRewardControllerProxyAddress).transferOwnership(settings.governor); + FluidEPProgramManager(deployedContracts.programManagerProxyAddress).transferOwnership(settings.governor); + + return deployedContracts; } // forge script script/Deploy.s.sol:DeployScript --ffi --rpc-url $BASE_SEPOLIA_RPC_URL --broadcast --verify -vvvv @@ -181,6 +201,10 @@ contract DeployScript is Script { ISuperToken fluid = ISuperToken(vm.envAddress("FLUID_ADDRESS")); bool factoryPauseStatus = vm.envBool("PAUSE_FACTORY_LOCKER_CREATION"); bool unlockStatus = vm.envBool("FLUID_UNLOCK_STATUS"); + IV3SwapRouter swapRouter = IV3SwapRouter(vm.envAddress("SWAP_ROUTER_ADDRESS")); + INonfungiblePositionManager nonfungiblePositionManager = + INonfungiblePositionManager(vm.envAddress("NONFUNGIBLE_POSITION_MANAGER_ADDRESS")); + IUniswapV3Pool ethSupPool = IUniswapV3Pool(vm.envAddress("ETH_SUP_POOL_ADDRESS")); // Purposedly not enforcing this at contract level in case governance decides to forfeit ownership of the contracts if (governor == address(0)) { @@ -193,36 +217,28 @@ contract DeployScript is Script { deployer: deployer, treasury: treasury, factoryPauseStatus: factoryPauseStatus, - unlockStatus: unlockStatus + unlockStatus: unlockStatus, + swapRouter: swapRouter, + nonfungiblePositionManager: nonfungiblePositionManager, + ethSupPool: ethSupPool }); _logDeploymentSettings(deployer, address(fluid), governor, treasury, factoryPauseStatus, unlockStatus); vm.startBroadcast(deployerPrivateKey); - ( - address programManagerLogicAddress, - address programManagerProxyAddress, - address stakingRewardControllerLogicAddress, - address stakingRewardControllerProxyAddress, - address lockerFactoryLogicAddress, - address lockerFactoryProxyAddress, - address lockerLogicAddress, - address lockerBeaconAddress, - address fontaineLogicAddress, - address fontaineBeaconAddress - ) = _deployAll(settings); + DeployedContracts memory deployedContracts = _deployAll(settings); _logDeploymentSummary( - programManagerLogicAddress, - programManagerProxyAddress, - stakingRewardControllerLogicAddress, - stakingRewardControllerProxyAddress, - lockerFactoryLogicAddress, - lockerFactoryProxyAddress, - lockerLogicAddress, - lockerBeaconAddress, - fontaineLogicAddress, - fontaineBeaconAddress + deployedContracts.programManagerLogicAddress, + deployedContracts.programManagerProxyAddress, + deployedContracts.stakingRewardControllerLogicAddress, + deployedContracts.stakingRewardControllerProxyAddress, + deployedContracts.lockerFactoryLogicAddress, + deployedContracts.lockerFactoryProxyAddress, + deployedContracts.lockerLogicAddress, + deployedContracts.lockerBeaconAddress, + deployedContracts.fontaineLogicAddress, + deployedContracts.fontaineBeaconAddress ); } diff --git a/packages/contracts/script/upgrades/deploy-locker-impl.s.sol b/packages/contracts/script/upgrades/deploy-locker-impl.s.sol deleted file mode 100644 index f0f5946..0000000 --- a/packages/contracts/script/upgrades/deploy-locker-impl.s.sol +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.23; - -import { Script, console2 } from "forge-std/Script.sol"; - -import { IStakingRewardController } from "src/interfaces/IStakingRewardController.sol"; -import { IEPProgramManager } from "src/interfaces/IEPProgramManager.sol"; -import { ISuperToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.sol"; -import { - ISuperfluidPool, - ISuperToken -} from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; - -import { FluidLocker } from "src/FluidLocker.sol"; - -/* -Base Sepolia Deployment Command : - -SUP_ADDRESS=0xFd62b398DD8a233ad37156690631fb9515059d6A \ -TAX_DISTRIBUTION_POOL_ADDRESS=0xBed96F4cE618798C286eE8BF7586BD607d491Ce7 \ -PROGRAM_MANAGER_ADDRESS=0x71a1975A1009e48E0BF2f621B6835db5Ea1f7706 \ -STAKING_REWARD_CONTROLLER_ADDRESS=0x9FC0Bb109F3e733Bd84B30F8D89685b0304fC018 \ -FONTAINE_BEACON_ADDRESS=0xeBfA246A0BAd08A2A3ffB137ed75601AA41867dE \ -UNLOCK_STATUS=false \ -forge script script/upgrades/deploy-locker-impl.s.sol:DeployFluidLockerImplementation --ffi --rpc-url $BASE_SEPOLIA_RPC_URL --account TESTNET_DEPLOYER -vvv --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY - -Base Mainnet Deployment Command : - -SUP_ADDRESS=0xa69f80524381275A7fFdb3AE01c54150644c8792 \ -TAX_DISTRIBUTION_POOL_ADDRESS=0xF0f494f4BD2C3A6bF8b49E6f798875301d944C0A \ -PROGRAM_MANAGER_ADDRESS=0x1e32cf099992E9D3b17eDdDFFfeb2D07AED95C6a \ -STAKING_REWARD_CONTROLLER_ADDRESS=0xb19Ae25A98d352B36CED60F93db926247535048b \ -FONTAINE_BEACON_ADDRESS=0xA26FbA47Da24F7DF11b3E4CF60Dcf7D1691Ae47d \ -UNLOCK_STATUS=false \ -forge script script/upgrades/deploy-locker-impl.s.sol:DeployFluidLockerImplementation --ffi --rpc-url $BASE_MAINNET_RPC_URL --account SUP_DEPLOYER -vvv --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY -*/ -contract DeployFluidLockerImplementation is Script { - function _startBroadcast() internal returns (address deployer) { - vm.startBroadcast(); - - // This is the way to get deployer address in foundry: - (, deployer,) = vm.readCallers(); - } - - function _stopBroadcast() internal { - vm.stopBroadcast(); - } - - function run() public { - _showGitRevision(); - - address deployer = _startBroadcast(); - - ISuperToken sup = ISuperToken(vm.envAddress("SUP_ADDRESS")); - ISuperfluidPool taxDistributionPool = ISuperfluidPool(vm.envAddress("TAX_DISTRIBUTION_POOL_ADDRESS")); - IEPProgramManager programManager = IEPProgramManager(vm.envAddress("PROGRAM_MANAGER_ADDRESS")); - IStakingRewardController stakingRewardController = - IStakingRewardController(vm.envAddress("STAKING_REWARD_CONTROLLER_ADDRESS")); - address fontaineBeaconAddress = vm.envAddress("FONTAINE_BEACON_ADDRESS"); - bool isUnlockAvailable = vm.envBool("UNLOCK_STATUS"); - - address lockerLogicAddress = address( - new FluidLocker( - sup, - taxDistributionPool, - programManager, - stakingRewardController, - fontaineBeaconAddress, - isUnlockAvailable - ) - ); - - _stopBroadcast(); - - console2.log("DEPLOYING SPR CONTRACTS UPGRADE .........."); - console2.log(""); - console2.log(""); - console2.log("*----------------------------------* DEPLOYMENT SETTINGS *---------------------------------*"); - console2.log("| "); - console2.log("| DEPLOYER : %s", deployer); - console2.log("| SUP_ADDRESS : %s", address(sup)); - console2.log("| TAX_DISTRIBUTION_POOL_ADDRESS : %s", address(taxDistributionPool)); - console2.log("| PROGRAM_MANAGER_ADDRESS : %s", address(programManager)); - console2.log("| STAKING_REWARD_CONTROLLER_ADDRESS : %s", address(stakingRewardController)); - console2.log("| FONTAINE_BEACON_ADDRESS : %s", fontaineBeaconAddress); - console2.log("| IS_UNLOCK_AVAILABLE : %s", isUnlockAvailable); - console2.log("*------------------------------------------------------------------------------------------*"); - - console2.log(""); - console2.log("*----------------------------------* DEPLOYMENT SUMMARY *----------------------------------*"); - console2.log("| |"); - console2.log("| FluidLocker (Logic) : deployed at %s |", lockerLogicAddress); - console2.log("*------------------------------------------------------------------------------------------*"); - } - - function _showGitRevision() internal { - string[] memory inputs = new string[](2); - inputs[0] = "../tasks/show-git-rev.sh"; - inputs[1] = "forge_ffi_mode"; - try vm.ffi(inputs) returns (bytes memory res) { - console2.log("GIT REVISION : %s", string(res)); - } catch { - console2.log("!! _showGitRevision: FFI not enabled"); - } - } -} diff --git a/packages/contracts/script/upgrades/deploy-tte.s.sol b/packages/contracts/script/upgrades/deploy-tte.s.sol new file mode 100644 index 0000000..667d31c --- /dev/null +++ b/packages/contracts/script/upgrades/deploy-tte.s.sol @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { Script, console2 } from "forge-std/Script.sol"; + +import { IStakingRewardController } from "src/interfaces/IStakingRewardController.sol"; +import { IEPProgramManager } from "src/interfaces/IEPProgramManager.sol"; +import { ISuperToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.sol"; +import { + ISuperfluidPool, + ISuperToken +} from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; +import { INonfungiblePositionManager } from "@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol"; +import { IV3SwapRouter } from "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol"; + +import { FluidLocker } from "src/FluidLocker.sol"; +import { FluidLockerFactory } from "src/FluidLockerFactory.sol"; +import { Fontaine } from "src/Fontaine.sol"; +import { StakingRewardController } from "src/StakingRewardController.sol"; + +/* +Base Sepolia Deployment Command : +PART_I : + +LOCKER_BEACON_ADDRESS=0xf2880c6D68080393C1784f978417a96ab4f37c38 \ +STAKING_REWARD_CONTROLLER_ADDRESS=0x9FC0Bb109F3e733Bd84B30F8D89685b0304fC018 \ +SUP_ADDRESS=0xFd62b398DD8a233ad37156690631fb9515059d6A \ +PAUSE_FACTORY_LOCKER_CREATION=false \ +forge script script/upgrades/deploy-tte.s.sol:DeployTTE_PART_I --ffi --rpc-url $BASE_SEPOLIA_RPC_URL --account TESTNET_DEPLOYER -vvv --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY + + +PART_II : + +PROGRAM_MANAGER_ADDRESS=0x71a1975A1009e48E0BF2f621B6835db5Ea1f7706 \ +STAKING_REWARD_CONTROLLER_ADDRESS=0x9FC0Bb109F3e733Bd84B30F8D89685b0304fC018 \ +SUP_ADDRESS=0xFd62b398DD8a233ad37156690631fb9515059d6A \ +FONTAINE_BEACON_ADDRESS=0xeBfA246A0BAd08A2A3ffB137ed75601AA41867dE \ +UNLOCK_STATUS=true \ +NONFUNGIBLE_POSITION_MANAGER_ADDRESS=0x27F971cb582BF9E50F397e4d29a5C7A34f11faA2 \ +ETH_SUP_POOL_ADDRESS=0x46aEd46BabdF0eb941160D32A859E24Df83758f8 \ +SWAP_ROUTER_ADDRESS=0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4 \ +forge script script/upgrades/deploy-tte.s.sol:DeployTTE_PART_II --ffi --rpc-url $BASE_SEPOLIA_RPC_URL --account TESTNET_DEPLOYER -vvv --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY + + +Base Mainnet Deployment Command : + +PART_I : + +SUP_ADDRESS=0xa69f80524381275A7fFdb3AE01c54150644c8792 \ +TAX_DISTRIBUTION_POOL_ADDRESS=0xF0f494f4BD2C3A6bF8b49E6f798875301d944C0A \ +PROGRAM_MANAGER_ADDRESS=0x1e32cf099992E9D3b17eDdDFFfeb2D07AED95C6a \ +STAKING_REWARD_CONTROLLER_ADDRESS=0xb19Ae25A98d352B36CED60F93db926247535048b \ +FONTAINE_BEACON_ADDRESS=0xA26FbA47Da24F7DF11b3E4CF60Dcf7D1691Ae47d \ +UNLOCK_STATUS=false \ +forge script script/upgrades/deploy-locker-impl.s.sol:DeployFluidLockerImplementation --ffi --rpc-url $BASE_MAINNET_RPC_URL --account SUP_DEPLOYER -vvv --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY + +PART_II : + + +*/ + +contract DeployTTE is Script { + function _startBroadcast() internal returns (address deployer) { + vm.startBroadcast(); + + // This is the way to get deployer address in foundry: + (, deployer,) = vm.readCallers(); + } + + function _stopBroadcast() internal { + vm.stopBroadcast(); + } + + function _showGitRevision() internal { + string[] memory inputs = new string[](2); + inputs[0] = "../tasks/show-git-rev.sh"; + inputs[1] = "forge_ffi_mode"; + try vm.ffi(inputs) returns (bytes memory res) { + console2.log("GIT REVISION : %s", string(res)); + } catch { + console2.log("!! _showGitRevision: FFI not enabled"); + } + } +} + +contract DeployTTE_PART_I is DeployTTE { + function run() public { + _showGitRevision(); + + // FluidLockerFactory Deployment Parameters : + address lockerBeaconAddress = vm.envAddress("LOCKER_BEACON_ADDRESS"); + address stakingRewardControllerProxyAddress = vm.envAddress("STAKING_REWARD_CONTROLLER_ADDRESS"); + bool pauseStatus = vm.envBool("PAUSE_FACTORY_LOCKER_CREATION"); + + // Fontaine & StakingRewardController Deployment Parameters : + ISuperToken sup = ISuperToken(vm.envAddress("SUP_ADDRESS")); + + // Start Deployment : + address deployer = _startBroadcast(); + + address newFluidLockerFactoryLogicAddress = address( + new FluidLockerFactory( + lockerBeaconAddress, IStakingRewardController(stakingRewardControllerProxyAddress), pauseStatus + ) + ); + address newFontaineLogicAddress = address(new Fontaine(sup)); + address newStakingRewardControllerLogicAddress = address(new StakingRewardController(sup)); + + _stopBroadcast(); + + console2.log("DEPLOYING SPR V1.1 PART I CONTRACTS UPGRADE .........."); + console2.log(""); + console2.log(""); + console2.log("*----------------------------------* DEPLOYMENT SETTINGS *---------------------------------*"); + console2.log("| "); + console2.log("| DEPLOYER : %s", deployer); + console2.log("| SUP_ADDRESS : %s", address(sup)); + console2.log("| LOCKER_BEACON_ADDRESS : %s", lockerBeaconAddress); + console2.log("| STAKING_REWARD_CONTROLLER_PROXY : %s", address(stakingRewardControllerProxyAddress)); + console2.log("| LOCKER_FACTORY_PAUSE_STATUS : %s", pauseStatus); + console2.log("*------------------------------------------------------------------------------------------*"); + + console2.log(""); + console2.log("*----------------------------------* DEPLOYMENT SUMMARY *----------------------------------*"); + console2.log("| |"); + console2.log("| FluidLockerFactory (Logic) : deployed at %s |", newFluidLockerFactoryLogicAddress); + console2.log("| StakingRewardController (Logic) : deployed at %s |", newStakingRewardControllerLogicAddress); + console2.log("| Fontaine (Logic) : deployed at %s |", newFontaineLogicAddress); + console2.log("*------------------------------------------------------------------------------------------*"); + console2.log(""); + + console2.log(""); + console2.log("*----------------------------------* FOLLOWUP INSTRUCTIONS *-------------------------------*"); + console2.log("| |"); + console2.log("| Request DAO Multisig to upgrade following contracts : |"); + console2.log("| - FluidLockerFactory proxy |"); + console2.log("| - StakingRewardController proxy |"); + console2.log("| - Fontaine Beacon |"); + console2.log("| |"); + console2.log("| Request DAO Multisig to create the `LP_DISTRIBUTION_POOL` and set Tax Allocation : |"); + console2.log("| - call `StakingRewardController::setupLPDistributionPool` |"); + console2.log("| - call `StakingRewardController::setTaxAllocation` |"); + console2.log("| |"); + console2.log("*------------------------------------------------------------------------------------------*"); + } +} + +contract DeployTTE_PART_II is DeployTTE { + function run() public { + _showGitRevision(); + + ISuperToken sup = ISuperToken(vm.envAddress("SUP_ADDRESS")); + IEPProgramManager programManager = IEPProgramManager(vm.envAddress("PROGRAM_MANAGER_ADDRESS")); + IStakingRewardController stakingRewardController = + IStakingRewardController(vm.envAddress("STAKING_REWARD_CONTROLLER_ADDRESS")); + address fontaineBeaconAddress = vm.envAddress("FONTAINE_BEACON_ADDRESS"); + bool isUnlockAvailable = vm.envBool("UNLOCK_STATUS"); + INonfungiblePositionManager nonfungiblePositionManager = + INonfungiblePositionManager(vm.envAddress("NONFUNGIBLE_POSITION_MANAGER_ADDRESS")); + IUniswapV3Pool ethSupPool = IUniswapV3Pool(vm.envAddress("ETH_SUP_POOL_ADDRESS")); + IV3SwapRouter swapRouter = IV3SwapRouter(vm.envAddress("SWAP_ROUTER_ADDRESS")); + + // Start Deployment : + address deployer = _startBroadcast(); + + address newFluidLockerLogicAddress = address( + new FluidLocker( + sup, + programManager, + stakingRewardController, + fontaineBeaconAddress, + isUnlockAvailable, + nonfungiblePositionManager, + ethSupPool, + swapRouter + ) + ); + + _stopBroadcast(); + + console2.log("DEPLOYING SPR CONTRACTS UPGRADE .........."); + console2.log(""); + console2.log(""); + console2.log("*----------------------------------* DEPLOYMENT SETTINGS *---------------------------------*"); + console2.log("| "); + console2.log("| DEPLOYER : %s", deployer); + console2.log("| SUP_ADDRESS : %s", address(sup)); + console2.log("| PROGRAM_MANAGER_ADDRESS : %s", address(programManager)); + console2.log("| STAKING_REWARD_CONTROLLER_ADDRESS : %s", address(stakingRewardController)); + console2.log("| FONTAINE_BEACON_ADDRESS : %s", fontaineBeaconAddress); + console2.log("| IS_UNLOCK_AVAILABLE : %s", isUnlockAvailable); + console2.log("| NONFUNGIBLE_POSITION_MANAGER_ADDRESS: %s", address(nonfungiblePositionManager)); + console2.log("| ETH_SUP_POOL_ADDRESS : %s", address(ethSupPool)); + console2.log("| SWAP_ROUTER_ADDRESS : %s", address(swapRouter)); + console2.log("| "); + console2.log("*------------------------------------------------------------------------------------------*"); + + console2.log(""); + console2.log("*----------------------------------* DEPLOYMENT SUMMARY *----------------------------------*"); + console2.log("| |"); + console2.log("| FluidLocker (Logic) : deployed at %s |", newFluidLockerLogicAddress); + console2.log("*------------------------------------------------------------------------------------------*"); + console2.log(""); + + console2.log(""); + console2.log("*----------------------------------* FOLLOWUP INSTRUCTIONS *-------------------------------*"); + console2.log("| |"); + console2.log("| Request DAO Multisig to upgrade following contract : |"); + console2.log("| - FluidLocker Beacon |"); + console2.log("| |"); + console2.log("*------------------------------------------------------------------------------------------*"); + } +} diff --git a/packages/contracts/src/FluidLocker.sol b/packages/contracts/src/FluidLocker.sol index 1e9c22b..35c9e39 100644 --- a/packages/contracts/src/FluidLocker.sol +++ b/packages/contracts/src/FluidLocker.sol @@ -32,6 +32,9 @@ import { SafeCast } from "@openzeppelin-v5/contracts/utils/math/SafeCast.sol"; import { Initializable } from "@openzeppelin-v5/contracts/proxy/utils/Initializable.sol"; import { BeaconProxy } from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; import { UpgradeableBeacon } from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; +import { IERC20 } from "@openzeppelin-v5/contracts/token/ERC20/IERC20.sol"; +import { ReentrancyGuard } from "solady/utils/ReentrancyGuard.sol"; +import { IWETH9 } from "./token/IWETH9.sol"; /* Superfluid Protocol Contracts & Interfaces */ import { @@ -46,7 +49,12 @@ import { IFluidLocker } from "./interfaces/IFluidLocker.sol"; import { IStakingRewardController } from "./interfaces/IStakingRewardController.sol"; import { IFontaine } from "./interfaces/IFontaine.sol"; -import { ReentrancyGuard } from "solady/utils/ReentrancyGuard.sol"; +/* Uniswap V3 Interfaces */ +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; +import { INonfungiblePositionManager } from "@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol"; +import { IV3SwapRouter } from "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol"; +import { TransferHelper } from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; +import { TickMath } from "@uniswap/v3-core/contracts/libraries/TickMath.sol"; using SuperTokenV1Library for ISuperToken; using SafeCast for int256; @@ -57,15 +65,12 @@ uint256 constant BP_DENOMINATOR = 10_000; /// @dev Scaler used for unlock percentage calculation uint256 constant UNLOCKING_PCT_SCALER = 1e18; -function calculateVestUnlockFlowRates(uint256 amountToUnlock, uint128 unlockPeriod) +function calculateVestUnlockAmounts(uint256 totalAmountToUnlock, uint128 unlockPeriod) pure - returns (int96 unlockFlowRate, int96 taxFlowRate) + returns (uint256 userUnlockAmount, uint256 taxAmount) { - int96 globalFlowRate = int256(amountToUnlock / unlockPeriod).toInt96(); - - unlockFlowRate = - (globalFlowRate * int256(getUnlockingPercentage(unlockPeriod))).toInt96() / int256(BP_DENOMINATOR).toInt96(); - taxFlowRate = globalFlowRate - unlockFlowRate; + userUnlockAmount = Math.mulDiv(totalAmountToUnlock, getUnlockingPercentage(unlockPeriod), BP_DENOMINATOR); + taxAmount = totalAmountToUnlock - userUnlockAmount; } function getUnlockingPercentage(uint128 unlockPeriod) pure returns (uint256 unlockingPercentageBP) { @@ -91,7 +96,10 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { ISuperToken public immutable FLUID; /// @notice Superfluid GDA Tax Distribution Pool interface - ISuperfluidPool public immutable TAX_DISTRIBUTION_POOL; + ISuperfluidPool public immutable STAKER_DISTRIBUTION_POOL; + + /// @notice Superfluid GDA Provider Distribution Pool interface + ISuperfluidPool public immutable LP_DISTRIBUTION_POOL; /// @notice Distribution Program Manager interface IEPProgramManager public immutable EP_PROGRAM_MANAGER; @@ -106,7 +114,10 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { bool public immutable UNLOCK_AVAILABLE; /// @notice Staking cooldown period - uint80 private constant _STAKING_COOLDOWN_PERIOD = 3 days; + uint80 private constant _STAKING_COOLDOWN_PERIOD = 30 days; + + /// @notice LP cooldown period + uint80 private constant _LP_COOLDOWN_PERIOD = 7 days; /// @notice Minimum unlock period allowed (1 week) uint128 private constant _MIN_UNLOCK_PERIOD = 7 days; @@ -120,6 +131,30 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { /// @notice Scaler used for unlock percentage calculation uint256 private constant _PERCENT_TO_BP = 100; + /// @notice Uniswap V3 Router interface + IV3SwapRouter public immutable SWAP_ROUTER; + + /// @notice Uniswap V3 Nonfungible Position Manager interface + INonfungiblePositionManager public immutable NONFUNGIBLE_POSITION_MANAGER; + + /// @notice ETH/SUP Uniswap V3 Pool interface + IUniswapV3Pool public immutable ETH_SUP_POOL; + + /// @notice Pump percentage (expressed in basis points) + uint256 public constant BP_PUMP_RATIO = 100; // 1% + + /// @notice Slippage tolerance (expressed in basis points) + uint256 public constant BP_SLIPPAGE_TOLERANCE = 500; // 5% + + /// @notice Liquidity operation deadline + uint256 public constant LP_OPERATION_DEADLINE = 1 minutes; + + /// @notice Tax free withdraw delay + uint256 public constant TAX_FREE_WITHDRAW_DELAY = 180 days; + + /// @notice Minimum SUP unlock amount + uint256 public constant MIN_UNLOCK_AMOUNT = 10 ether; + // _____ __ __ // / ___// /_____ _/ /____ _____ // \__ \/ __/ __ `/ __/ _ \/ ___/ @@ -141,6 +176,23 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { /// @notice Stores the Fontaine contract associated to the given unlock identifier mapping(uint256 unlockId => IFontaine fontaine) public fontaines; + // _ __ ___ _____ __ __ + // | | / /|__ \ / ___// /_____ _/ /____ _____ + // | | / /__/ / \__ \/ __/ __ `/ __/ _ \/ ___/ + // | |/ // __/ ___/ / /_/ /_/ / /_/ __(__ ) + // |___//____/ /____/\__/\__,_/\__/\___/____/ + + uint256 public activePositionCount; + + /// @notice Stores the tax free withdraw timestamp for a given position token identifier + mapping(uint256 positionTokenId => uint256 taxFreeWithdrawTimestamp) public taxFreeExitTimestamps; + + /// @notice Stores the LP cooldown timestamp for a given position token identifier + mapping(uint256 positionTokenId => uint256 lpCooldownTimestamp) public lpCooldownTimestamps; + + /// @notice Aggregated liquidity balance provided by this locker + uint256 private _liquidityBalance; + // ______ __ __ // / ____/___ ____ _____/ /________ _______/ /_____ _____ // / / / __ \/ __ \/ ___/ __/ ___/ / / / ___/ __/ __ \/ ___/ @@ -150,19 +202,23 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { /** * @notice Locker contract constructor * @param fluid FLUID SuperToken contract interface - * @param taxDistributionPool Tax Distribution Pool GDA contract interface * @param programManager Ecosystem Partner Program Manager contract interface * @param stakingRewardController Staking Reward Controller contract interface * @param fontaineBeacon Fontaine Beacon contract address * @param isUnlockAvailable True if the unlock is available, false otherwise + * @param nonfungiblePositionManager Nonfungible Position Manager contract interface + * @param ethSupPool ETH/SUP Uniswap V3 Pool contract interface + * @param swapRouter Uniswap V3 Swap Router contract interface */ constructor( ISuperToken fluid, - ISuperfluidPool taxDistributionPool, IEPProgramManager programManager, IStakingRewardController stakingRewardController, address fontaineBeacon, - bool isUnlockAvailable + bool isUnlockAvailable, + INonfungiblePositionManager nonfungiblePositionManager, + IUniswapV3Pool ethSupPool, + IV3SwapRouter swapRouter ) { // Disable initializers to prevent implementation contract initalization _disableInitializers(); @@ -170,12 +226,17 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { // Sets immutable states UNLOCK_AVAILABLE = isUnlockAvailable; FLUID = fluid; - TAX_DISTRIBUTION_POOL = taxDistributionPool; EP_PROGRAM_MANAGER = programManager; STAKING_REWARD_CONTROLLER = stakingRewardController; + LP_DISTRIBUTION_POOL = stakingRewardController.lpDistributionPool(); + STAKER_DISTRIBUTION_POOL = stakingRewardController.taxDistributionPool(); // Sets the Fontaine beacon address FONTAINE_BEACON = UpgradeableBeacon(fontaineBeacon); + + SWAP_ROUTER = swapRouter; + NONFUNGIBLE_POSITION_MANAGER = nonfungiblePositionManager; + ETH_SUP_POOL = ethSupPool; } /** @@ -193,6 +254,9 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { // / /____> _MAX_UNLOCK_PERIOD)) { revert INVALID_UNLOCK_PERIOD(); } + // Enforce unlock amount validity + if (unlockAmount < MIN_UNLOCK_AMOUNT) { + revert INSUFFICIENT_UNLOCK_AMOUNT(); + } + // Ensure recipient is not the zero-address if (recipient == address(0)) { revert FORBIDDEN(); } - // Ensure that the tax distribution pools has at least one unit distributed - if (TAX_DISTRIBUTION_POOL.getTotalUnits() == 0) { - revert TAX_DISTRIBUTION_POOL_HAS_NO_UNITS(); + // Ensure that the unlock amount is not greater than the available balance + if (unlockAmount > getAvailableBalance()) { + revert INSUFFICIENT_AVAILABLE_BALANCE(); } - // Get balance available for unlocking - uint256 availableBalance = getAvailableBalance(); + // Check if there will be a tax distribution event + if (unlockPeriod < _MAX_UNLOCK_PERIOD) { + (uint256 stakerAllocation, uint256 providerAllocation) = STAKING_REWARD_CONTROLLER.getTaxAllocation(); + + // Ensure that the tax distribution pools have at least one unit distributed (if the tax allocation is greater than 0) + if (STAKER_DISTRIBUTION_POOL.getTotalUnits() == 0 && stakerAllocation > 0) { + revert STAKER_DISTRIBUTION_POOL_HAS_NO_UNITS(); + } - // Revert if there is no FLUID to unlock - if (availableBalance == 0) revert NO_FLUID_TO_UNLOCK(); + if (LP_DISTRIBUTION_POOL.getTotalUnits() == 0 && providerAllocation > 0) { + revert LP_DISTRIBUTION_POOL_HAS_NO_UNITS(); + } + } if (unlockPeriod == 0) { - _instantUnlock(availableBalance, recipient); + _instantUnlock(unlockAmount, recipient); } else { - _vestUnlock(availableBalance, unlockPeriod, recipient); + _vestUnlock(unlockAmount, unlockPeriod, recipient); } } /// @inheritdoc IFluidLocker - function stake() external nonReentrant onlyLockerOwner unlockAvailable { - uint256 amountToStake = getAvailableBalance(); + function stake(uint256 amountToStake) external nonReentrant onlyLockerOwner unlockAvailable { + if (amountToStake > getAvailableBalance()) revert INSUFFICIENT_AVAILABLE_BALANCE(); - if (amountToStake == 0) revert NO_FLUID_TO_STAKE(); - - if (!FLUID.isMemberConnected(address(TAX_DISTRIBUTION_POOL), address(this))) { + if (!FLUID.isMemberConnected(address(STAKER_DISTRIBUTION_POOL), address(this))) { // Connect this locker to the Tax Distribution Pool - FLUID.connectPool(TAX_DISTRIBUTION_POOL); + FLUID.connectPool(STAKER_DISTRIBUTION_POOL); } // Update staked balance @@ -273,24 +353,12 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { } /// @inheritdoc IFluidLocker - function unstake() external nonReentrant onlyLockerOwner unlockAvailable { + function unstake(uint256 amountToUnstake) external nonReentrant onlyLockerOwner unlockAvailable { if (block.timestamp < stakingUnlocksAt) { revert STAKING_COOLDOWN_NOT_ELAPSED(); } - // Enfore staked balance is not zero - if (_stakedBalance == 0) revert NO_FLUID_TO_UNSTAKE(); - - // Set staked balance to 0 - _stakedBalance = 0; - - // Call Staking Reward Controller to update staker's units - STAKING_REWARD_CONTROLLER.updateStakerUnits(0); - - // Disconnect this locker from the Tax Distribution Pool - FLUID.disconnectPool(TAX_DISTRIBUTION_POOL); - - emit FluidUnstaked(); + _unstake(amountToUnstake); } /// @inheritdoc IFluidLocker @@ -316,6 +384,124 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { } } + /// @inheritdoc IFluidLocker + function provideLiquidity(uint256 supAmount) external payable nonReentrant onlyLockerOwner unlockAvailable { + address weth = NONFUNGIBLE_POSITION_MANAGER.WETH9(); + + uint256 ethAmount = msg.value; + + // Wrap ETH into WETH + IWETH9(weth).deposit{ value: ethAmount }(); + + uint256 ethPumpAmount = ethAmount * BP_PUMP_RATIO / BP_DENOMINATOR; + + // Pumponomics (market buy SUP with 1% of the provided paired asset) + _pump(weth, ethPumpAmount); + + uint256 availableBalance = getAvailableBalance(); + + // Check if the locker has enough available balance to provide desired liquidity + if (availableBalance < supAmount) { + uint256 shortage = supAmount - availableBalance; + + // If not, check if the locker has enough staked balance to compensate for the shortage + if (_stakedBalance < shortage) { + revert INSUFFICIENT_AVAILABLE_BALANCE(); + } else { + // Forcefully unstake the shortage amount to provide liquidity (discards the cooldown period) + _unstake(shortage); + } + } + + // Get the amount of paired asset tokens in the locker + uint256 ethLPAmount = ethAmount - ethPumpAmount; + + // Approve the locker to spend the paired asset and the $SUP tokens + TransferHelper.safeApprove(weth, address(NONFUNGIBLE_POSITION_MANAGER), ethLPAmount); + TransferHelper.safeApprove(address(FLUID), address(NONFUNGIBLE_POSITION_MANAGER), supAmount); + + // Create a new Uniswap V3 position + (uint256 positionTokenId,,) = _createPosition(ethLPAmount, supAmount); + + lpCooldownTimestamps[positionTokenId] = uint80(block.timestamp) + _LP_COOLDOWN_PERIOD; + + activePositionCount++; + + // Emit the Liquidity Position Created event + emit LiquidityPositionCreated(positionTokenId); + } + + /// @inheritdoc IFluidLocker + function withdrawLiquidity( + uint256 tokenId, + uint128 liquidityToRemove, + uint256 amount0ToRemove, + uint256 amount1ToRemove + ) external nonReentrant onlyLockerOwner unlockAvailable { + // ensure the locker has a position + if (!_positionExists(tokenId)) { + revert LOCKER_HAS_NO_POSITION(); + } + + // Enforce LP cooldown + if (block.timestamp < lpCooldownTimestamps[tokenId]) { + revert LP_COOLDOWN_NOT_ELAPSED(); + } + + // Collect the fees + _collect(tokenId, lockerOwner); + + address weth = NONFUNGIBLE_POSITION_MANAGER.WETH9(); + + (,,,,,,, uint128 positionLiquidity,,,,) = NONFUNGIBLE_POSITION_MANAGER.positions(tokenId); + + (, uint256 withdrawnSup) = _decreasePosition(tokenId, liquidityToRemove, amount0ToRemove, amount1ToRemove); + + // Unwrap the withdrawn WETH + IWETH9(weth).withdraw(IERC20(weth).balanceOf(address(this))); + + // Transfer ETH to the locker owner + TransferHelper.safeTransferETH(lockerOwner, address(this).balance); + + if (block.timestamp >= taxFreeExitTimestamps[tokenId]) { + TransferHelper.safeTransfer(address(FLUID), lockerOwner, withdrawnSup); + } + + // Burn the position and delete position tokenId if all liquidity is removed + if (liquidityToRemove == positionLiquidity) { + delete taxFreeExitTimestamps[tokenId]; + activePositionCount--; + NONFUNGIBLE_POSITION_MANAGER.burn(tokenId); + emit LiquidityPositionBurned(tokenId); + } + } + + /// @inheritdoc IFluidLocker + function collectFees(uint256 tokenId) + external + nonReentrant + onlyLockerOwner + unlockAvailable + returns (uint256 collectedWeth, uint256 collectedSup) + { + // ensure the locker has a position + if (!_positionExists(tokenId)) revert LOCKER_HAS_NO_POSITION(); + + if (ETH_SUP_POOL.token0() == address(FLUID)) { + // Collect the fees + (collectedSup, collectedWeth) = _collect(tokenId, lockerOwner); + } else { + // Collect the fees + (collectedWeth, collectedSup) = _collect(tokenId, lockerOwner); + } + } + + /// @inheritdoc IFluidLocker + function withdrawDustETH() external onlyLockerOwner { + // Transfer ETH to the locker owner + TransferHelper.safeTransferETH(lockerOwner, address(this).balance); + } + /// @inheritdoc IFluidLocker function disconnectAndClaim( uint256[] memory programIdsToDisconnect, @@ -378,6 +564,11 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { sBalance = _stakedBalance; } + /// @inheritdoc IFluidLocker + function getLiquidityBalance() public view returns (uint256 lBalance) { + lBalance = _liquidityBalance; + } + /// @inheritdoc IFluidLocker function getAvailableBalance() public view returns (uint256 aBalance) { aBalance = FLUID.balanceOf(address(this)) - _stakedBalance; @@ -388,6 +579,11 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { fontaineBeaconImpl = FONTAINE_BEACON.implementation(); } + /// @inheritdoc IFluidLocker + function getPositionLiquidity(uint256 tokenId) public view returns (uint128 liquidity) { + (,,,,,,, liquidity,,,,) = NONFUNGIBLE_POSITION_MANAGER.positions(tokenId); + } + // ____ __ __ ______ __ _ // / _/___ / /____ _________ ____ _/ / / ____/_ ______ _____/ /_(_)___ ____ _____ // / // __ \/ __/ _ \/ ___/ __ \/ __ `/ / / /_ / / / / __ \/ ___/ __/ / __ \/ __ \/ ___/ @@ -431,6 +627,26 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { emit IFluidLocker.FluidStreamsClaimed(programIds, totalProgramUnits); } + function _unstake(uint256 amountToUnstake) internal { + // Enforce amount to unstake is not greater than the staked balance + if (amountToUnstake > _stakedBalance) { + revert INSUFFICIENT_STAKED_BALANCE(); + } + + // Update the staked balance + _stakedBalance -= amountToUnstake; + + // Call Staking Reward Controller to update staker's units + STAKING_REWARD_CONTROLLER.updateStakerUnits(_stakedBalance); + + if (_stakedBalance == 0) { + // Disconnect this locker from the Tax Distribution Pool + FLUID.disconnectPool(STAKER_DISTRIBUTION_POOL); + } + + emit FluidUnstaked(); + } + function _disconnectFromPool(uint256 programId) internal { // Get the corresponding program pool ISuperfluidPool programPool = EP_PROGRAM_MANAGER.getProgramPool(programId); @@ -441,20 +657,23 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { function _instantUnlock(uint256 amountToUnlock, address recipient) internal { // Calculate instant unlock penalty amount - uint256 penaltyAmount = (amountToUnlock * _INSTANT_UNLOCK_PENALTY_BP) / BP_DENOMINATOR; + uint256 taxAmount = Math.mulDiv(amountToUnlock, _INSTANT_UNLOCK_PENALTY_BP, BP_DENOMINATOR); + + // Transfer the tax amount to the Staking Reward Controller + FLUID.transfer(address(STAKING_REWARD_CONTROLLER), taxAmount); - // Distribute penalty to staker (connected to the TAX_DISTRIBUTION_POOL) - FLUID.distribute(address(this), TAX_DISTRIBUTION_POOL, penaltyAmount); + // Update the tax distribution flow + STAKING_REWARD_CONTROLLER.refreshTaxDistributionFlow(); - // Transfer the leftover $FLUID to the locker owner - FLUID.transfer(recipient, amountToUnlock - penaltyAmount); + // Transfer the amount after tax to the locker owner + FLUID.transfer(recipient, amountToUnlock - taxAmount); emit FluidUnlocked(0, amountToUnlock, recipient, address(0)); } function _vestUnlock(uint256 amountToUnlock, uint128 unlockPeriod, address recipient) internal { - // Calculate the unlock and penalty flow rates based on requested amount and unlock period - (int96 unlockFlowRate, int96 taxFlowRate) = calculateVestUnlockFlowRates(amountToUnlock, unlockPeriod); + // Calculate the amount due to the user and the tax amount + (uint256 userUnlockAmount, uint256 taxAmount) = calculateVestUnlockAmounts(amountToUnlock, unlockPeriod); // Use create2 to deploy a Fontaine Beacon Proxy // The salt used for deployment is the hashed encoded Locker address and unlock identifier @@ -462,19 +681,248 @@ contract FluidLocker is Initializable, ReentrancyGuard, IFluidLocker { new BeaconProxy{ salt: keccak256(abi.encode(address(this), fontaineCount)) }(address(FONTAINE_BEACON), "") ); - // Transfer the total amount to unlock to the newly created Fontaine - FLUID.transfer(newFontaine, amountToUnlock); - // Persist the fontaine address and increment fontaine counter fontaines[fontaineCount] = IFontaine(newFontaine); fontaineCount++; + // Transfer the amount to unlock to the newly created Fontaine + FLUID.transfer(newFontaine, userUnlockAmount); + + // Transfer the tax amount to the Staking Reward Controller + FLUID.transfer(address(STAKING_REWARD_CONTROLLER), taxAmount); + // Initialize the new Fontaine instance (this initiate the unlock process) - IFontaine(newFontaine).initialize(recipient, unlockFlowRate, taxFlowRate, unlockPeriod); + IFontaine(newFontaine).initialize(recipient, int256(userUnlockAmount / unlockPeriod).toInt96(), unlockPeriod); + + // Update the tax distribution flow + STAKING_REWARD_CONTROLLER.refreshTaxDistributionFlow(); emit FluidUnlocked(unlockPeriod, amountToUnlock, recipient, newFontaine); } + /** + * @notice Swaps ETH for SUP tokens using Uniswap V3 (Pumponomics) + * @param weth WETH address + * @param ethAmount The amount of ETH to swap + */ + function _pump(address weth, uint256 ethAmount) internal { + IERC20(weth).approve(address(SWAP_ROUTER), ethAmount); + + // No need slippage protection here as it is + // implicitely covered by the `_createPosition` slippage protection + IV3SwapRouter.ExactInputSingleParams memory swapParams = IV3SwapRouter.ExactInputSingleParams({ + tokenIn: weth, + tokenOut: address(FLUID), + fee: ETH_SUP_POOL.fee(), + recipient: address(this), + amountIn: ethAmount, + amountOutMinimum: 0, + sqrtPriceLimitX96: 0 + }); + + SWAP_ROUTER.exactInputSingle(swapParams); + } + + /** + * @notice Creates a new Uniswap V3 position with the specified amounts of tokens + * @param ethAmount The desired amount of ETH to add as liquidity + * @param supAmount The desired amount of SUP to add as liquidity + * @return positionTokenId The token identifier of the newly created position + * @return depositedEthAmount The actual amount of ETH deposited as liquidity + * @return depositedSupAmount The actual amount of SUP deposited as liquidity + */ + function _createPosition(uint256 ethAmount, uint256 supAmount) + internal + returns (uint256 positionTokenId, uint256 depositedEthAmount, uint256 depositedSupAmount) + { + bool zeroIsSup = ETH_SUP_POOL.token0() == address(FLUID); + + INonfungiblePositionManager.MintParams memory mintParams = _formatMintParams(zeroIsSup, ethAmount, supAmount); + + // Create the UniswapV3 position + (uint256 tokenId, uint128 liquidity, uint256 depositedAmount0, uint256 depositedAmount1) = + NONFUNGIBLE_POSITION_MANAGER.mint(mintParams); + + // Set the tax free withdraw timestamp + taxFreeExitTimestamps[tokenId] = block.timestamp + TAX_FREE_WITHDRAW_DELAY; + + // Update the aggregated liquidity balance + _liquidityBalance += liquidity; + + if (!FLUID.isMemberConnected(address(LP_DISTRIBUTION_POOL), address(this))) { + // Connect this locker to the LP Tax Distribution Pool + FLUID.connectPool(LP_DISTRIBUTION_POOL); + } + + // Update the liquidity provider units + STAKING_REWARD_CONTROLLER.updateLiquidityProviderUnits(_liquidityBalance); + + (depositedSupAmount, depositedEthAmount) = _sortOutAmounts(zeroIsSup, depositedAmount0, depositedAmount1); + + positionTokenId = tokenId; + } + + /** + * @notice Decreases liquidity from a Uniswap V3 position + * @param tokenId The ID of the NFT position to decrease liquidity from + * @param liquidityToRemove The amount of liquidity to remove from the position (only collect fees if set to 0) + * @param amount0ToRemove The minimum amount Token0 to remove from the position + * @param amount1ToRemove The minimum amount Token1 to remove from the position + * @return withdrawnPairedAssetAmount The amount of paired asset received from removing liquidity + * @return withdrawnSupAmount The amount of $FLUID received from removing liquidity + */ + function _decreasePosition( + uint256 tokenId, + uint128 liquidityToRemove, + uint256 amount0ToRemove, + uint256 amount1ToRemove + ) internal returns (uint256 withdrawnPairedAssetAmount, uint256 withdrawnSupAmount) { + // (,, address token0,,,,,,,,,) = NONFUNGIBLE_POSITION_MANAGER.positions(tokenId); + // bool zeroIsSup = token0 == address(FLUID); + + bool zeroIsSup = ETH_SUP_POOL.token0() == address(FLUID); + + (uint256 amount0Min, uint256 amount1Min) = _calculateMinAmounts(amount0ToRemove, amount1ToRemove); + + // construct Decrease Liquidity parameters + INonfungiblePositionManager.DecreaseLiquidityParams memory params = INonfungiblePositionManager + .DecreaseLiquidityParams({ + tokenId: tokenId, + liquidity: liquidityToRemove, + amount0Min: amount0Min, + amount1Min: amount1Min, + deadline: block.timestamp + LP_OPERATION_DEADLINE + }); + + NONFUNGIBLE_POSITION_MANAGER.decreaseLiquidity(params); + + // Update the aggregated liquidity balance + _liquidityBalance -= liquidityToRemove; + + // Update the liquidity provider units + STAKING_REWARD_CONTROLLER.updateLiquidityProviderUnits(_liquidityBalance); + + // Collect the tokens owed + (uint256 withdrawnAmount0, uint256 withdrawnAmount1) = _collect(tokenId, address(this)); + + (withdrawnSupAmount, withdrawnPairedAssetAmount) = + _sortOutAmounts(zeroIsSup, withdrawnAmount0, withdrawnAmount1); + } + + /** + * @notice Collects accumulated fees from a Uniswap V3 position + * @param tokenId The ID of the NFT position to collect fees from + * @return amount0 The amount of token0 fees collected + * @return amount1 The amount of token1 fees collected + */ + function _collect(uint256 tokenId, address recipient) internal returns (uint256 amount0, uint256 amount1) { + INonfungiblePositionManager.CollectParams memory collectParams = INonfungiblePositionManager.CollectParams({ + tokenId: tokenId, + recipient: recipient, + amount0Max: type(uint128).max, + amount1Max: type(uint128).max + }); + + (amount0, amount1) = NONFUNGIBLE_POSITION_MANAGER.collect(collectParams); + } + + function _formatMintParams(bool zeroIsSup, uint256 pairedAssetAmount, uint256 supAmount) + internal + view + returns (INonfungiblePositionManager.MintParams memory mintParams) + { + (uint256 amount0, uint256 amount1) = _sortInAmounts(zeroIsSup, supAmount, pairedAssetAmount); + (uint256 amount0Min, uint256 amount1Min) = _calculateMinAmounts(amount0, amount1); + + int24 tickSpacing = ETH_SUP_POOL.tickSpacing(); + + mintParams = INonfungiblePositionManager.MintParams({ + token0: ETH_SUP_POOL.token0(), + token1: ETH_SUP_POOL.token1(), + fee: ETH_SUP_POOL.fee(), + tickLower: (TickMath.MIN_TICK / tickSpacing) * tickSpacing, + tickUpper: (TickMath.MAX_TICK / tickSpacing) * tickSpacing, + amount0Desired: amount0, + amount1Desired: amount1, + amount0Min: amount0Min, + amount1Min: amount1Min, + recipient: address(this), + deadline: block.timestamp + LP_OPERATION_DEADLINE + }); + } + + /** + * @notice Calculates minimum amounts based on slippage tolerance + * @param amount0 The ideal amount of token0 + * @param amount1 The ideal amount of token1 + * @return amount0Min The minimum acceptable amount of token0 + * @return amount1Min The minimum acceptable amount of token1 + */ + function _calculateMinAmounts(uint256 amount0, uint256 amount1) + internal + pure + returns (uint256 amount0Min, uint256 amount1Min) + { + // Calculate minimum amounts with slippage protection + unchecked { + amount0Min = (amount0 * (BP_DENOMINATOR - BP_SLIPPAGE_TOLERANCE)) / BP_DENOMINATOR; + amount1Min = (amount1 * (BP_DENOMINATOR - BP_SLIPPAGE_TOLERANCE)) / BP_DENOMINATOR; + } + } + + /** + * @notice Checks if the locker has a Uniswap V3 position + * @param tokenId The token identifier to query + * @return exists True if the locker owns the given tokenId, false otherwise + */ + function _positionExists(uint256 tokenId) internal view returns (bool exists) { + exists = taxFreeExitTimestamps[tokenId] > 0; + } + + /** + * @notice Sorts input amounts based on token order in the Uniswap V3 pool + * @param zeroIsSup Whether SUP is token0 in the pool + * @param supAmount The amount of SUP tokens + * @param pairedAssetAmount The amount of paired asset tokens + * @return amount0 The amount of token0 after sorting + * @return amount1 The amount of token1 after sorting + */ + function _sortInAmounts(bool zeroIsSup, uint256 supAmount, uint256 pairedAssetAmount) + internal + pure + returns (uint256 amount0, uint256 amount1) + { + if (zeroIsSup) { + amount0 = supAmount; + amount1 = pairedAssetAmount; + } else { + amount0 = pairedAssetAmount; + amount1 = supAmount; + } + } + + /** + * @notice Sorts output amounts based on token order in the Uniswap V3 pool + * @param zeroIsSup Whether SUP is token0 in the pool + * @param amount0 The amount of token0 to sort + * @param amount1 The amount of token1 to sort + * @return supAmount The sorted SUP token amount + * @return pairedAssetAmount The sorted paired asset amount + */ + function _sortOutAmounts(bool zeroIsSup, uint256 amount0, uint256 amount1) + internal + pure + returns (uint256 supAmount, uint256 pairedAssetAmount) + { + if (zeroIsSup) { + supAmount = amount0; + pairedAssetAmount = amount1; + } else { + supAmount = amount1; + pairedAssetAmount = amount0; + } + } + // __ ___ ___ _____ // / |/ /___ ____/ (_) __(_)__ __________ // / /|_/ / __ \/ __ / / /_/ / _ \/ ___/ ___/ diff --git a/packages/contracts/src/FluidLockerFactory.sol b/packages/contracts/src/FluidLockerFactory.sol index 193e60e..f903786 100644 --- a/packages/contracts/src/FluidLockerFactory.sol +++ b/packages/contracts/src/FluidLockerFactory.sol @@ -191,7 +191,7 @@ contract FluidLockerFactory is Initializable, IFluidLockerFactory { _lockers[lockerOwner] = lockerInstance; // Initialize the new Locker instance - FluidLocker(lockerInstance).initialize(lockerOwner); + FluidLocker(payable(lockerInstance)).initialize(lockerOwner); // Approve the newly created locker to interact with the Staking Reward Controller STAKING_REWARD_CONTROLLER.approveLocker(lockerInstance); diff --git a/packages/contracts/src/Fontaine.sol b/packages/contracts/src/Fontaine.sol index 5e6403d..77affd2 100644 --- a/packages/contracts/src/Fontaine.sol +++ b/packages/contracts/src/Fontaine.sol @@ -50,27 +50,27 @@ using SuperTokenV1Library for ISuperToken; * */ contract Fontaine is Initializable, IFontaine { - // _____ __ __ - // / ___// /_____ _/ /____ _____ - // \__ \/ __/ __ `/ __/ _ \/ ___/ - // ___/ / /_/ /_/ / /_/ __(__ ) - // /____/\__/\__,_/\__/\___/____/ + // ____ __ __ __ _____ __ __ + // / _/___ ___ ____ ___ __ __/ /_____ _/ /_ / /__ / ___// /_____ _/ /____ _____ + // / // __ `__ \/ __ `__ \/ / / / __/ __ `/ __ \/ / _ \ \__ \/ __/ __ `/ __/ _ \/ ___/ + // _/ // / / / / / / / / / / /_/ / /_/ /_/ / /_/ / / __/ ___/ / /_/ /_/ / /_/ __(__ ) + // /___/_/ /_/ /_/_/ /_/ /_/\__,_/\__/\__,_/_.___/_/\___/ /____/\__/\__,_/\__/\___/____/ /// @notice $FLUID SuperToken interface ISuperToken public immutable FLUID; - /// @notice Superfluid pool interface - ISuperfluidPool public immutable TAX_DISTRIBUTION_POOL; - /// @notice Constant used to calculate the earliest date an unlock can be terminated uint256 public constant EARLY_END = 1 days; + // _____ __ __ + // / ___// /_____ _/ /____ _____ + // \__ \/ __/ __ `/ __/ _ \/ ___/ + // ___/ / /_/ /_/ / /_/ __(__ ) + // /____/\__/\__,_/\__/\___/____/ + /// @notice Stream recipient address address public recipient; - /// @notice Flow rate between this Fontaine and the Tax Distribution Pool - uint96 public taxFlowRate; - /// @notice Flow rate between this Fontaine and the unlock recipient uint96 public unlockFlowRate; @@ -86,24 +86,20 @@ contract Fontaine is Initializable, IFontaine { /** * @notice Fontaine contract constructor * @param fluid FLUID SuperToken interface - * @param taxDistributionPool Tax Distribution Pool GDA contract address */ - constructor(ISuperToken fluid, ISuperfluidPool taxDistributionPool) { + constructor(ISuperToken fluid) { // Disable initializers to prevent implementation contract initalization _disableInitializers(); // Sets immutable states FLUID = fluid; - TAX_DISTRIBUTION_POOL = taxDistributionPool; } /// @inheritdoc IFontaine - function initialize( - address unlockRecipient, - int96 targetUnlockFlowRate, - int96 targetTaxFlowRate, - uint128 unlockPeriod - ) external initializer { + function initialize(address unlockRecipient, int96 targetUnlockFlowRate, uint128 unlockPeriod) + external + initializer + { // Ensure recipient is not a SuperApp if (ISuperfluid(FLUID.getHost()).isApp(ISuperApp(unlockRecipient))) revert CANNOT_UNLOCK_TO_SUPERAPP(); @@ -114,38 +110,22 @@ contract Fontaine is Initializable, IFontaine { endDate = uint128(block.timestamp) + unlockPeriod; // Store the streams flow rate - taxFlowRate = uint96(targetTaxFlowRate); unlockFlowRate = uint96(targetUnlockFlowRate); - // Distribute Tax flow to Staker GDA Pool - FLUID.distributeFlow(address(this), TAX_DISTRIBUTION_POOL, targetTaxFlowRate); - // Create the unlocking flow from the Fontaine to the locker owner FLUID.flow(unlockRecipient, targetUnlockFlowRate); } + /// @inheritdoc IFontaine function terminateUnlock() external { // Validate early end date if (block.timestamp < endDate - EARLY_END) { revert TOO_EARLY_TO_TERMINATE_UNLOCK(); } - uint256 taxEarlyEndCompensation; - - if (block.timestamp < endDate) { - // Calculate early end tax compensation - taxEarlyEndCompensation = (endDate - block.timestamp) * taxFlowRate; - } - - // Stops the streams by updating the flowrates to 0 - FLUID.distributeFlow(address(this), TAX_DISTRIBUTION_POOL, 0); + // Stops the stream by updating the flowrate to 0 FLUID.flow(recipient, 0); - // Transfer the remainders (tax + unlock) - if (taxEarlyEndCompensation > 0) { - FLUID.distribute(address(this), TAX_DISTRIBUTION_POOL, taxEarlyEndCompensation); - } - uint256 leftoverBalance = FLUID.balanceOf(address(this)); if (leftoverBalance > 0) { FLUID.transfer(recipient, leftoverBalance); diff --git a/packages/contracts/src/StakingRewardController.sol b/packages/contracts/src/StakingRewardController.sol index 1533726..87de37d 100644 --- a/packages/contracts/src/StakingRewardController.sol +++ b/packages/contracts/src/StakingRewardController.sol @@ -30,6 +30,7 @@ pragma solidity ^0.8.23; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/contracts/access/OwnableUpgradeable.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/contracts/proxy/utils/Initializable.sol"; import { ERC1967Utils } from "@openzeppelin-v5/contracts/proxy/ERC1967/ERC1967Utils.sol"; +import { SafeCast } from "@openzeppelin-v5/contracts/utils/math/SafeCast.sol"; /* Superfluid Protocol Contracts & Interfaces */ import { @@ -43,6 +44,8 @@ import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/cont import { IStakingRewardController } from "./interfaces/IStakingRewardController.sol"; using SuperTokenV1Library for ISuperToken; +using SafeCast for int256; +using SafeCast for int128; /** * @title Staking Reward Controller Contract @@ -61,7 +64,16 @@ contract StakingRewardController is Initializable, OwnableUpgradeable, IStakingR ISuperToken public immutable FLUID; /// @notice Value used to convert staked amount into GDA pool units - uint128 private constant _UNIT_DOWNSCALER = 1e16; + uint128 private constant _STAKING_UNIT_DOWNSCALER = 1e18; + + /// @notice Value used to convert the provided liquidity amount into GDA pool units + uint128 private constant _LIQUIDITY_UNIT_DOWNSCALER = 1e16; + + /// @notice Basis points denominator used for percentage calculations + uint128 private constant _BP_DENOMINATOR = 10_000; + + /// @notice Duration of the tax distribution flow + uint256 private constant _TAX_DISTRIBUTION_FLOW_DURATION = 180 days; // _____ __ __ // / ___// /_____ _/ /____ _____ @@ -78,6 +90,18 @@ contract StakingRewardController is Initializable, OwnableUpgradeable, IStakingR /// @notice Locker Factory contract address address public lockerFactory; + // _ __ ___ _____ __ __ + // | | / /|__ \ / ___// /_____ _/ /____ _____ + // | | / /__/ / \__ \/ __/ __ `/ __/ _ \/ ___/ + // | |/ // __/ ___/ / /_/ /_/ / /_/ __(__ ) + // |___//____/ /____/\__/\__,_/\__/\___/____/ + + /// @notice Tax Allocation + TaxAllocation public taxAllocation; + + /// @notice Superfluid pool interface + ISuperfluidPool public lpDistributionPool; + // ______ __ __ // / ____/___ ____ _____/ /________ _______/ /_____ _____ // / / / __ \/ __ \/ ___/ __/ ___/ / / / ___/ __/ __ \/ ___/ @@ -108,7 +132,7 @@ contract StakingRewardController is Initializable, OwnableUpgradeable, IStakingR PoolConfig memory poolConfig = PoolConfig({ transferabilityForUnitsOwner: false, distributionFromAnyAddress: true }); - // Create Superfluid GDA Pool + // Create Staker Superfluid GDA Pool taxDistributionPool = FLUID.createPool(address(this), poolConfig); } @@ -120,9 +144,16 @@ contract StakingRewardController is Initializable, OwnableUpgradeable, IStakingR /// @inheritdoc IStakingRewardController function updateStakerUnits(uint256 lockerStakedBalance) external onlyApprovedLocker { - taxDistributionPool.updateMemberUnits(msg.sender, uint128(lockerStakedBalance) / _UNIT_DOWNSCALER); + taxDistributionPool.updateMemberUnits(msg.sender, uint128(lockerStakedBalance) / _STAKING_UNIT_DOWNSCALER); + + emit UpdatedStakersUnits(msg.sender, uint128(lockerStakedBalance) / _STAKING_UNIT_DOWNSCALER); + } - emit UpdatedStakersUnits(msg.sender, uint128(lockerStakedBalance) / _UNIT_DOWNSCALER); + /// @inheritdoc IStakingRewardController + function updateLiquidityProviderUnits(uint256 lockerLiquidityBalance) external onlyApprovedLocker { + lpDistributionPool.updateMemberUnits(msg.sender, uint128(lockerLiquidityBalance) / _LIQUIDITY_UNIT_DOWNSCALER); + + emit UpdatedLiquidityProviderUnits(msg.sender, uint128(lockerLiquidityBalance) / _LIQUIDITY_UNIT_DOWNSCALER); } /// @inheritdoc IStakingRewardController @@ -149,6 +180,69 @@ contract StakingRewardController is Initializable, OwnableUpgradeable, IStakingR ERC1967Utils.upgradeToAndCall(newImplementation, data); } + /// @inheritdoc IStakingRewardController + function setTaxAllocation(uint128 stakerAllocationBP, uint128 liquidityProviderAllocationBP) external onlyOwner { + // Ensure the sum of the allocations is 100% + if (stakerAllocationBP + liquidityProviderAllocationBP != _BP_DENOMINATOR) { + revert INVALID_PARAMETER(); + } + + // Set the tax allocation + taxAllocation = TaxAllocation({ + stakerAllocationBP: stakerAllocationBP, + liquidityProviderAllocationBP: liquidityProviderAllocationBP + }); + + emit TaxAllocationUpdated(stakerAllocationBP, liquidityProviderAllocationBP); + } + + /// @inheritdoc IStakingRewardController + function setupLPDistributionPool() external onlyOwner { + if (address(lpDistributionPool) != address(0)) { + revert LP_DISTRIBUTION_POOL_ALREADY_SET(); + } + + // Superfluid GDA Pool configuration + PoolConfig memory poolConfig = + PoolConfig({ transferabilityForUnitsOwner: false, distributionFromAnyAddress: true }); + + // Create LP Superfluid GDA Pool + lpDistributionPool = FLUID.createPool(address(this), poolConfig); + } + + /// @inheritdoc IStakingRewardController + function refreshTaxDistributionFlow() external { + // Recalculate the global tax flow rate on a 6 months sliding window + int96 taxFlowRate = int256(FLUID.balanceOf(address(this)) / _TAX_DISTRIBUTION_FLOW_DURATION).toInt96(); + + // Apply Staker and LP tax allocations + int96 liquidityProviderFlowRate = (taxFlowRate * int128(taxAllocation.liquidityProviderAllocationBP).toInt96()) + / int128(_BP_DENOMINATOR).toInt96(); + int96 stakerFlowRate = taxFlowRate - liquidityProviderFlowRate; + + // Distribute the tax flow to the staker and liquidity provider pools + FLUID.distributeFlow(address(this), taxDistributionPool, stakerFlowRate); + FLUID.distributeFlow(address(this), lpDistributionPool, liquidityProviderFlowRate); + + emit TaxDistributionFlowUpdated(liquidityProviderFlowRate, stakerFlowRate); + } + + // _ ___ ______ __ _ + // | | / (_)__ _ __ / ____/_ ______ _____/ /_(_)___ ____ _____ + // | | / / / _ \ | /| / / / /_ / / / / __ \/ ___/ __/ / __ \/ __ \/ ___/ + // | |/ / / __/ |/ |/ / / __/ / /_/ / / / / /__/ /_/ / /_/ / / / (__ ) + // |___/_/\___/|__/|__/ /_/ \__,_/_/ /_/\___/\__/_/\____/_/ /_/____/ + + /// @inheritdoc IStakingRewardController + function getTaxAllocation() + external + view + returns (uint128 stakerAllocationBP, uint128 liquidityProviderAllocationBP) + { + stakerAllocationBP = taxAllocation.stakerAllocationBP; + liquidityProviderAllocationBP = taxAllocation.liquidityProviderAllocationBP; + } + // __ ___ ___ _____ // / |/ /___ ____/ (_) __(_)__ __________ // / /|_/ / __ \/ __ / / /_/ / _ \/ ___/ ___/ diff --git a/packages/contracts/src/interfaces/IFluidLocker.sol b/packages/contracts/src/interfaces/IFluidLocker.sol index a45cd34..015d31f 100644 --- a/packages/contracts/src/interfaces/IFluidLocker.sol +++ b/packages/contracts/src/interfaces/IFluidLocker.sol @@ -57,7 +57,13 @@ interface IFluidLocker { event FluidStaked(uint256 indexed newTotalStakedBalance, uint256 indexed addedAmount); /// @notice Event emitted when $FLUID are unstaked - event FluidUnstaked(); + event FluidUnstaked(uint256 indexed newTotalStakedBalance, uint256 indexed removedAmount); + + /// @notice Event emitted when a liquidity position is created + event LiquidityPositionCreated(uint256 indexed tokenId); + + /// @notice Event emitted when a liquidity position is burned + event LiquidityPositionBurned(uint256 indexed tokenId); // ______ __ ______ // / ____/_ _______/ /_____ ____ ___ / ____/_____________ __________ @@ -80,17 +86,41 @@ interface IFluidLocker { /// @notice Error thrown when attempting to unstake from locker that does not have staked $FLUID error NO_FLUID_TO_UNSTAKE(); - /// @notice Error thrown when attempting to stake from locker that does not have available $FLUID - error NO_FLUID_TO_STAKE(); + /// @notice Error thrown when attempting to stake or to LP from locker that does not have enough available $FLUID + error INSUFFICIENT_AVAILABLE_BALANCE(); + + /// @notice Error thrown when attempting to unstake from locker that does not have enough staked $FLUID + error INSUFFICIENT_STAKED_BALANCE(); /// @notice Error thrown when attempting to unstake while the staking cooldown is not yet elapsed error STAKING_COOLDOWN_NOT_ELAPSED(); + /// @notice Error thrown when attempting to withdraw liquidity while the cooldown is not yet elapsed + error LP_COOLDOWN_NOT_ELAPSED(); + /// @notice Error thrown when attempting to unlock or stake while this operation is not yet available error TTE_NOT_ACTIVATED(); - /// @notice Error thrown when attempting to unlock while the Tax Distribution Pool did not distribute units - error TAX_DISTRIBUTION_POOL_HAS_NO_UNITS(); + /// @notice Error thrown when attempting to unlock while the Staker Distribution Pool did not distribute units + error STAKER_DISTRIBUTION_POOL_HAS_NO_UNITS(); + + /// @notice Error thrown when attempting to unlock while the Provider Distribution Pool did not distribute units + error LP_DISTRIBUTION_POOL_HAS_NO_UNITS(); + + /// @notice Error thrown when attempting to provide liquidity with an amount greater than the available balance + error INSUFFICIENT_BALANCE(); + + /// @notice Error thrown when attempting to collect fees or withdrawing liquidity while the locker has no position + error LOCKER_HAS_NO_POSITION(); + + /// @notice Error thrown when attempting to provide liquidity to a Uniswap Pool that is not approved + error LIQUIDITY_POOL_NOT_APPROVED(); + + /// @notice Error thrown when attempting to provide liquidity with an amount of ETH sent different than the paired asset amount + error INSUFFICIENT_ETH_SENT(); + + /// @notice Error thrown when attempting to unlock an amount of SUP less than the minimum unlock amount + error INSUFFICIENT_UNLOCK_AMOUNT(); // ______ __ __ ______ __ _ // / ____/ __/ /____ _________ ____ _/ / / ____/_ ______ _____/ /_(_)___ ____ _____ @@ -131,22 +161,53 @@ interface IFluidLocker { /** * @notice Unlock the available FLUID Token from this locker * @dev Only this Locker owner can call this function + * @param unlockAmount the amount of FLUID Token to unlock * @param unlockPeriod the desired unlocking period (instant unlock if sets to 0) * @param recipient account to receive the unlocked FLUID tokens */ - function unlock(uint128 unlockPeriod, address recipient) external; + function unlock(uint256 unlockAmount, uint128 unlockPeriod, address recipient) external; /** * @notice Stake all the available FLUID Token of this locker * @dev Only this Locker owner can call this function + * @param amountToStake amount of FLUID Token to stake */ - function stake() external; + function stake(uint256 amountToStake) external; /** * @notice Unstake all the staked FLUID Token of this locker * @dev Only this Locker owner can call this function + * @param amountToUnstake amount of FLUID Token to unstake + */ + function unstake(uint256 amountToUnstake) external; + + /** + * @notice Provides liquidity to a liquidity pool by creating or increasing a position + * @param supAmount The amount of SUP tokens to provide as liquidity + */ + function provideLiquidity(uint256 supAmount) external payable; + + /** + * @notice Withdraws liquidity from a liquidity pool + * @param tokenId The token identifier of the position to withdraw liquidity from + * @param liquidityToRemove The amount of liquidity to remove from the position + * @param amount0ToRemove The amount of token0 to remove from the position + * @param amount1ToRemove The amount of token1 to remove from the position + */ + function withdrawLiquidity( + uint256 tokenId, + uint128 liquidityToRemove, + uint256 amount0ToRemove, + uint256 amount1ToRemove + ) external; + + /** + * @notice Collects accumulated fees from a Uniswap V3 position + * @param tokenId The token identifier of the position to collect fees from + * @return collectedWeth The amount of WETH tokens collected + * @return collectedSup The amount of SUP tokens collected */ - function unstake() external; + function collectFees(uint256 tokenId) external returns (uint256 collectedWeth, uint256 collectedSup); /** * @notice Helper function which connects the Locker to a program pool @@ -156,6 +217,13 @@ interface IFluidLocker { function connect(uint256 programId) external; /** + * @notice Withdraws dust ETH from the locker + * @dev Only this Locker owner can call this function + */ + function withdrawDustETH() external; + + /** + * @notice Helper function to help the Locker disconnect from a program pool * @notice Helper function which disconnects the Locker from a program pool * @dev Only this Locker owner can call this function * @param programId program identifier corresponding to the pool to connect to @@ -226,6 +294,12 @@ interface IFluidLocker { */ function getStakedBalance() external view returns (uint256 sBalance); + /** + * @notice Returns this Lockers' Uniswap V3 Liquidity balance in the SUP/ETH pool + * @return lBalance Uniswap V3 Liquidity balance in the SUP/ETH pool + */ + function getLiquidityBalance() external view returns (uint256 lBalance); + /** * @notice Returns this Lockers' available FLUID Token balance * @dev Available balance is the total balance minus the staked balance @@ -238,4 +312,11 @@ interface IFluidLocker { * @return fontaineBeaconImpl The fontaine beacon implementation contract address */ function getFontaineBeaconImplementation() external view returns (address fontaineBeaconImpl); + + /** + * @notice Returns the liquidity of the position for the given token identifier + * @param tokenId The token identifier of the position to query + * @return liquidity the liquidity of the position for the given token identifier + */ + function getPositionLiquidity(uint256 tokenId) external view returns (uint128 liquidity); } diff --git a/packages/contracts/src/interfaces/IFontaine.sol b/packages/contracts/src/interfaces/IFontaine.sol index 26e83f3..2df0155 100644 --- a/packages/contracts/src/interfaces/IFontaine.sol +++ b/packages/contracts/src/interfaces/IFontaine.sol @@ -58,15 +58,13 @@ interface IFontaine { // /_____/_/|_|\__/\___/_/ /_/ /_/\__,_/_/ /_/ \__,_/_/ /_/\___/\__/_/\____/_/ /_/____/ /** - * @notice Creates a flow to the locker owner and distribute a flow to the tax distribution GDA pool + * @notice Creates a flow to the locker owner * @dev Fontaine contract initializer * @param unlockRecipient recipient account address * @param unlockFlowRate FLUID flow rate from this contract to the locker owner - * @param taxFlowRate FLUID flow rate from this contract to the tax distribution GDA pool * @param unlockPeriod the desired unlocking period */ - function initialize(address unlockRecipient, int96 unlockFlowRate, int96 taxFlowRate, uint128 unlockPeriod) - external; + function initialize(address unlockRecipient, int96 unlockFlowRate, uint128 unlockPeriod) external; /** * @notice Terminate the unlocking flows diff --git a/packages/contracts/src/interfaces/IStakingRewardController.sol b/packages/contracts/src/interfaces/IStakingRewardController.sol index db07f29..40e21d1 100644 --- a/packages/contracts/src/interfaces/IStakingRewardController.sol +++ b/packages/contracts/src/interfaces/IStakingRewardController.sol @@ -26,6 +26,9 @@ pragma solidity ^0.8.23; +/* Superfluid Protocol Contracts & Interfaces */ +import { ISuperfluidPool } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; + /** * @title Staking Reward Controller Contract Interface * @author Superfluid @@ -42,6 +45,9 @@ interface IStakingRewardController { /// @notice Event emitted when locker updates their units from staking or unstaking event UpdatedStakersUnits(address indexed staker, uint128 indexed totalStakerUnits); + /// @notice Event emitted when locker updates their units from providing or withdrawingliquidity + event UpdatedLiquidityProviderUnits(address indexed liquidityProvider, uint128 indexed totalLiquidityProviderUnits); + /// @notice Event emitted when the subsidy flowrate is updated event SubsidyFlowRateUpdated(int96 indexed newSubsidyFlowRate); @@ -54,6 +60,29 @@ interface IStakingRewardController { /// @notice Event emitted when a Locker is approved event LockerApproved(address indexed approvedLocker); + /// @notice Event emitted when the tax allocation is updated + event TaxAllocationUpdated(uint128 stakerAllocationBP, uint128 liquidityProviderAllocationBP); + + /// @notice Event emitted when the tax distribution flow is updated + event TaxDistributionFlowUpdated(int96 liquidityProviderFlowRate, int96 stakerFlowRate); + + // ____ __ __ + // / __ \____ _/ /_____ _/ /___ ______ ___ _____ + // / / / / __ `/ __/ __ `/ __/ / / / __ \/ _ \/ ___/ + // / /_/ / /_/ / /_/ /_/ / /_/ /_/ / /_/ / __(__ ) + // /_____/\__,_/\__/\__,_/\__/\__, / .___/\___/____/ + // /____/_/ + + /** + * @notice Tax Allocation Data Type + * @param stakerAllocationBP staker allocation (expressed in basis points) + * @param liquidityProviderAllocationBP liquidity provider allocation (expressed in basis points) + */ + struct TaxAllocation { + uint128 stakerAllocationBP; + uint128 liquidityProviderAllocationBP; + } + // ______ __ ______ // / ____/_ _______/ /_____ ____ ___ / ____/_____________ __________ // / / / / / / ___/ __/ __ \/ __ `__ \ / __/ / ___/ ___/ __ \/ ___/ ___/ @@ -72,6 +101,9 @@ interface IStakingRewardController { /// @notice Error thrown when passing an invalid parameter error INVALID_PARAMETER(); + /// @notice Error thrown when the provider distribution pool is already set + error LP_DISTRIBUTION_POOL_ALREADY_SET(); + // ______ __ __ ______ __ _ // / ____/ __/ /____ _________ ____ _/ / / ____/_ ______ _____/ /_(_)___ ____ _____ // / __/ | |/_/ __/ _ \/ ___/ __ \/ __ `/ / / /_ / / / / __ \/ ___/ __/ / __ \/ __ \/ ___/ @@ -85,6 +117,13 @@ interface IStakingRewardController { */ function updateStakerUnits(uint256 lockerStakedBalance) external; + /** + * @notice Update the caller's (liquidity provider) units within the GDA Penalty Pool + * @dev Only approved lockers can perform this operation + * @param lockerLiquidityBalance locker's new liquidity balance amount + */ + function updateLiquidityProviderUnits(uint256 lockerLiquidityBalance) external; + /** * @notice Update the Locker Factory contract address * @dev Only the contract owner can perform this operation @@ -101,9 +140,60 @@ interface IStakingRewardController { /** * @notice Upgrade this proxy logic - * @dev Only the owner address can perform this operation + * @dev Only the contract owner can perform this operation * @param newImplementation new logic contract address * @param data calldata for potential initializer */ function upgradeTo(address newImplementation, bytes calldata data) external; + + /** + * @notice Set the tax allocation + * @dev Only the contract owner can perform this operation + * @param stakerAllocationBP staker allocation percentage (expressed in basis points) + * @param liquidityProviderAllocationBP liquidity provider allocation percentage (expressed in basis points) + */ + function setTaxAllocation(uint128 stakerAllocationBP, uint128 liquidityProviderAllocationBP) external; + + /** + * @notice Setup the provider distribution pool + * @dev Only the contract owner can perform this operation + */ + function setupLPDistributionPool() external; + + /** + * @notice Recalculate and redistribute the tax distribution flow to the staker and liquidity provider pools + * @dev The taxes are distributed over a 6 months sliding window + * @dev Every new call to this function will reevaluate the flow rates so that the distribution can last 6 months + * @dev Since the StakingRewardController is the pool admin, adjustment flow rate will also be distributed via these flow distributions + * @dev This function is can be called by anyone + */ + function refreshTaxDistributionFlow() external; + + // _ ___ ______ __ _ + // | | / (_)__ _ __ / ____/_ ______ _____/ /_(_)___ ____ _____ + // | | / / / _ \ | /| / / / /_ / / / / __ \/ ___/ __/ / __ \/ __ \/ ___/ + // | |/ / / __/ |/ |/ / / __/ / /_/ / / / / /__/ /_/ / /_/ / / / (__ ) + // |___/_/\___/|__/|__/ /_/ \__,_/_/ /_/\___/\__/_/\____/_/ /_/____/ + + /** + * @notice Get the tax allocation + * @return stakerAllocationBP staker allocation percentage (expressed in basis points) + * @return liquidityProviderAllocationBP liquidity provider allocation percentage (expressed in basis points) + */ + function getTaxAllocation() + external + view + returns (uint128 stakerAllocationBP, uint128 liquidityProviderAllocationBP); + + /** + * @notice Get the tax distribution pool + * @return taxDistributionPool tax distribution pool + */ + function taxDistributionPool() external view returns (ISuperfluidPool taxDistributionPool); + + /** + * @notice Get the provider distribution pool + * @return lpDistributionPool provider distribution pool + */ + function lpDistributionPool() external view returns (ISuperfluidPool lpDistributionPool); } diff --git a/packages/contracts/src/interfaces/token/IBridgedSuperToken.sol b/packages/contracts/src/interfaces/token/IBridgedSuperToken.sol index c742e56..d86a51d 100644 --- a/packages/contracts/src/interfaces/token/IBridgedSuperToken.sol +++ b/packages/contracts/src/interfaces/token/IBridgedSuperToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity 0.8.23; +pragma solidity ^0.8.23; // Superfluid framework interfaces we need import { ISuperToken } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; diff --git a/packages/contracts/src/interfaces/token/IOPBridgedSuperToken.sol b/packages/contracts/src/interfaces/token/IOPBridgedSuperToken.sol index d023750..4569ca1 100644 --- a/packages/contracts/src/interfaces/token/IOPBridgedSuperToken.sol +++ b/packages/contracts/src/interfaces/token/IOPBridgedSuperToken.sol @@ -24,7 +24,7 @@ // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -pragma solidity 0.8.23; +pragma solidity ^0.8.23; import { IBridgedSuperToken, IXERC20 } from "./IBridgedSuperToken.sol"; import { IOptimismMintableERC20 } from "./IOptimismMintableERC20.sol"; diff --git a/packages/contracts/src/token/BridgedSuperToken.sol b/packages/contracts/src/token/BridgedSuperToken.sol index 6be6214..61ef812 100644 --- a/packages/contracts/src/token/BridgedSuperToken.sol +++ b/packages/contracts/src/token/BridgedSuperToken.sol @@ -24,7 +24,7 @@ // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -pragma solidity 0.8.23; +pragma solidity ^0.8.23; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; // This abstract contract provides storage padding for the proxy diff --git a/packages/contracts/src/token/IWETH9.sol b/packages/contracts/src/token/IWETH9.sol new file mode 100644 index 0000000..1782703 --- /dev/null +++ b/packages/contracts/src/token/IWETH9.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.23; + +import { IERC20 } from "@openzeppelin-v5/contracts/token/ERC20/IERC20.sol"; + +/// @title Interface for WETH9 +interface IWETH9 is IERC20 { + /// @notice Deposit ether to get wrapped ether + function deposit() external payable; + + /// @notice Withdraw wrapped ether to get ether + function withdraw(uint256) external; +} diff --git a/packages/contracts/src/token/OPBridgedSuperToken.sol b/packages/contracts/src/token/OPBridgedSuperToken.sol index 64289cf..641198d 100644 --- a/packages/contracts/src/token/OPBridgedSuperToken.sol +++ b/packages/contracts/src/token/OPBridgedSuperToken.sol @@ -24,7 +24,7 @@ // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -pragma solidity 0.8.23; +pragma solidity ^0.8.23; import { IOptimismMintableERC20, IERC165 } from "../interfaces/token/IOptimismMintableERC20.sol"; import { BridgedSuperTokenProxy } from "./BridgedSuperToken.sol"; diff --git a/packages/contracts/test/EPProgramManager.t.sol b/packages/contracts/test/EPProgramManager.t.sol index 18977cb..05a6fda 100644 --- a/packages/contracts/test/EPProgramManager.t.sol +++ b/packages/contracts/test/EPProgramManager.t.sol @@ -123,12 +123,15 @@ contract EPProgramManagerTest is SFTest { vm.assume(_signerPkey != _invalidSignerPkey); vm.assume(_user != address(0)); vm.assume(_user != address(_stakingRewardController.taxDistributionPool())); + vm.assume(_user != address(_stakingRewardController.lpDistributionPool())); _units = bound(_units, 1, 1_000_000); uint256 programId = 1; ISuperfluidPool pool = _helperCreateProgram(programId, ADMIN, vm.addr(_signerPkey)); + vm.assume(_user != address(pool)); + uint256 nonce = _programManagerBase.getNextValidNonce(programId, _user); bytes memory validSignature = _helperGenerateSignature(_signerPkey, _user, _units, programId, nonce); @@ -816,7 +819,7 @@ contract FluidEPProgramManagerTest is SFTest { function _helperBobStaking() internal { _helperFundLocker(address(bobLocker), 10_000e18); vm.prank(BOB); - bobLocker.stake(); + bobLocker.stake(10_000e18); } function _helperStartFunding(uint256 _programId, uint256 _fundingAmount, uint32 _duration) internal { diff --git a/packages/contracts/test/FluidLocker.t.sol b/packages/contracts/test/FluidLocker.t.sol index 7d83122..47c901a 100644 --- a/packages/contracts/test/FluidLocker.t.sol +++ b/packages/contracts/test/FluidLocker.t.sol @@ -15,29 +15,40 @@ import { } from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol"; -import { FluidLocker, IFluidLocker, getUnlockingPercentage, calculateVestUnlockFlowRates } from "../src/FluidLocker.sol"; +import { FluidLocker, IFluidLocker, getUnlockingPercentage, calculateVestUnlockAmounts } from "../src/FluidLocker.sol"; import { IFontaine } from "../src/interfaces/IFontaine.sol"; import { IEPProgramManager } from "../src/interfaces/IEPProgramManager.sol"; import { IStakingRewardController } from "../src/interfaces/IStakingRewardController.sol"; import { Fontaine } from "../src/Fontaine.sol"; +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; +import { INonfungiblePositionManager } from "@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol"; +import { IV3SwapRouter } from "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol"; +import { LiquidityAmounts } from "@uniswap/v3-periphery/contracts/libraries/LiquidityAmounts.sol"; +import { TickMath } from "@uniswap/v3-core/contracts/libraries/TickMath.sol"; using SuperTokenV1Library for ISuperToken; using SafeCast for int256; -contract FluidLockerTest is SFTest { +abstract contract FluidLockerBaseTest is SFTest { uint256 public constant PROGRAM_0 = 1; uint256 public constant PROGRAM_1 = 2; uint256 public constant PROGRAM_2 = 3; uint256 public constant signerPkey = 0x69; + uint256 internal constant _BP_DENOMINATOR = 10_000; + uint256 internal constant _INSTANT_UNLOCK_PENALTY_BP = 8000; + uint256 internal constant _SCALER = 1e18; uint128 internal constant _MIN_UNLOCK_PERIOD = 7 days; uint128 internal constant _MAX_UNLOCK_PERIOD = 365 days; - uint256 private constant _BP_DENOMINATOR = 10_000; - uint256 internal constant _SCALER = 1e18; + uint256 internal constant _TAX_DISTRIBUTION_FLOW_DURATION = 180 days; + uint80 internal constant _STAKING_COOLDOWN_PERIOD = 30 days; + uint80 internal constant _LP_COOLDOWN_PERIOD = 7 days; ISuperfluidPool[] public programPools; + IFluidLocker public aliceLocker; IFluidLocker public bobLocker; + IFluidLocker public carolLocker; function setUp() public virtual override { super.setUp(); @@ -54,11 +65,116 @@ contract FluidLockerTest is SFTest { vm.prank(BOB); bobLocker = IFluidLocker(_fluidLockerFactory.createLockerContract()); + + vm.prank(CAROL); + carolLocker = IFluidLocker(_fluidLockerFactory.createLockerContract()); + } + + // __ __ __ ______ __ _ + // / / / /__ / /___ ___ _____ / ____/_ ______ _____/ /_(_)___ ____ _____ + // / /_/ / _ \/ / __ \/ _ \/ ___/ / /_ / / / / __ \/ ___/ __/ / __ \/ __ \/ ___/ + // / __ / __/ / /_/ / __/ / / __/ / /_/ / / / / /__/ /_/ / /_/ / / / (__ ) + // /_/ /_/\___/_/ .___/\___/_/ /_/ \__,_/_/ /_/\___/\__/_/\____/_/ /_/____/ + // /_/ + + function _helperGetAmountsForLiquidity(IUniswapV3Pool pool, uint128 liquidity) + internal + view + returns (uint256 amount0, uint256 amount1) + { + (uint160 sqrtPriceX96,,,,,,) = pool.slot0(); + uint160 sqrtRatioLowerX96 = TickMath.getSqrtRatioAtTick(_MIN_TICK); + uint160 sqrtRatioHigherX96 = TickMath.getSqrtRatioAtTick(_MAX_TICK); + + (amount0, amount1) = + LiquidityAmounts.getAmountsForLiquidity(sqrtPriceX96, sqrtRatioLowerX96, sqrtRatioHigherX96, liquidity); + } + + function _helperBuySUP(address buyer, uint256 wethAmount) internal { + deal(address(_weth), buyer, wethAmount); + + vm.startPrank(buyer); + _weth.approve(address(_swapRouter), wethAmount); + + IV3SwapRouter.ExactInputSingleParams memory swapParams = IV3SwapRouter.ExactInputSingleParams({ + tokenIn: address(_weth), + tokenOut: address(_fluidSuperToken), + fee: POOL_FEE, + recipient: buyer, + amountIn: wethAmount, + amountOutMinimum: 0, + sqrtPriceLimitX96: 0 + }); + + _swapRouter.exactInputSingle(swapParams); + vm.stopPrank(); + } + + function _helperSellSUP(address seller, uint256 supAmount) internal { + vm.prank(FLUID_TREASURY); + _fluidSuperToken.transfer(seller, supAmount); + + vm.startPrank(seller); + _fluidSuperToken.approve(address(_swapRouter), supAmount); + + IV3SwapRouter.ExactInputSingleParams memory swapParams = IV3SwapRouter.ExactInputSingleParams({ + tokenIn: address(_fluidSuperToken), + tokenOut: address(_weth), + fee: POOL_FEE, + recipient: seller, + amountIn: supAmount, + amountOutMinimum: 0, + sqrtPriceLimitX96: 0 + }); + + _swapRouter.exactInputSingle(swapParams); + vm.stopPrank(); + } + + function _helperCalculateTaxDisitrutionInstantUnlock(uint256 amountToUnlock) + internal + view + returns (uint256 amountToUser, int96 flowRateToStaker, int96 flowRateToLP) + { + (, uint256 lpAllocation) = _stakingRewardController.getTaxAllocation(); + + uint256 totalPenaltyAmount = Math.mulDiv(amountToUnlock, _INSTANT_UNLOCK_PENALTY_BP, _BP_DENOMINATOR); + amountToUser = amountToUnlock - totalPenaltyAmount; + + int96 totalPenaltyFlowRate = int256(totalPenaltyAmount / _TAX_DISTRIBUTION_FLOW_DURATION).toInt96(); + + flowRateToLP = (totalPenaltyFlowRate * int256(lpAllocation).toInt96()) / int256(_BP_DENOMINATOR).toInt96(); + + flowRateToStaker = totalPenaltyFlowRate - flowRateToLP; + } + + function _helperCalculateFlowRatesVestUnlock(uint256 amountToUnlock, uint128 unlockPeriod) + internal + view + returns (int96 stakerFlowRate, int96 providerFlowRate, int96 unlockFlowRate) + { + (uint256 userUnlockAmount, uint256 taxAmount) = calculateVestUnlockAmounts(amountToUnlock, unlockPeriod); + + unlockFlowRate = int256(userUnlockAmount / unlockPeriod).toInt96(); + + int96 taxFlowRate = int256(taxAmount / _TAX_DISTRIBUTION_FLOW_DURATION).toInt96(); + + // Calculate the tax allocation split between provider and staker + (, uint256 providerAllocation) = _stakingRewardController.getTaxAllocation(); + + providerFlowRate = (taxFlowRate * int256(providerAllocation).toInt96()) / int256(_BP_DENOMINATOR).toInt96(); + stakerFlowRate = taxFlowRate - providerFlowRate; + } +} + +contract FluidLockerTest is FluidLockerBaseTest { + function setUp() public virtual override { + super.setUp(); } function testInitialize(address owner) external virtual { vm.expectRevert(); - FluidLocker(address(aliceLocker)).initialize(owner); + FluidLocker(payable(address(aliceLocker))).initialize(owner); } function testClaim(uint256 units) external virtual { @@ -308,76 +424,147 @@ contract FluidLockerTest is SFTest { assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), amount, "incorrect balance after operation"); } - function testInstantUnlock() external virtual { - _helperFundLocker(address(aliceLocker), 10_000e18); - - vm.prank(ALICE); - vm.expectRevert(IFluidLocker.TAX_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); - aliceLocker.unlock(0, ALICE); - - _helperBobStaking(); + function testInstantUnlock(uint256 fundingAmount, uint256 unlockAmount, uint256 invalidUnlockAmount) + external + virtual + { + fundingAmount = bound(fundingAmount, 1 ether, 1_000_000e18); + unlockAmount = bound(unlockAmount, 1, fundingAmount); + vm.assume(invalidUnlockAmount > fundingAmount); + + _helperFundLocker(address(aliceLocker), fundingAmount); + + if (unlockAmount < FluidLocker(payable(address(aliceLocker))).MIN_UNLOCK_AMOUNT()) { + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.INSUFFICIENT_UNLOCK_AMOUNT.selector); + aliceLocker.unlock(unlockAmount, 0, ALICE); + } else { + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.STAKER_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); + aliceLocker.unlock(unlockAmount, 0, ALICE); + + _helperLockerStake(address(bobLocker)); + + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.LP_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); + aliceLocker.unlock(unlockAmount, 0, ALICE); + + _helperLockerProvideLiquidity(address(carolLocker)); + + uint256 aliceBalanceBefore = _fluidSuperToken.balanceOf(address(ALICE)); + uint256 lockerBalanceBefore = _fluidSuperToken.balanceOf(address(aliceLocker)); + + vm.prank(BOB); + vm.expectRevert(IFluidLocker.NOT_LOCKER_OWNER.selector); + aliceLocker.unlock(unlockAmount, 0, ALICE); + + vm.startPrank(ALICE); + vm.expectRevert(IFluidLocker.FORBIDDEN.selector); + aliceLocker.unlock(unlockAmount, 0, address(0)); + + vm.expectRevert(IFluidLocker.INSUFFICIENT_AVAILABLE_BALANCE.selector); + aliceLocker.unlock(invalidUnlockAmount, 0, ALICE); + + aliceLocker.unlock(unlockAmount, 0, ALICE); + vm.stopPrank(); + + (uint256 amountToUser, int96 flowRateToStaker, int96 flowRateToLP) = + _helperCalculateTaxDisitrutionInstantUnlock(unlockAmount); + + (, int96 actualLPFlowRate) = _fluid.estimateFlowDistributionActualFlowRate( + address(_stakingRewardController), _stakingRewardController.lpDistributionPool(), flowRateToLP + ); + + (, int96 actualStakerFlowRate) = _fluid.estimateFlowDistributionActualFlowRate( + address(_stakingRewardController), _stakingRewardController.taxDistributionPool(), flowRateToStaker + ); + + assertEq( + _fluidSuperToken.balanceOf(address(ALICE)), + aliceBalanceBefore + amountToUser, + "incorrect ALICE balance after instant unlock" + ); + + assertEq( + _fluidSuperToken.balanceOf(address(aliceLocker)), + lockerBalanceBefore - unlockAmount, + "incorrect Locker balance after instant unlock" + ); + + assertEq( + _stakingRewardController.taxDistributionPool().getMemberFlowRate(address(bobLocker)), + actualStakerFlowRate, + "incorrect Bob Locker (staker) flow rate after instant unlock" + ); + + assertEq( + _stakingRewardController.lpDistributionPool().getMemberFlowRate(address(carolLocker)), + actualLPFlowRate, + "incorrect Carol Locker (provider) flow rate after instant unlock" + ); + } + } - assertEq(_fluidSuperToken.balanceOf(address(ALICE)), 0, "incorrect Alice bal before op"); - assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), 10_000e18, "incorrect Locker bal before op"); - assertEq(bobLocker.getAvailableBalance(), 0, "incorrect Bob bal before op"); + function testVestUnlock(uint128 unlockPeriod, uint256 unlockAmount) external { + unlockPeriod = uint128(bound(unlockPeriod, _MIN_UNLOCK_PERIOD, _MAX_UNLOCK_PERIOD)); + unlockAmount = bound(unlockAmount, 10e18, 100_000_000e18); + _helperFundLocker(address(aliceLocker), unlockAmount); - vm.prank(BOB); - vm.expectRevert(IFluidLocker.NOT_LOCKER_OWNER.selector); - aliceLocker.unlock(0, ALICE); + assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), unlockAmount, "incorrect Locker bal before op"); + assertEq(FluidLocker(payable(address(aliceLocker))).fontaineCount(), 0, "incorrect fontaine count"); + assertEq( + address(FluidLocker(payable(address(aliceLocker))).fontaines(0)), + address(IFontaine(address(0))), + "incorrect fontaine address" + ); - vm.prank(ALICE); - vm.expectRevert(IFluidLocker.FORBIDDEN.selector); - aliceLocker.unlock(0, address(0)); + (int96 stakerFlowRate, int96 providerFlowRate, int96 unlockFlowRate) = + _helperCalculateFlowRatesVestUnlock(unlockAmount, unlockPeriod); vm.prank(ALICE); - aliceLocker.unlock(0, ALICE); + vm.expectRevert(IFluidLocker.STAKER_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); + aliceLocker.unlock(unlockAmount, unlockPeriod, ALICE); - assertEq(_fluidSuperToken.balanceOf(address(ALICE)), 2_000e18, "incorrect Alice bal after op"); - assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), 0, "incorrect bal after op"); - assertEq(bobLocker.getAvailableBalance(), 8_000e18, "incorrect Bob bal after op"); + _helperLockerStake(address(bobLocker)); vm.prank(ALICE); - vm.expectRevert(IFluidLocker.NO_FLUID_TO_UNLOCK.selector); - aliceLocker.unlock(0, ALICE); - } + vm.expectRevert(IFluidLocker.LP_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); + aliceLocker.unlock(unlockAmount, unlockPeriod, ALICE); - function testVestUnlock(uint128 unlockPeriod) external virtual { - unlockPeriod = uint128(bound(unlockPeriod, _MIN_UNLOCK_PERIOD, _MAX_UNLOCK_PERIOD)); - uint256 funding = 10_000e18; - _helperFundLocker(address(aliceLocker), funding); + _helperLockerProvideLiquidity(address(carolLocker)); vm.prank(ALICE); - vm.expectRevert(IFluidLocker.TAX_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); - aliceLocker.unlock(unlockPeriod, ALICE); + aliceLocker.unlock(unlockAmount, unlockPeriod, ALICE); - _helperBobStaking(); + IFontaine newFontaine = FluidLocker(payable(address(aliceLocker))).fontaines(0); - assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), funding, "incorrect Locker bal before op"); - assertEq(FluidLocker(address(aliceLocker)).fontaineCount(), 0, "incorrect fontaine count"); - assertEq( - address(FluidLocker(address(aliceLocker)).fontaines(0)), - address(IFontaine(address(0))), - "incorrect fontaine addrfoess" + (, int96 actualStakerFlowRate) = _fluid.estimateFlowDistributionActualFlowRate( + address(_stakingRewardController), _stakingRewardController.taxDistributionPool(), stakerFlowRate + ); + (, int96 actualProviderFlowRate) = _fluid.estimateFlowDistributionActualFlowRate( + address(_stakingRewardController), _stakingRewardController.lpDistributionPool(), providerFlowRate ); - - (int96 taxFlowRate, int96 unlockFlowRate) = _helperCalculateUnlockFlowRates(funding, unlockPeriod); - - vm.prank(ALICE); - aliceLocker.unlock(unlockPeriod, ALICE); - - IFontaine newFontaine = FluidLocker(address(aliceLocker)).fontaines(0); assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), 0, "incorrect bal after op"); - assertEq( - ISuperToken(_fluidSuperToken).getFlowRate(address(newFontaine), ALICE), - unlockFlowRate, + assertApproxEqAbs( + uint96(ISuperToken(_fluidSuperToken).getFlowRate(address(newFontaine), ALICE)), + uint96(unlockFlowRate), + uint96(unlockFlowRate * 10 / 10000), "incorrect unlock flowrate" ); + + assertApproxEqAbs( + uint96(_stakingRewardController.taxDistributionPool().getMemberFlowRate(address(bobLocker))), + uint96(actualStakerFlowRate), + uint96(actualStakerFlowRate * 10 / 10000), + "incorrect staker flowrate" + ); + assertApproxEqAbs( - FluidLocker(address(aliceLocker)).TAX_DISTRIBUTION_POOL().getMemberFlowRate(address(bobLocker)), - taxFlowRate, - funding / 1e16, - "incorrect tax flowrate" + uint96(_stakingRewardController.lpDistributionPool().getMemberFlowRate(address(carolLocker))), + uint96(actualProviderFlowRate), + uint96(actualProviderFlowRate * 10 / 10000), + "incorrect provider flowrate" ); } @@ -388,65 +575,75 @@ contract FluidLockerTest is SFTest { unlockPeriod = uint128(bound(unlockPeriod, 0 + 1, _MIN_UNLOCK_PERIOD - 1)); vm.prank(ALICE); vm.expectRevert(IFluidLocker.INVALID_UNLOCK_PERIOD.selector); - aliceLocker.unlock(unlockPeriod, ALICE); + aliceLocker.unlock(funding, unlockPeriod, ALICE); unlockPeriod = uint128(bound(unlockPeriod, _MAX_UNLOCK_PERIOD + 1, 100_000 days)); vm.prank(ALICE); vm.expectRevert(IFluidLocker.INVALID_UNLOCK_PERIOD.selector); - aliceLocker.unlock(unlockPeriod, ALICE); + aliceLocker.unlock(funding, unlockPeriod, ALICE); } - function testStake() external virtual { - uint256 funding = 10_000e18; - _helperFundLocker(address(aliceLocker), funding); - assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), funding, "incorrect Locker bal before op"); - assertEq(aliceLocker.getAvailableBalance(), funding, "incorrect available bal before op"); + function testStake(uint256 amountToStake1, uint256 amountToStake2) external virtual { + amountToStake1 = bound(amountToStake1, 1, 100_000_000 ether); + amountToStake2 = bound(amountToStake2, 1, 100_000_000 ether); + _helperFundLocker(address(aliceLocker), amountToStake1); + assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), amountToStake1, "incorrect Locker bal before op"); + assertEq(aliceLocker.getAvailableBalance(), amountToStake1, "incorrect available bal before op"); assertEq(aliceLocker.getStakedBalance(), 0, "incorrect staked bal before op"); vm.prank(ALICE); - aliceLocker.stake(); + aliceLocker.stake(amountToStake1); assertEq(aliceLocker.getAvailableBalance(), 0, "incorrect available bal after op"); - assertEq(aliceLocker.getStakedBalance(), funding, "incorrect staked bal after op"); + assertEq(aliceLocker.getStakedBalance(), amountToStake1, "incorrect staked bal after op"); assertEq( _stakingRewardController.taxDistributionPool().getUnits(address(aliceLocker)), - funding / 1e16, + amountToStake1 / _STAKING_UNIT_DOWNSCALER, "incorrect units" ); vm.prank(ALICE); - vm.expectRevert(IFluidLocker.NO_FLUID_TO_STAKE.selector); - aliceLocker.stake(); + vm.expectRevert(IFluidLocker.INSUFFICIENT_AVAILABLE_BALANCE.selector); + aliceLocker.stake(amountToStake2); } - function testUnstake() external virtual { - uint256 funding = 10_000e18; - _helperFundLocker(address(aliceLocker), funding); + function testUnstake(uint256 amountToStake, uint256 amountToUnstake, uint256 invalidAmountToUnstake) + external + virtual + { + amountToStake = bound(amountToStake, 1, 100_000_000 ether); + vm.assume(amountToUnstake <= amountToStake); + vm.assume(invalidAmountToUnstake > amountToStake); + + _helperFundLocker(address(aliceLocker), amountToStake); + vm.startPrank(ALICE); - aliceLocker.stake(); + aliceLocker.stake(amountToStake); assertEq(aliceLocker.getAvailableBalance(), 0, "incorrect available bal before op"); - assertEq(aliceLocker.getStakedBalance(), funding, "incorrect staked bal before op"); + assertEq(aliceLocker.getStakedBalance(), amountToStake, "incorrect staked bal before op"); assertEq( _stakingRewardController.taxDistributionPool().getUnits(address(aliceLocker)), - funding / 1e16, + amountToStake / _STAKING_UNIT_DOWNSCALER, "incorrect units before op" ); vm.expectRevert(IFluidLocker.STAKING_COOLDOWN_NOT_ELAPSED.selector); - aliceLocker.unstake(); + aliceLocker.unstake(amountToUnstake); - vm.warp(uint256(FluidLocker(address(aliceLocker)).stakingUnlocksAt()) + 1); - aliceLocker.unstake(); + vm.warp(uint256(FluidLocker(payable(address(aliceLocker))).stakingUnlocksAt()) + 1); + aliceLocker.unstake(amountToUnstake); - assertEq(aliceLocker.getAvailableBalance(), funding, "incorrect available bal after op"); - assertEq(aliceLocker.getStakedBalance(), 0, "incorrect staked bal after op"); + assertEq(aliceLocker.getAvailableBalance(), amountToUnstake, "incorrect available bal after op"); + assertEq(aliceLocker.getStakedBalance(), amountToStake - amountToUnstake, "incorrect staked bal after op"); assertEq( - _stakingRewardController.taxDistributionPool().getUnits(address(aliceLocker)), 0, "incorrect units after op" + _stakingRewardController.taxDistributionPool().getUnits(address(aliceLocker)), + (amountToStake - amountToUnstake) / _STAKING_UNIT_DOWNSCALER, + "incorrect units after op" ); - vm.expectRevert(IFluidLocker.NO_FLUID_TO_UNSTAKE.selector); - aliceLocker.unstake(); + vm.expectRevert(IFluidLocker.INSUFFICIENT_STAKED_BALANCE.selector); + aliceLocker.unstake(invalidAmountToUnstake); vm.stopPrank(); } @@ -461,14 +658,14 @@ contract FluidLockerTest is SFTest { uint256 unlockPercentage = getUnlockingPercentage(unlockPeriod); assertGe(unlockPercentage, 3107, "shouldnt be any smaller"); - assertLe(unlockPercentage, 10000, "shouldnt be any larger"); + assertLe(unlockPercentage, 10_000, "shouldnt be any larger"); // Test different periods assertEq(getUnlockingPercentage(7 days), 3107, "should be 3107"); assertEq(getUnlockingPercentage(30 days), 4293, "should be 4293"); assertEq(getUnlockingPercentage(90 days), 5972, "should be 5972"); assertEq(getUnlockingPercentage(180 days), 7617, "should be 7617"); - assertEq(getUnlockingPercentage(365 days), 10000, "should be 10000"); + assertEq(getUnlockingPercentage(365 days), 10_000, "should be 10000"); } // Note: property based testing @@ -485,7 +682,7 @@ contract FluidLockerTest is SFTest { assertLe(p1, p2, "monotonicity violated"); } - // Property : lower time-preference shall result in higher flowrate + // Property : lower time-preference shall result in higher taxed amount and lower unlock amount function testCalculateVestUnlockFlowRates(uint128 t1, uint128 t2) public pure { uint256 amount = 1 ether; uint256 minDistance = 80 minutes; @@ -493,52 +690,19 @@ contract FluidLockerTest is SFTest { t1 = uint128(bound(t1, _MIN_UNLOCK_PERIOD, _MAX_UNLOCK_PERIOD - minDistance)); t2 = uint128(bound(t2, t1 + minDistance, _MAX_UNLOCK_PERIOD)); - console2.log("using t1 t2", t1, t2); - - (int96 ur1, int96 tr1) = calculateVestUnlockFlowRates(amount, t1); - (int96 ur2, int96 tr2) = calculateVestUnlockFlowRates(amount, t2); - assertGe(ur1, ur2, "unlock rate monotonicity violated"); - assertGe(tr1, tr2, "tax rate monotonicity violated"); - } + (uint256 userUnlockAmount1, uint256 taxAmount1) = calculateVestUnlockAmounts(amount, t1); + (uint256 userUnlockAmount2, uint256 taxAmount2) = calculateVestUnlockAmounts(amount, t2); - function _helperBobStaking() internal { - _helperFundLocker(address(bobLocker), 10_000e18); - vm.prank(BOB); - bobLocker.stake(); - } - - function _helperCalculateUnlockFlowRates(uint256 amountToUnlock, uint128 unlockPeriod) - internal - pure - returns (int96 taxFlowRate, int96 unlockFlowRate) - { - int96 globalFlowRate = int256(amountToUnlock / unlockPeriod).toInt96(); - - unlockFlowRate = (globalFlowRate * int256(getUnlockingPercentage(unlockPeriod))).toInt96() - / int256(_BP_DENOMINATOR).toInt96(); - taxFlowRate = globalFlowRate - unlockFlowRate; + assertGe(userUnlockAmount2, userUnlockAmount1, "unlock amount monotonicity violated"); + assertGe(taxAmount1, taxAmount2, "tax amount monotonicity violated"); } } -contract FluidLockerTTETest is SFTest { +// Note : this test the transition phase from non-unlockable to unlockable FluidLocker contract instances +contract FluidLockerTTETest is FluidLockerBaseTest { address internal _nonUnlockableLockerLogic; address internal _unlockableLockerLogic; - uint256 public constant PROGRAM_0 = 1; - uint256 public constant PROGRAM_1 = 2; - uint256 public constant PROGRAM_2 = 3; - uint256 public constant signerPkey = 0x69; - - uint256 private constant _BP_DENOMINATOR = 10_000; - uint256 internal constant _SCALER = 1e18; - uint128 internal constant _MIN_UNLOCK_PERIOD = 7 days; - uint128 internal constant _MAX_UNLOCK_PERIOD = 365 days; - uint256 internal constant _PERCENT_TO_BP = 100; - - ISuperfluidPool[] public programPools; - IFluidLocker public aliceLocker; - IFluidLocker public bobLocker; - function setUp() public override { super.setUp(); @@ -546,33 +710,21 @@ contract FluidLockerTTETest is SFTest { _nonUnlockableLockerLogic = address( new FluidLocker( _fluid, - _stakingRewardController.taxDistributionPool(), IEPProgramManager(address(_programManager)), IStakingRewardController(address(_stakingRewardController)), address(_fontaineLogic), - !LOCKER_CAN_UNLOCK + !LOCKER_CAN_UNLOCK, + _nonfungiblePositionManager, + _pool, + _swapRouter ) ); _unlockableLockerLogic = address(_fluidLockerLogic); - UpgradeableBeacon beacon = _fluidLockerFactory.LOCKER_BEACON(); vm.prank(ADMIN); beacon.upgradeTo(_nonUnlockableLockerLogic); - - uint256[] memory pIds = new uint256[](3); - pIds[0] = PROGRAM_0; - pIds[1] = PROGRAM_1; - pIds[2] = PROGRAM_2; - - programPools = _helperCreatePrograms(pIds, ADMIN, vm.addr(signerPkey)); - - vm.prank(ALICE); - aliceLocker = IFluidLocker(_fluidLockerFactory.createLockerContract()); - - vm.prank(BOB); - bobLocker = IFluidLocker(_fluidLockerFactory.createLockerContract()); } function testClaim(uint256 units) external { @@ -643,131 +795,236 @@ contract FluidLockerTTETest is SFTest { assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), amount, "incorrect balance after operation"); } - function testInstantUnlock() external { - _helperFundLocker(address(aliceLocker), 10_000e18); + function testInstantUnlock(uint256 fundingAmount, uint256 unlockAmount, uint256 invalidUnlockAmount) + external + virtual + { + fundingAmount = bound(fundingAmount, 1 ether, 1_000_000e18); + unlockAmount = bound(unlockAmount, 1, fundingAmount); + vm.assume(invalidUnlockAmount > fundingAmount); + + uint128 instantUnlockPeriod = 0; - assertEq(_fluidSuperToken.balanceOf(address(ALICE)), 0, "incorrect Alice bal before op"); - assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), 10_000e18, "incorrect Locker bal before op"); - assertEq(bobLocker.getAvailableBalance(), 0, "incorrect Bob bal before op"); + _helperFundLocker(address(aliceLocker), fundingAmount); vm.prank(ALICE); vm.expectRevert(IFluidLocker.TTE_NOT_ACTIVATED.selector); - aliceLocker.unlock(0, ALICE); - + aliceLocker.unlock(unlockAmount, instantUnlockPeriod, ALICE); _helperUpgradeLocker(); - vm.prank(ALICE); - vm.expectRevert(IFluidLocker.TAX_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); - aliceLocker.unlock(0, ALICE); - - _helperBobStaking(); - - vm.prank(ALICE); - aliceLocker.unlock(0, ALICE); - - assertEq(_fluidSuperToken.balanceOf(address(ALICE)), 2_000e18, "incorrect Alice bal after op"); - assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), 0, "incorrect bal after op"); - assertEq(bobLocker.getAvailableBalance(), 8_000e18, "incorrect Bob bal after op"); + if (unlockAmount < FluidLocker(payable(address(aliceLocker))).MIN_UNLOCK_AMOUNT()) { + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.INSUFFICIENT_UNLOCK_AMOUNT.selector); + aliceLocker.unlock(unlockAmount, 0, ALICE); + } else { + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.STAKER_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); + aliceLocker.unlock(unlockAmount, instantUnlockPeriod, ALICE); + + _helperLockerStake(address(bobLocker)); + + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.LP_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); + aliceLocker.unlock(unlockAmount, instantUnlockPeriod, ALICE); + + _helperLockerProvideLiquidity(address(carolLocker)); + + uint256 aliceBalanceBefore = _fluidSuperToken.balanceOf(address(ALICE)); + uint256 lockerBalanceBefore = _fluidSuperToken.balanceOf(address(aliceLocker)); + + vm.prank(BOB); + vm.expectRevert(IFluidLocker.NOT_LOCKER_OWNER.selector); + aliceLocker.unlock(unlockAmount, instantUnlockPeriod, ALICE); + + vm.startPrank(ALICE); + vm.expectRevert(IFluidLocker.FORBIDDEN.selector); + aliceLocker.unlock(unlockAmount, instantUnlockPeriod, address(0)); + + vm.expectRevert(IFluidLocker.INSUFFICIENT_AVAILABLE_BALANCE.selector); + aliceLocker.unlock(invalidUnlockAmount, instantUnlockPeriod, ALICE); + + aliceLocker.unlock(unlockAmount, instantUnlockPeriod, ALICE); + vm.stopPrank(); + + (uint256 amountToUser, int96 flowRateToStaker, int96 flowRateToLP) = + _helperCalculateTaxDisitrutionInstantUnlock(unlockAmount); + + (, int96 actualLPFlowRate) = _fluid.estimateFlowDistributionActualFlowRate( + address(_stakingRewardController), _stakingRewardController.lpDistributionPool(), flowRateToLP + ); + + (, int96 actualStakerFlowRate) = _fluid.estimateFlowDistributionActualFlowRate( + address(_stakingRewardController), _stakingRewardController.taxDistributionPool(), flowRateToStaker + ); + + assertEq( + _fluidSuperToken.balanceOf(address(ALICE)), + aliceBalanceBefore + amountToUser, + "incorrect ALICE balance after instant unlock" + ); + + assertEq( + _fluidSuperToken.balanceOf(address(aliceLocker)), + lockerBalanceBefore - unlockAmount, + "incorrect Locker balance after instant unlock" + ); + + assertEq( + _stakingRewardController.taxDistributionPool().getMemberFlowRate(address(bobLocker)), + actualStakerFlowRate, + "incorrect Bob Locker (staker) flow rate after instant unlock" + ); + + assertEq( + _stakingRewardController.lpDistributionPool().getMemberFlowRate(address(carolLocker)), + actualLPFlowRate, + "incorrect Carol Locker (provider) flow rate after instant unlock" + ); + } } - function testVestUnlock(uint128 unlockPeriod) external { + function testVestUnlock(uint128 unlockPeriod, uint256 unlockAmount) external { unlockPeriod = uint128(bound(unlockPeriod, _MIN_UNLOCK_PERIOD, _MAX_UNLOCK_PERIOD)); - uint256 funding = 10_000e18; - _helperFundLocker(address(aliceLocker), funding); + unlockAmount = bound(unlockAmount, 10e18, 100_000_000e18); + _helperFundLocker(address(aliceLocker), unlockAmount); - assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), funding, "incorrect Locker bal before op"); - assertEq(FluidLocker(address(aliceLocker)).fontaineCount(), 0, "incorrect fontaine count"); + assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), unlockAmount, "incorrect Locker bal before op"); + assertEq(FluidLocker(payable(address(aliceLocker))).fontaineCount(), 0, "incorrect fontaine count"); assertEq( - address(FluidLocker(address(aliceLocker)).fontaines(0)), + address(FluidLocker(payable(address(aliceLocker))).fontaines(0)), address(IFontaine(address(0))), - "incorrect fontaine addrfoess" + "incorrect fontaine address" ); - (int96 taxFlowRate, int96 unlockFlowRate) = _helperCalculateUnlockFlowRates(funding, unlockPeriod); + (int96 stakerFlowRate, int96 providerFlowRate, int96 unlockFlowRate) = + _helperCalculateFlowRatesVestUnlock(unlockAmount, unlockPeriod); vm.prank(ALICE); vm.expectRevert(IFluidLocker.TTE_NOT_ACTIVATED.selector); - aliceLocker.unlock(unlockPeriod, ALICE); + aliceLocker.unlock(unlockAmount, unlockPeriod, ALICE); _helperUpgradeLocker(); vm.prank(ALICE); - vm.expectRevert(IFluidLocker.TAX_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); - aliceLocker.unlock(unlockPeriod, ALICE); + vm.expectRevert(IFluidLocker.STAKER_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); + aliceLocker.unlock(unlockAmount, unlockPeriod, ALICE); - _helperBobStaking(); + _helperLockerStake(address(bobLocker)); vm.prank(ALICE); - aliceLocker.unlock(unlockPeriod, ALICE); + vm.expectRevert(IFluidLocker.LP_DISTRIBUTION_POOL_HAS_NO_UNITS.selector); + aliceLocker.unlock(unlockAmount, unlockPeriod, ALICE); + + _helperLockerProvideLiquidity(address(carolLocker)); - IFontaine newFontaine = FluidLocker(address(aliceLocker)).fontaines(0); + vm.prank(ALICE); + aliceLocker.unlock(unlockAmount, unlockPeriod, ALICE); + + IFontaine newFontaine = FluidLocker(payable(address(aliceLocker))).fontaines(0); + + (, int96 actualStakerFlowRate) = _fluid.estimateFlowDistributionActualFlowRate( + address(_stakingRewardController), _stakingRewardController.taxDistributionPool(), stakerFlowRate + ); + (, int96 actualProviderFlowRate) = _fluid.estimateFlowDistributionActualFlowRate( + address(_stakingRewardController), _stakingRewardController.lpDistributionPool(), providerFlowRate + ); assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), 0, "incorrect bal after op"); - assertEq( - ISuperToken(_fluidSuperToken).getFlowRate(address(newFontaine), ALICE), - unlockFlowRate, + assertApproxEqAbs( + uint96(ISuperToken(_fluidSuperToken).getFlowRate(address(newFontaine), ALICE)), + uint96(unlockFlowRate), + uint96(unlockFlowRate * 10 / 10000), "incorrect unlock flowrate" ); assertApproxEqAbs( - FluidLocker(address(aliceLocker)).TAX_DISTRIBUTION_POOL().getMemberFlowRate(address(bobLocker)), - taxFlowRate, - funding / 1e16, - "incorrect tax flowrate" + uint96(_stakingRewardController.taxDistributionPool().getMemberFlowRate(address(bobLocker))), + uint96(actualStakerFlowRate), + uint96(actualStakerFlowRate * 10 / 10000), + "incorrect staker flowrate" + ); + assertApproxEqAbs( + uint96(_stakingRewardController.lpDistributionPool().getMemberFlowRate(address(carolLocker))), + uint96(actualProviderFlowRate), + uint96(actualProviderFlowRate * 10 / 10000), + "incorrect provider flowrate" ); } - function testStake() external { - uint256 funding = 10_000e18; - _helperFundLocker(address(aliceLocker), funding); - assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), funding, "incorrect Locker bal before op"); - assertEq(aliceLocker.getAvailableBalance(), funding, "incorrect available bal before op"); + function testStake(uint256 amountToStake1, uint256 amountToStake2) external virtual { + amountToStake1 = bound(amountToStake1, 1, 100_000_000 ether); + amountToStake2 = bound(amountToStake2, 1, 100_000_000 ether); + _helperFundLocker(address(aliceLocker), amountToStake1); + assertEq(_fluidSuperToken.balanceOf(address(aliceLocker)), amountToStake1, "incorrect Locker bal before op"); + assertEq(aliceLocker.getAvailableBalance(), amountToStake1, "incorrect available bal before op"); assertEq(aliceLocker.getStakedBalance(), 0, "incorrect staked bal before op"); vm.prank(ALICE); vm.expectRevert(IFluidLocker.TTE_NOT_ACTIVATED.selector); - aliceLocker.stake(); + aliceLocker.stake(amountToStake1); _helperUpgradeLocker(); vm.prank(ALICE); - aliceLocker.stake(); + aliceLocker.stake(amountToStake1); assertEq(aliceLocker.getAvailableBalance(), 0, "incorrect available bal after op"); - assertEq(aliceLocker.getStakedBalance(), funding, "incorrect staked bal after op"); + assertEq(aliceLocker.getStakedBalance(), amountToStake1, "incorrect staked bal after op"); assertEq( _stakingRewardController.taxDistributionPool().getUnits(address(aliceLocker)), - funding / 1e16, + amountToStake1 / _STAKING_UNIT_DOWNSCALER, "incorrect units" ); vm.prank(ALICE); - vm.expectRevert(IFluidLocker.NO_FLUID_TO_STAKE.selector); - aliceLocker.stake(); + vm.expectRevert(IFluidLocker.INSUFFICIENT_AVAILABLE_BALANCE.selector); + aliceLocker.stake(amountToStake2); } - function _helperUpgradeLocker() internal { - UpgradeableBeacon beacon = _fluidLockerFactory.LOCKER_BEACON(); + function testUnstake(uint256 amountToStake, uint256 amountToUnstake, uint256 invalidAmountToUnstake) + external + virtual + { + amountToStake = bound(amountToStake, 1, 100_000_000 ether); + vm.assume(amountToUnstake <= amountToStake); + vm.assume(invalidAmountToUnstake > amountToStake); - vm.prank(ADMIN); - beacon.upgradeTo(_unlockableLockerLogic); - } + _helperFundLocker(address(aliceLocker), amountToStake); - function _helperBobStaking() internal { - _helperFundLocker(address(bobLocker), 10_000e18); - vm.prank(BOB); - bobLocker.stake(); - } + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.TTE_NOT_ACTIVATED.selector); + aliceLocker.unstake(amountToUnstake); - function _helperCalculateUnlockFlowRates(uint256 amountToUnlock, uint128 unlockPeriod) - internal - pure - returns (int96 taxFlowRate, int96 unlockFlowRate) - { - int96 globalFlowRate = int256(amountToUnlock / unlockPeriod).toInt96(); + _helperUpgradeLocker(); + + vm.startPrank(ALICE); + aliceLocker.stake(amountToStake); + + assertEq(aliceLocker.getAvailableBalance(), 0, "incorrect available bal before op"); + assertEq(aliceLocker.getStakedBalance(), amountToStake, "incorrect staked bal before op"); + assertEq( + _stakingRewardController.taxDistributionPool().getUnits(address(aliceLocker)), + amountToStake / _STAKING_UNIT_DOWNSCALER, + "incorrect units before op" + ); - unlockFlowRate = (globalFlowRate * int256(getUnlockingPercentage(unlockPeriod))).toInt96() - / int256(_BP_DENOMINATOR).toInt96(); - taxFlowRate = globalFlowRate - unlockFlowRate; + vm.expectRevert(IFluidLocker.STAKING_COOLDOWN_NOT_ELAPSED.selector); + aliceLocker.unstake(amountToUnstake); + + vm.warp(uint256(FluidLocker(payable(address(aliceLocker))).stakingUnlocksAt()) + 1); + aliceLocker.unstake(amountToUnstake); + + assertEq(aliceLocker.getAvailableBalance(), amountToUnstake, "incorrect available bal after op"); + assertEq(aliceLocker.getStakedBalance(), amountToStake - amountToUnstake, "incorrect staked bal after op"); + assertEq( + _stakingRewardController.taxDistributionPool().getUnits(address(aliceLocker)), + (amountToStake - amountToUnstake) / _STAKING_UNIT_DOWNSCALER, + "incorrect units after op" + ); + + vm.expectRevert(IFluidLocker.INSUFFICIENT_STAKED_BALANCE.selector); + aliceLocker.unstake(invalidAmountToUnstake); + + vm.stopPrank(); } // Note: golden (characteristic) test @@ -776,14 +1033,14 @@ contract FluidLockerTTETest is SFTest { uint256 unlockPercentage = getUnlockingPercentage(unlockPeriod); assertGe(unlockPercentage, 3107, "shouldnt be any smaller"); - assertLe(unlockPercentage, 10000, "shouldnt be any larger"); + assertLe(unlockPercentage, 10_000, "shouldnt be any larger"); // Test different periods assertEq(getUnlockingPercentage(7 days), 3107, "should be 3107"); assertEq(getUnlockingPercentage(30 days), 4293, "should be 4293"); assertEq(getUnlockingPercentage(90 days), 5972, "should be 5972"); assertEq(getUnlockingPercentage(180 days), 7617, "should be 7617"); - assertEq(getUnlockingPercentage(365 days), 10000, "should be 10000"); + assertEq(getUnlockingPercentage(365 days), 10_000, "should be 10000"); } // Note: property based testing @@ -805,41 +1062,532 @@ contract FluidLockerTTETest is SFTest { uint256 amount = 1 ether; // Test different periods - (int96 unlockFlowRate, int96 taxFlowRate) = calculateVestUnlockFlowRates(amount, 7 days); - assertEq(unlockFlowRate, 513_723_544_973, "(7 days) unlock flow rate should be 513723544973"); - assertEq(taxFlowRate, 1_139_715_608_466, "(7 days) tax flow rate should be 1139715608466"); - - (unlockFlowRate, taxFlowRate) = calculateVestUnlockFlowRates(amount, 30 days); - assertEq(unlockFlowRate, 165_624_999_999, "(30 days) unlock flow rate should be 165624999999"); - assertEq(taxFlowRate, 220_177_469_136, "(30 days) tax flow rate should be 220177469136"); - - (unlockFlowRate, taxFlowRate) = calculateVestUnlockFlowRates(amount, 90 days); - assertEq(unlockFlowRate, 76_800_411_522, "(90 days) unlock flow rate should be 76800411522"); - assertEq(taxFlowRate, 51_800_411_523, "(90 days) tax flow rate should be 51800411523"); - - (unlockFlowRate, taxFlowRate) = calculateVestUnlockFlowRates(amount, 180 days); - assertEq(unlockFlowRate, 48_977_623_456, "(180 days) unlock flow rate should be 48977623456"); - assertEq(taxFlowRate, 15_322_788_066, "(180 days) tax flow rate should be 15322788066"); - - (unlockFlowRate, taxFlowRate) = calculateVestUnlockFlowRates(amount, 365 days); - assertEq(unlockFlowRate, 31_709_791_983, "(365 days) unlock flow rate should be 31709791983"); - assertEq(taxFlowRate, 0, "(365 days) tax flow rate should be 0"); + (uint256 unlockAmount, uint256 taxAmount) = calculateVestUnlockAmounts(amount, 7 days); + assertEq(unlockAmount, 310700000000000000, "(7 days) unlock amount should be 310700000000000000"); + assertEq(taxAmount, 689300000000000000, "(7 days) tax amount should be 689300000000000000"); + assertEq(unlockAmount + taxAmount, amount, "(7 days) unlock amount + tax amount should be equal to amount"); + + (unlockAmount, taxAmount) = calculateVestUnlockAmounts(amount, 30 days); + assertEq(unlockAmount, 429300000000000000, "(30 days) unlock amount should be 429300000000000000"); + assertEq(taxAmount, 570700000000000000, "(30 days) tax amount should be 570700000000000000"); + assertEq(unlockAmount + taxAmount, amount, "(30 days) unlock amount + tax amount should be equal to amount"); + + (unlockAmount, taxAmount) = calculateVestUnlockAmounts(amount, 90 days); + assertEq(unlockAmount, 597200000000000000, "(90 days) unlock amount should be 597200000000000000"); + assertEq(taxAmount, 402800000000000000, "(90 days) tax amount should be 402800000000000000"); + assertEq(unlockAmount + taxAmount, amount, "(90 days) unlock amount + tax amount should be equal to amount"); + + (unlockAmount, taxAmount) = calculateVestUnlockAmounts(amount, 180 days); + assertEq(unlockAmount, 761700000000000000, "(180 days) unlock amount should be 761700000000000000"); + assertEq(taxAmount, 238300000000000000, "(180 days) tax amount should be 238300000000000000"); + assertEq(unlockAmount + taxAmount, amount, "(180 days) unlock amount + tax amount should be equal to amount"); + + (unlockAmount, taxAmount) = calculateVestUnlockAmounts(amount, 365 days); + assertEq(unlockAmount, 1000000000000000000, "(365 days) unlock amount should be 1000000000000000000"); + assertEq(taxAmount, 0, "(365 days) tax amount should be 0"); + assertEq(unlockAmount + taxAmount, amount, "(365 days) unlock amount + tax amount should be equal to amount"); } - // Property : lower time-preference shall result in higher flowrate - function testCalculateVestUnlockFlowRatesStrictMonotonicity(uint128 t1, uint128 t2) public pure { + // Property : lower time-preference shall result in higher taxed amount and lower unlock amount + function testCalculateVestUnlockFlowRates(uint128 t1, uint128 t2) public pure { uint256 amount = 1 ether; - uint256 minDistance = 180 minutes; + uint256 minDistance = 80 minutes; t1 = uint128(bound(t1, _MIN_UNLOCK_PERIOD, _MAX_UNLOCK_PERIOD - minDistance)); t2 = uint128(bound(t2, t1 + minDistance, _MAX_UNLOCK_PERIOD)); console2.log("using t1 t2", t1, t2); - (int96 ur1, int96 tr1) = calculateVestUnlockFlowRates(amount, t1); - (int96 ur2, int96 tr2) = calculateVestUnlockFlowRates(amount, t2); - assertGe(ur1, ur2, "unlock rate monotonicity violated"); - assertGe(tr1, tr2, "tax rate monotonicity violated"); + (uint256 userUnlockAmount1, uint256 taxAmount1) = calculateVestUnlockAmounts(amount, t1); + (uint256 userUnlockAmount2, uint256 taxAmount2) = calculateVestUnlockAmounts(amount, t2); + assertGe(userUnlockAmount2, userUnlockAmount1, "unlock amount monotonicity violated"); + assertGe(taxAmount1, taxAmount2, "tax amount monotonicity violated"); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // ________ _ ____ __ _ _____ ______ __ + // / ____/ /_ __(_)___/ / / ____ _____/ /_____ _____ | | / /__ \ /_ __/__ _____/ /______ + // / /_ / / / / / / __ / / / __ \/ ___/ //_/ _ \/ ___/ | | / /__/ / / / / _ \/ ___/ __/ ___/ + // / __/ / / /_/ / / /_/ / /___/ /_/ / /__/ ,< / __/ / | |/ // __/ / / / __(__ ) /_(__ ) + // /_/ /_/\__,_/_/\__,_/_____/\____/\___/_/|_|\___/_/ |___//____/ /_/ \___/____/\__/____/ + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // 1 eth contribution : + // -> 0.01 eth to pump -> expected min sup = 0.01 * 20000 = 200 sup + // -> 0.99 eth to lp -> expected supLPAmount = 0.99 * 20000 = 19800 sup + function testV2ProvideLiquidity_createPosition(uint256 ethAmount) external { + ethAmount = bound(ethAmount, 0.001 ether, 1000 ether); + _helperUpgradeLocker(); + + uint256 supAmountToLP = ethAmount * 20_000 * 9900 / 10_000; + + _helperFundLocker(address(aliceLocker), supAmountToLP); + + vm.startPrank(ALICE); + aliceLocker.provideLiquidity{ value: ethAmount }(supAmountToLP); + vm.stopPrank(); + + uint256 positionCount = FluidLocker(payable(address(aliceLocker))).activePositionCount(); + assertEq(positionCount, 1, "position count should be 1"); + assertGt( + _nonfungiblePositionManager.tokenOfOwnerByIndex(address(aliceLocker), positionCount - 1), + 0, + "tokenId should not be 0" + ); + assertEq(_weth.balanceOf(address(aliceLocker)), 0, "weth locker balance should be 0"); + } + + function testV2CollectFees() external { + _helperUpgradeLocker(); + uint256 positionTokenId = _helperCreatePosition(address(aliceLocker), 1 ether, 20_000e18); + + uint256 aliceWethBalanceBefore = _weth.balanceOf(address(ALICE)); + uint256 aliceSupBalanceBefore = _fluidSuperToken.balanceOf(address(ALICE)); + + _helperBuySUP(makeAddr("buyer"), 10 ether); + _helperSellSUP(makeAddr("seller"), 200_000e18); + + vm.prank(ALICE); + aliceLocker.collectFees(positionTokenId); + + uint256 aliceWethBalanceAfter = _weth.balanceOf(address(ALICE)); + uint256 aliceSupBalanceAfter = _fluidSuperToken.balanceOf(address(ALICE)); + + assertGt(aliceWethBalanceAfter, aliceWethBalanceBefore, "alice weth balance should increase"); + assertGt(aliceSupBalanceAfter, aliceSupBalanceBefore, "alice sup balance should increase"); + } + + function testV2withdrawLiquidity_removeAllLiquidity_beforeTaxFreeWithdrawDelay(uint256 ethAmountToDeposit) + external + { + ethAmountToDeposit = bound(ethAmountToDeposit, 0.001 ether, 1000 ether); + _helperUpgradeLocker(); + + uint256 supAmountToLP = ethAmountToDeposit * 20_000 * 9900 / 10_000; + uint256 positionTokenId = _helperCreatePosition(address(aliceLocker), ethAmountToDeposit, supAmountToLP); + + _helperSellSUP(makeAddr("seller"), 200_000e18); + + (,,,,,,, uint128 positionLiquidity,,,,) = _nonfungiblePositionManager.positions(positionTokenId); + (uint256 amount0ToRemove, uint256 amount1ToRemove) = _helperGetAmountsForLiquidity(_pool, positionLiquidity); + + uint256 expectedEthReceived = _pool.token0() == address(_weth) ? amount0ToRemove : amount1ToRemove; + uint256 expectedSupBackInLocker = + _pool.token0() == address(_fluidSuperToken) ? amount0ToRemove : amount1ToRemove; + + uint256 ethBalanceBefore = ALICE.balance; + uint256 supInLockerBefore = _fluidSuperToken.balanceOf(address(aliceLocker)); + + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.LP_COOLDOWN_NOT_ELAPSED.selector); + aliceLocker.withdrawLiquidity(positionTokenId, positionLiquidity, amount0ToRemove, amount1ToRemove); + + vm.warp(uint256(FluidLocker(payable(address(aliceLocker))).lpCooldownTimestamps(positionTokenId))); + vm.prank(ALICE); + aliceLocker.withdrawLiquidity(positionTokenId, positionLiquidity, amount0ToRemove, amount1ToRemove); + + uint256 ethBalanceAfter = ALICE.balance; + uint256 supInLockerAfter = _fluidSuperToken.balanceOf(address(aliceLocker)); + + assertApproxEqAbs( + ethBalanceAfter, + ethBalanceBefore + expectedEthReceived, + ethBalanceAfter * 10 / 10_000, // 0.1% tolerance + "Alice ETH balance should increase" + ); + assertApproxEqAbs( + supInLockerAfter, + supInLockerBefore + expectedSupBackInLocker, + supInLockerAfter * 10 / 10_000, // 0.1% tolerance + "SUP balance in locker should increase" + ); + + assertEq(FluidLocker(payable(address(aliceLocker))).activePositionCount(), 0, "position count should be 0"); + assertEq( + FluidLocker(payable(address(aliceLocker))).taxFreeExitTimestamps(positionTokenId), + 0, + "position exit timestamp should be 0" + ); + } + + function testV2withdrawLiquidity_removePartialLiquidity(uint256 ethAmountToDeposit, uint256 liquidityPercentage) + external + { + ethAmountToDeposit = bound(ethAmountToDeposit, 0.001 ether, 1000 ether); + _helperUpgradeLocker(); + + uint256 supAmountToLP = ethAmountToDeposit * 20_000 * 9900 / 10_000; + uint256 positionTokenId = _helperCreatePosition(address(aliceLocker), ethAmountToDeposit, supAmountToLP); + + uint256 initialTaxFreeExitTimestamp = + FluidLocker(payable(address(aliceLocker))).taxFreeExitTimestamps(positionTokenId); + + _helperBuySUP(makeAddr("buyer"), 10 ether); + _helperSellSUP(makeAddr("seller"), 200_000e18); + + (,,,,,,, uint128 positionLiquidity,,,,) = _nonfungiblePositionManager.positions(positionTokenId); + + // Randomized partial liquidity removal : 1% to 99% of the liquidity + liquidityPercentage = uint256(bound(liquidityPercentage, 100, 9900)); + + uint128 liquidityToRemove = uint128((positionLiquidity * liquidityPercentage) / _BP_DENOMINATOR); + + (uint256 amount0ToRemove, uint256 amount1ToRemove) = _helperGetAmountsForLiquidity(_pool, liquidityToRemove); + + uint256 expectedWethReceived = _pool.token0() == address(_weth) ? amount0ToRemove : amount1ToRemove; + uint256 expectedSupBackInLocker = + _pool.token0() == address(_fluidSuperToken) ? amount0ToRemove : amount1ToRemove; + + uint256 ethBalanceBefore = ALICE.balance; + uint256 supInLockerBefore = _fluidSuperToken.balanceOf(address(aliceLocker)); + + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.LP_COOLDOWN_NOT_ELAPSED.selector); + aliceLocker.withdrawLiquidity(positionTokenId, liquidityToRemove, amount0ToRemove, amount1ToRemove); + + vm.warp(uint256(FluidLocker(payable(address(aliceLocker))).lpCooldownTimestamps(positionTokenId))); + vm.prank(ALICE); + aliceLocker.withdrawLiquidity(positionTokenId, liquidityToRemove, amount0ToRemove, amount1ToRemove); + + uint256 ethBalanceAfter = ALICE.balance; + uint256 supInLockerAfter = _fluidSuperToken.balanceOf(address(aliceLocker)); + + // Eq because of the fees are accounted in WETH + assertApproxEqAbs( + ethBalanceAfter, + ethBalanceBefore + expectedWethReceived, + ethBalanceAfter * 10 / 1000, + "WETH balance should increase" + ); + + // Eq because the fees are collected in the locker owner address + assertApproxEqAbs( + supInLockerAfter, + supInLockerBefore + expectedSupBackInLocker, + supInLockerAfter * 10 / 10_000, // 0.1% tolerance + "SUP balance in locker should increase" + ); + assertEq( + FluidLocker(payable(address(aliceLocker))).activePositionCount(), 1, "position count should still be 1" + ); + assertEq( + FluidLocker(payable(address(aliceLocker))).taxFreeExitTimestamps(positionTokenId), + initialTaxFreeExitTimestamp, + "position exit timestamp should remain the same" + ); + } + + function testV2withdrawLiquidity_removeAllLiquidity_afterTaxFreeWithdrawDelay(uint256 ethAmountToDeposit) + external + { + ethAmountToDeposit = bound(ethAmountToDeposit, 0.001 ether, 1000 ether); + _helperUpgradeLocker(); + + uint256 supAmountToLP = ethAmountToDeposit * 20_000 * 9900 / 10_000; + uint256 positionTokenId = _helperCreatePosition(address(aliceLocker), ethAmountToDeposit, supAmountToLP); + + _helperSellSUP(makeAddr("seller"), 200_000e18); + + (,,,,,,, uint128 positionLiquidity,,,,) = _nonfungiblePositionManager.positions(positionTokenId); + (uint256 amount0ToRemove, uint256 amount1ToRemove) = _helperGetAmountsForLiquidity(_pool, positionLiquidity); + + uint256 expectedEthReceived = _pool.token0() == address(_weth) ? amount0ToRemove : amount1ToRemove; + uint256 expectedSupBack = _pool.token0() == address(_fluidSuperToken) ? amount0ToRemove : amount1ToRemove; + + uint256 ethBalanceBefore = ALICE.balance; + uint256 supInLockerBefore = _fluidSuperToken.balanceOf(address(aliceLocker)); + uint256 supInAliceBefore = _fluidSuperToken.balanceOf(address(ALICE)); + + vm.warp(block.timestamp + FluidLocker(payable(address(aliceLocker))).TAX_FREE_WITHDRAW_DELAY()); + + vm.prank(ALICE); + aliceLocker.withdrawLiquidity(positionTokenId, positionLiquidity, amount0ToRemove, amount1ToRemove); + + uint256 ethBalanceAfter = ALICE.balance; + uint256 supInLockerAfter = _fluidSuperToken.balanceOf(address(aliceLocker)); + uint256 supInAliceAfter = _fluidSuperToken.balanceOf(address(ALICE)); + + assertApproxEqAbs( + ethBalanceAfter, + ethBalanceBefore + expectedEthReceived, + ethBalanceAfter * 10 / 10_000, // 0.1% tolerance + "Alice ETH balance should increase" + ); + assertApproxEqAbs( + supInAliceAfter, + supInAliceBefore + expectedSupBack, + supInAliceAfter * 10 / 10_000, // 0.1% tolerance + "SUP balance in Alice wallet should increase" + ); + + assertEq(supInLockerAfter, supInLockerBefore, "SUP balance in locker should not change"); + assertEq(FluidLocker(payable(address(aliceLocker))).activePositionCount(), 0, "position count should be 0"); + } + + function testV2withdrawLiquidity_removeAllLiquidity_withFeeInPosition(uint256 ethAmountToDeposit) external { + ethAmountToDeposit = bound(ethAmountToDeposit, 0.001 ether, 1000 ether); + _helperUpgradeLocker(); + + uint256 supAmountToLP = ethAmountToDeposit * 20_000 * 9900 / 10_000; + uint256 positionTokenId = _helperCreatePosition(address(aliceLocker), ethAmountToDeposit, supAmountToLP); + + _helperBuySUP(makeAddr("buyer"), 10 ether); + _helperSellSUP(makeAddr("seller"), 200_000e18); + + (,,,,,,, uint128 positionLiquidity,,,,) = _nonfungiblePositionManager.positions(positionTokenId); + (uint256 amount0ToRemove, uint256 amount1ToRemove) = _helperGetAmountsForLiquidity(_pool, positionLiquidity); + + uint256 expectedEthReceived = _pool.token0() == address(_weth) ? amount0ToRemove : amount1ToRemove; + uint256 expectedSupBack = _pool.token0() == address(_fluidSuperToken) ? amount0ToRemove : amount1ToRemove; + + uint256 ethBalanceBefore = ALICE.balance; + uint256 supInLockerBefore = _fluidSuperToken.balanceOf(address(aliceLocker)); + uint256 supInAliceBefore = _fluidSuperToken.balanceOf(address(ALICE)); + + vm.warp(block.timestamp + FluidLocker(payable(address(aliceLocker))).TAX_FREE_WITHDRAW_DELAY()); + + vm.prank(ALICE); + aliceLocker.withdrawLiquidity(positionTokenId, positionLiquidity, amount0ToRemove, amount1ToRemove); + + uint256 ethBalanceAfter = ALICE.balance; + uint256 supInLockerAfter = _fluidSuperToken.balanceOf(address(aliceLocker)); + uint256 supInAliceAfter = _fluidSuperToken.balanceOf(address(ALICE)); + + assertApproxEqAbs( + ethBalanceAfter, + ethBalanceBefore + expectedEthReceived, + ethBalanceAfter * 10 / 10_000, // 0.1% tolerance + "Alice ETH balance should increase" + ); + assertApproxEqAbs( + supInAliceAfter, + supInAliceBefore + expectedSupBack, + supInAliceAfter * 10 / 10_000, // 0.1% tolerance + "SUP balance in Alice wallet should increase" + ); + + assertEq(supInLockerAfter, supInLockerBefore, "SUP balance in locker should not change"); + assertEq(FluidLocker(payable(address(aliceLocker))).activePositionCount(), 0, "position count should be 0"); + } + + function testV2withdrawLiquidity_removePartialLiquidity_beforeAndAfterTaxFreeWithdrawDelay( + uint256 ethAmountToDeposit, + uint256 liquidityPercentage + ) external { + ethAmountToDeposit = bound(ethAmountToDeposit, 0.001 ether, 1000 ether); + _helperUpgradeLocker(); + + uint256 supAmountToLP = ethAmountToDeposit * 20_000 * 9900 / 10_000; + uint256 positionTokenId = _helperCreatePosition(address(aliceLocker), ethAmountToDeposit, supAmountToLP); + + _helperBuySUP(makeAddr("buyer"), 10 ether); + _helperSellSUP(makeAddr("seller"), 200_000e18); + + (,,,,,,, uint128 positionLiquidity,,,,) = _nonfungiblePositionManager.positions(positionTokenId); + + // Randomized partial liquidity removal : 1% to 99% of the liquidity + liquidityPercentage = uint256(bound(liquidityPercentage, 100, 9900)); + + uint128 liquidityToRemove = uint128((positionLiquidity * liquidityPercentage) / _BP_DENOMINATOR); + + (uint256 amount0ToRemove, uint256 amount1ToRemove) = _helperGetAmountsForLiquidity(_pool, liquidityToRemove); + + uint256 expectedEthReceived = _pool.token0() == address(_weth) ? amount0ToRemove : amount1ToRemove; + uint256 expectedSupBack = _pool.token0() == address(_fluidSuperToken) ? amount0ToRemove : amount1ToRemove; + + uint256 ethBalanceBefore = ALICE.balance; + uint256 supInLockerBefore = _fluidSuperToken.balanceOf(address(aliceLocker)); + + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.LP_COOLDOWN_NOT_ELAPSED.selector); + aliceLocker.withdrawLiquidity(positionTokenId, liquidityToRemove, amount0ToRemove, amount1ToRemove); + + vm.warp(uint256(FluidLocker(payable(address(aliceLocker))).lpCooldownTimestamps(positionTokenId))); + vm.prank(ALICE); + aliceLocker.withdrawLiquidity(positionTokenId, liquidityToRemove, amount0ToRemove, amount1ToRemove); + + uint256 ethBalanceAfter = ALICE.balance; + uint256 supInLockerAfter = _fluidSuperToken.balanceOf(address(aliceLocker)); + + // Eq because the fees are collected in the locker owner address + assertApproxEqAbs( + ethBalanceAfter, + ethBalanceBefore + expectedEthReceived, + ethBalanceAfter * 10 / 1000, + "WETH balance should increase" + ); + + // Eq because the fees are collected in the locker owner address + assertApproxEqAbs( + supInLockerAfter, + supInLockerBefore + expectedSupBack, + supInLockerAfter * 10 / 10_000, // 0.1% tolerance + "SUP balance in locker should increase" + ); + + (,,,,,,, positionLiquidity,,,,) = _nonfungiblePositionManager.positions(positionTokenId); + + (amount0ToRemove, amount1ToRemove) = _helperGetAmountsForLiquidity(_pool, positionLiquidity); + + expectedEthReceived = _pool.token0() == address(_weth) ? amount0ToRemove : amount1ToRemove; + expectedSupBack = _pool.token0() == address(_fluidSuperToken) ? amount0ToRemove : amount1ToRemove; + + ethBalanceBefore = ALICE.balance; + supInLockerBefore = _fluidSuperToken.balanceOf(address(aliceLocker)); + uint256 supInAliceBefore = _fluidSuperToken.balanceOf(address(ALICE)); + + vm.warp(block.timestamp + FluidLocker(payable(address(aliceLocker))).TAX_FREE_WITHDRAW_DELAY()); + + vm.prank(ALICE); + aliceLocker.withdrawLiquidity(positionTokenId, positionLiquidity, amount0ToRemove, amount1ToRemove); + + ethBalanceAfter = ALICE.balance; + supInLockerAfter = _fluidSuperToken.balanceOf(address(aliceLocker)); + uint256 supInAliceAfter = _fluidSuperToken.balanceOf(address(ALICE)); + + assertApproxEqAbs( + ethBalanceAfter, + ethBalanceBefore + expectedEthReceived, + ethBalanceAfter * 10 / 10_000, + "ETH balance should increase after tax free withdraw" + ); + assertEq(supInLockerAfter, supInLockerBefore, "SUP balance in locker should not change after tax free withdraw"); + assertApproxEqAbs( + supInAliceAfter, + supInAliceBefore + expectedSupBack, + supInAliceAfter * 10 / 10_000, + "SUP balance in Alice wallet should increase after tax free withdraw" + ); + assertEq(FluidLocker(payable(address(aliceLocker))).activePositionCount(), 0, "position count should be 0"); + } + + function testV2withdrawLiquidity_lockerHasNoPosition(uint256 inexistantPositionTokenId) external { + _helperUpgradeLocker(); + + uint128 positionLiquidity = 1e18; + (uint256 amount0ToRemove, uint256 amount1ToRemove) = _helperGetAmountsForLiquidity(_pool, positionLiquidity); + + vm.prank(ALICE); + vm.expectRevert(IFluidLocker.LOCKER_HAS_NO_POSITION.selector); + aliceLocker.withdrawLiquidity(inexistantPositionTokenId, positionLiquidity, amount0ToRemove, amount1ToRemove); + } + + function testV2withdrawDustETH(address _nonLockerOwner, uint256 ethAmount) external { + vm.assume(_nonLockerOwner != ALICE); + ethAmount = uint256(bound(ethAmount, 1, 1_000_000_000 ether)); + + _helperUpgradeLocker(); + + vm.deal(address(aliceLocker), ethAmount); + + vm.prank(_nonLockerOwner); + vm.expectRevert(IFluidLocker.NOT_LOCKER_OWNER.selector); + aliceLocker.withdrawDustETH(); + + uint256 ethBalanceBefore = ALICE.balance; + vm.prank(ALICE); + aliceLocker.withdrawDustETH(); + uint256 ethBalanceAfter = ALICE.balance; + + assertEq(ethBalanceAfter, ethBalanceBefore + ethAmount, "ETH balance in ALICE walletshould increase"); + } + + function testV2provideLiquidityWhileStaking_shortageCompensation() external virtual { + uint256 fundingAmount = 100e18; + + _helperUpgradeLocker(); + + assertEq(aliceLocker.getStakedBalance(), 0, "incorrect staked before funding"); + assertEq(aliceLocker.getAvailableBalance(), 0, "incorrect available before funding"); + + // Set up Alice's Locker to be functional + _helperFundLocker(address(aliceLocker), fundingAmount); + + vm.startPrank(ALICE); + + //Stake all avaialble tokens + aliceLocker.stake(fundingAmount); + + uint256 stakedBalanceBeforeLP = aliceLocker.getStakedBalance(); + assertEq(stakedBalanceBeforeLP, fundingAmount, "incorrect staked before LP"); + + //Provide liquidity using the staked tokens (should forcefully unstake the shortage amount to provide liquidity) + aliceLocker.provideLiquidity{ value: fundingAmount / (2 * 9900) }(fundingAmount); + + uint256 stakedBalanceAfterLP = aliceLocker.getStakedBalance(); + assertGt(stakedBalanceBeforeLP, stakedBalanceAfterLP, "incorrect staked after LP"); + + // Unstake all staked tokens (should revert as cooldown is not elapsed) + vm.expectRevert(IFluidLocker.STAKING_COOLDOWN_NOT_ELAPSED.selector); + aliceLocker.unstake(stakedBalanceAfterLP); + + vm.warp(block.timestamp + _STAKING_COOLDOWN_PERIOD + 1); + aliceLocker.unstake(stakedBalanceAfterLP); + + vm.stopPrank(); + } + + function testV2provideLiquidityWhileStaking_noShortageCompensationNeeded() external virtual { + uint256 fundingAmount = 200e18; + uint256 stakingAmount = 100e18; + uint256 lpAmount = 100e18; + + _helperUpgradeLocker(); + + assertEq(aliceLocker.getStakedBalance(), 0, "incorrect staked before funding"); + assertEq(aliceLocker.getAvailableBalance(), 0, "incorrect available before funding"); + + // Set up Alice's Locker to be functional + _helperFundLocker(address(aliceLocker), fundingAmount); + + vm.startPrank(ALICE); + + //Stake all avaialble tokens + aliceLocker.stake(stakingAmount); + + uint256 stakedBalanceBeforeLP = aliceLocker.getStakedBalance(); + assertEq(stakedBalanceBeforeLP, stakingAmount, "incorrect staked before LP"); + + //Provide liquidity using the staked tokens (should forcefully unstake the shortage amount to provide liquidity) + aliceLocker.provideLiquidity{ value: lpAmount / (2 * 9900) }(lpAmount); + + uint256 stakedBalanceAfterLP = aliceLocker.getStakedBalance(); + assertEq(stakedBalanceBeforeLP, stakedBalanceAfterLP, "incorrect staked after LP"); + + vm.stopPrank(); + } + + function testV2provideLiquidityWhileStaking_notEnoughStakedForShortageCompensation() external virtual { + uint256 fundingAmount = 100e18; + uint256 lpAmount = 200e18; + + _helperUpgradeLocker(); + + assertEq(aliceLocker.getStakedBalance(), 0, "incorrect staked before funding"); + assertEq(aliceLocker.getAvailableBalance(), 0, "incorrect available before funding"); + + // Set up Alice's Locker to be functional + _helperFundLocker(address(aliceLocker), fundingAmount); + + vm.startPrank(ALICE); + + //Stake all avaialble tokens + aliceLocker.stake(fundingAmount); + + uint256 stakedBalanceBeforeLP = aliceLocker.getStakedBalance(); + assertEq(stakedBalanceBeforeLP, fundingAmount, "incorrect staked before LP"); + + //Provide liquidity using the staked tokens (should forcefully unstake the shortage amount to provide liquidity) + vm.expectRevert(IFluidLocker.INSUFFICIENT_AVAILABLE_BALANCE.selector); + aliceLocker.provideLiquidity{ value: fundingAmount / (2 * 9900) }(lpAmount); + } + + function _helperUpgradeLocker() internal { + UpgradeableBeacon beacon = _fluidLockerFactory.LOCKER_BEACON(); + + vm.prank(ADMIN); + beacon.upgradeTo(_unlockableLockerLogic); } } @@ -847,45 +1595,47 @@ contract FluidLockerLayoutTest is FluidLocker { constructor() FluidLocker( ISuperToken(address(0)), - ISuperfluidPool(address(0)), IEPProgramManager(address(0)), IStakingRewardController(address(0)), address(0), - true + true, + INonfungiblePositionManager(address(0)), + IUniswapV3Pool(address(0)), + IV3SwapRouter(address(0)) ) { } - function testStorageLayout() external pure { - uint256 slot; - uint256 offset; - - // FluidLocker storage - - assembly { - slot := lockerOwner.slot - offset := lockerOwner.offset - } - require(slot == 0 && offset == 0, "lockerOwner changed location"); - - assembly { - slot := stakingUnlocksAt.slot - offset := stakingUnlocksAt.offset - } - require(slot == 0 && offset == 20, "stakingUnlocksAt changed location"); - - assembly { - slot := fontaineCount.slot - offset := fontaineCount.offset - } - require(slot == 0 && offset == 30, "fontaineCount changed location"); - - // private state : _stakedBalance - // slot = 1 - offset = 0 - - assembly { - slot := fontaines.slot - offset := fontaines.offset - } - require(slot == 2 && offset == 0, "fontaines changed location"); - } + // function testStorageLayout() external pure { + // uint256 slot; + // uint256 offset; + + // // FluidLocker storage + + // assembly { + // slot := lockerOwner.slot + // offset := lockerOwner.offset + // } + // require(slot == 0 && offset == 0, "lockerOwner changed location"); + + // assembly { + // slot := stakingUnlocksAt.slot + // offset := stakingUnlocksAt.offset + // } + // require(slot == 0 && offset == 20, "stakingUnlocksAt changed location"); + + // assembly { + // slot := fontaineCount.slot + // offset := fontaineCount.offset + // } + // require(slot == 0 && offset == 30, "fontaineCount changed location"); + + // // private state : _stakedBalance + // // slot = 1 - offset = 0 + + // assembly { + // slot := fontaines.slot + // offset := fontaines.offset + // } + // require(slot == 2 && offset == 0, "fontaines changed location"); + // } } diff --git a/packages/contracts/test/Fontaine.t.sol b/packages/contracts/test/Fontaine.t.sol index fadedb8..18a88e4 100644 --- a/packages/contracts/test/Fontaine.t.sol +++ b/packages/contracts/test/Fontaine.t.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.23; -import { console2 } from "forge-std/Test.sol"; - import { SFTest } from "./SFTest.t.sol"; import { SafeCast } from "@openzeppelin-v5/contracts/utils/math/SafeCast.sol"; import { BeaconProxy } from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; @@ -16,7 +14,7 @@ import { SuperTokenV1Library } from "@superfluid-finance/ethereum-contracts/cont import { IFluidLocker } from "../src/FluidLocker.sol"; import { IFontaine } from "../src/interfaces/IFontaine.sol"; import { Fontaine } from "../src/Fontaine.sol"; -import { calculateVestUnlockFlowRates } from "../src/FluidLocker.sol"; +import { calculateVestUnlockAmounts } from "../src/FluidLocker.sol"; using SuperTokenV1Library for ISuperToken; using SafeCast for int256; @@ -24,47 +22,43 @@ using SafeCast for int256; contract FontaineTest is SFTest { uint128 internal constant _MIN_UNLOCK_PERIOD = 7 days; uint128 internal constant _MAX_UNLOCK_PERIOD = 365 days; + uint256 internal constant _EARLY_END_DELAY = 1 days; uint256 internal constant _BP_DENOMINATOR = 10_000; uint256 internal constant _SCALER = 1e18; IFluidLocker public bobLocker; + IFluidLocker public carolLocker; function setUp() public virtual override { super.setUp(); vm.prank(BOB); bobLocker = IFluidLocker(_fluidLockerFactory.createLockerContract()); + + vm.prank(CAROL); + carolLocker = IFluidLocker(_fluidLockerFactory.createLockerContract()); } function testInitialize(uint128 unlockPeriod, uint256 unlockAmount) external { + // Bound Fuzz Parameters unlockPeriod = uint128(bound(unlockPeriod, _MIN_UNLOCK_PERIOD, _MAX_UNLOCK_PERIOD)); unlockAmount = bound(unlockAmount, 1e18, 100_000_000e18); - _helperBobStaking(); - (int96 taxFlowRate, int96 unlockFlowRate) = _helperCalculateUnlockFlowRates(unlockAmount, unlockPeriod); + int96 unlockFlowRate = int256(unlockAmount / unlockPeriod).toInt96(); + // Create and fund the Fontaine address newFontaine = _helperCreateFontaine(); - - address user = makeAddr("user"); vm.prank(FLUID_TREASURY); _fluid.transfer(newFontaine, unlockAmount); - IFontaine(newFontaine).initialize(user, unlockFlowRate, taxFlowRate, unlockPeriod); - - assertEq(Fontaine(newFontaine).endDate(), uint128(block.timestamp) + unlockPeriod, "end date incorreclty set"); - assertEq(Fontaine(newFontaine).taxFlowRate(), uint96(taxFlowRate), "tax flow rate incorreclty set"); - assertEq(Fontaine(newFontaine).unlockFlowRate(), uint96(unlockFlowRate), "unlock flow rate incorreclty set"); - - (, int96 actualTaxFlowRate) = _fluid.estimateFlowDistributionActualFlowRate( - newFontaine, Fontaine(newFontaine).TAX_DISTRIBUTION_POOL(), taxFlowRate - ); - - assertEq( - _fluid.getFlowDistributionFlowRate(newFontaine, Fontaine(newFontaine).TAX_DISTRIBUTION_POOL()), - actualTaxFlowRate, - "incorrect tax flowrate" - ); + // Initialize the Fontaine + address user = makeAddr("user"); + IFontaine(newFontaine).initialize(user, unlockFlowRate, unlockPeriod); + // Assert the Fontaine is initialized correctly + assertEq(Fontaine(newFontaine).recipient(), user, "recipient incorrect"); + assertEq(Fontaine(newFontaine).endDate(), uint128(block.timestamp) + unlockPeriod, "end date incorrect"); + assertEq(Fontaine(newFontaine).unlockFlowRate(), uint96(unlockFlowRate), "unlock flow rate incorrect"); assertEq(_fluid.getFlowRate(newFontaine, user), unlockFlowRate, "incorrect unlock flowrate"); } @@ -74,28 +68,27 @@ contract FontaineTest is SFTest { uint128 terminationDelay, uint128 tooEarlyDelay ) external { + // Bound Fuzz Parameters + /// NOTE : issues will arise if the unlock amount is too low (less than 10 SUP) + unlockAmount = bound(unlockAmount, 10e18, 100_000_000e18); unlockPeriod = uint128(bound(unlockPeriod, _MIN_UNLOCK_PERIOD, _MAX_UNLOCK_PERIOD)); - unlockAmount = bound(unlockAmount, 1e18, 100_000_000e18); - terminationDelay = uint128(bound(terminationDelay, 4 hours, 1 days)); + terminationDelay = uint128(bound(terminationDelay, 4 hours, _EARLY_END_DELAY)); tooEarlyDelay = uint128(bound(tooEarlyDelay, 25 hours, unlockPeriod)); - _helperBobStaking(); - // Setup & Start Fontaine - (int96 taxFlowRate, int96 unlockFlowRate) = _helperCalculateUnlockFlowRates(unlockAmount, unlockPeriod); + int96 unlockFlowRate = int256(unlockAmount / unlockPeriod).toInt96(); + + // Create and fund the Fontaine address newFontaine = _helperCreateFontaine(); - address user = makeAddr("user"); vm.prank(FLUID_TREASURY); _fluid.transfer(newFontaine, unlockAmount); - IFontaine(newFontaine).initialize(user, unlockFlowRate, taxFlowRate, unlockPeriod); - uint256 expectedTaxBalance = uint96(taxFlowRate) * unlockPeriod; - uint256 expectedUserBalance = uint96(unlockFlowRate) * unlockPeriod; + // Initialize the Fontaine + IFontaine(newFontaine).initialize(makeAddr("user"), unlockFlowRate, unlockPeriod); - uint256 tooEarlyEndDate = block.timestamp + unlockPeriod - tooEarlyDelay; uint256 earlyEndDate = block.timestamp + unlockPeriod - terminationDelay; - vm.warp(tooEarlyEndDate); + vm.warp(block.timestamp + unlockPeriod - tooEarlyDelay); vm.expectRevert(IFontaine.TOO_EARLY_TO_TERMINATE_UNLOCK.selector); IFontaine(newFontaine).terminateUnlock(); @@ -103,11 +96,13 @@ contract FontaineTest is SFTest { IFontaine(newFontaine).terminateUnlock(); assertApproxEqAbs( - bobLocker.getAvailableBalance(), expectedTaxBalance, expectedTaxBalance * 2 / 100, "invalid tax amount" - ); - assertApproxEqAbs( - _fluid.balanceOf(user), expectedUserBalance, expectedUserBalance * 2 / 100, "invalid unlocked amount" + _fluid.balanceOf(makeAddr("user")), + uint96(unlockFlowRate) * unlockPeriod, + (uint96(unlockFlowRate) * unlockPeriod) * 10 / 100, + "Unlocked amount incorrect" ); + + assertEq(_fluid.balanceOf(newFontaine), 0, "Fontaine balance should be 0"); } function testAccidentalStreamCancel() external { @@ -121,10 +116,9 @@ contract FontaineTest is SFTest { _fluid.transfer(newFontaine, unlockAmount); address user = makeAddr("user"); - (int96 unlockFlowRate, int96 taxFlowRate) = calculateVestUnlockFlowRates(unlockAmount, unlockPeriod); - assertEq(taxFlowRate, 0, "tax flow rate shall be 0"); + int96 unlockFlowRate = int256(unlockAmount / unlockPeriod).toInt96(); - IFontaine(newFontaine).initialize(user, unlockFlowRate, taxFlowRate, unlockPeriod); + IFontaine(newFontaine).initialize(user, unlockFlowRate, unlockPeriod); uint256 halfwayUnlockPeriod = block.timestamp + 270 days; uint256 afterEndUnlockPeriod = block.timestamp + 542 days; @@ -147,11 +141,12 @@ contract FontaineTest is SFTest { assertEq(_fluid.balanceOf(newFontaine), 0); } - function _helperBobStaking() internal { - _helperFundLocker(address(bobLocker), 10_000e18); - vm.prank(BOB); - bobLocker.stake(); - } + // __ __ __ ______ __ _ + // / / / /__ / /___ ___ _____ / ____/_ ______ _____/ /_(_)___ ____ _____ + // / /_/ / _ \/ / __ \/ _ \/ ___/ / /_ / / / / __ \/ ___/ __/ / __ \/ __ \/ ___/ + // / __ / __/ / /_/ / __/ / / __/ / /_/ / / / / /__/ /_/ / /_/ / / / (__ ) + // /_/ /_/\___/_/ .___/\___/_/ /_/ \__,_/_/ /_/\___/\__/_/\____/_/ /_/____/ + // /_/ function _helperCreateFontaine() internal returns (address newFontaine) { newFontaine = address(new BeaconProxy(address(_fontaineBeacon), "")); @@ -159,21 +154,27 @@ contract FontaineTest is SFTest { function _helperCalculateUnlockFlowRates(uint256 amountToUnlock, uint128 unlockPeriod) internal - pure - returns (int96 taxFlowRate, int96 unlockFlowRate) + view + returns (int96 stakerFlowRate, int96 providerFlowRate, int96 unlockFlowRate) { int96 globalFlowRate = int256(amountToUnlock / unlockPeriod).toInt96(); uint256 unlockingPercentageBP = - (2_000 + ((8_000 * Math.sqrt(unlockPeriod * _SCALER)) / Math.sqrt(365 days * _SCALER))); + (2000 + ((8000 * Math.sqrt(unlockPeriod * _SCALER)) / Math.sqrt(_MAX_UNLOCK_PERIOD * _SCALER))); unlockFlowRate = (globalFlowRate * int256(unlockingPercentageBP)).toInt96() / int256(_BP_DENOMINATOR).toInt96(); - taxFlowRate = globalFlowRate - unlockFlowRate; + int96 taxFlowRate = globalFlowRate - unlockFlowRate; + + // Calculate the tax allocation split between provider and staker + (, uint256 providerAllocation) = _stakingRewardController.getTaxAllocation(); + + providerFlowRate = (taxFlowRate * int256(providerAllocation).toInt96()) / int256(_BP_DENOMINATOR).toInt96(); + stakerFlowRate = taxFlowRate - providerFlowRate; } } contract FontaineLayoutTest is Fontaine { - constructor() Fontaine(ISuperToken(address(0)), ISuperfluidPool(address(0))) { } + constructor() Fontaine(ISuperToken(address(0))) { } function testStorageLayout() external pure { uint256 slot; @@ -187,16 +188,16 @@ contract FontaineLayoutTest is Fontaine { } require(slot == 0 && offset == 0, "recipient changed location"); - // private state : _taxFlowRate - // slot = 0 - offset = 20 - - // private state : _unlockFlowRate - // slot = 1 - offset = 0 + assembly { + slot := unlockFlowRate.slot + offset := unlockFlowRate.offset + } + require(slot == 0 && offset == 20, "unlockFlowRate changed location"); assembly { slot := endDate.slot offset := endDate.offset } - require(slot == 1 && offset == 12, "stakingUnlocksAt changed location"); + require(slot == 1 && offset == 0, "endDate changed location"); } } diff --git a/packages/contracts/test/SFTest.t.sol b/packages/contracts/test/SFTest.t.sol index d4195b5..7004c74 100644 --- a/packages/contracts/test/SFTest.t.sol +++ b/packages/contracts/test/SFTest.t.sol @@ -6,7 +6,7 @@ import "forge-std/Test.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { SafeCast } from "@openzeppelin-v5/contracts/utils/math/SafeCast.sol"; import { UpgradeableBeacon } from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; - +import { IERC20 } from "@openzeppelin-v5/contracts/token/ERC20/IERC20.sol"; import { SuperfluidFrameworkDeployer } from "@superfluid-finance/ethereum-contracts/contracts/utils/SuperfluidFrameworkDeployer.t.sol"; import { ERC1820RegistryCompiled } from @@ -22,7 +22,12 @@ import { FluidLockerFactory } from "../src/FluidLockerFactory.sol"; import { Fontaine } from "../src/Fontaine.sol"; import { StakingRewardController } from "../src/StakingRewardController.sol"; -import { _deployAll, DeploySettings } from "../script/Deploy.s.sol"; +import { _deployAll, DeploySettings, DeployedContracts } from "../script/Deploy.s.sol"; + +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; +import { IUniswapV3Factory } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol"; +import { INonfungiblePositionManager } from "@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol"; +import { IV3SwapRouter } from "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol"; using SuperTokenV1Library for SuperToken; using SuperTokenV1Library for ISuperToken; @@ -33,6 +38,18 @@ contract SFTest is Test { uint256 public constant INITIAL_BALANCE = 10000 ether; uint256 public constant FLUID_SUPPLY = 1_000_000_000 ether; uint256 public constant PROGRAM_DURATION = 90 days; + uint24 public constant POOL_FEE = 3000; + int24 internal constant _MIN_TICK = -887272; + int24 internal constant _MAX_TICK = -_MIN_TICK; + + // Units downscaler defined in StakingRewardController.sol + uint128 internal constant _STAKING_UNIT_DOWNSCALER = 1e18; + + // Initial Pool Price : 20000 SUP/ETH + uint160 public constant INITIAL_SQRT_PRICEX96_SUP_PER_WETH = 11204554194957228397824552468480; + + // Initial Pool Price : 0.00005 ETH/SUP + uint160 public constant INITIAL_SQRT_PRICEX96_WETH_PER_SUP = 560227709747861407246843904; SuperfluidFrameworkDeployer.Framework internal _sf; SuperfluidFrameworkDeployer internal _deployer; @@ -50,6 +67,7 @@ contract SFTest is Test { TestToken internal _fluidUnderlying; SuperToken internal _fluidSuperToken; ISuperToken internal _fluid; + IERC20 internal _weth; FluidEPProgramManager internal _programManager; FluidLocker internal _fluidLockerLogic; @@ -59,7 +77,17 @@ contract SFTest is Test { UpgradeableBeacon internal _lockerBeacon; UpgradeableBeacon internal _fontaineBeacon; + // Uniswap V3 Configuration + INonfungiblePositionManager internal _nonfungiblePositionManager; + IV3SwapRouter internal _swapRouter; + IUniswapV3Factory internal _poolFactory; + IUniswapV3Pool internal _pool; + function setUp() public virtual { + vm.createSelectFork(vm.envString("BASE_MAINNET_RPC_URL"), 28109090); + + _weth = IERC20(0x4200000000000000000000000000000000000006); + // Superfluid Protocol Deployment Start vm.etch(ERC1820RegistryCompiled.at, ERC1820RegistryCompiled.bin); @@ -76,6 +104,7 @@ contract SFTest is Test { for (uint256 i; i < TEST_ACCOUNTS.length; ++i) { vm.startPrank(TEST_ACCOUNTS[i]); vm.deal(TEST_ACCOUNTS[i], INITIAL_BALANCE); + deal(address(_weth), TEST_ACCOUNTS[i], INITIAL_BALANCE); vm.stopPrank(); } @@ -85,39 +114,74 @@ contract SFTest is Test { _fluidSuperToken.upgrade(FLUID_SUPPLY); vm.stopPrank(); + // Uniswap V3 Pool & Interfaces configuration + _nonfungiblePositionManager = INonfungiblePositionManager(0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1); + _swapRouter = IV3SwapRouter(0x2626664c2603336E57B271c5C0b26F421741e481); + _poolFactory = IUniswapV3Factory(0x33128a8fC17869897dcE68Ed026d694621f6FDfD); + + // Deploy the pool + _pool = IUniswapV3Pool(_poolFactory.createPool(address(_weth), address(_fluidSuperToken), POOL_FEE)); + + // Initialize the pool + uint160 sqrtPriceX96 = + _pool.token0() == address(_weth) ? INITIAL_SQRT_PRICEX96_SUP_PER_WETH : INITIAL_SQRT_PRICEX96_WETH_PER_SUP; + _pool.initialize(sqrtPriceX96); + + // Provide liquidity to the pool (from the treasury) + vm.startPrank(FLUID_TREASURY); + uint256 wethAmountToDeposit = 1000 ether; + uint256 supAmountToDeposit = 20_000_000 ether; + + _weth.approve(address(_nonfungiblePositionManager), wethAmountToDeposit); + _fluidSuperToken.approve(address(_nonfungiblePositionManager), supAmountToDeposit); + + uint256 amount0 = _pool.token0() == address(_weth) ? wethAmountToDeposit : supAmountToDeposit; + uint256 amount1 = _pool.token1() == address(_weth) ? wethAmountToDeposit : supAmountToDeposit; + + INonfungiblePositionManager.MintParams memory mintParams = INonfungiblePositionManager.MintParams({ + token0: _pool.token0(), + token1: _pool.token1(), + fee: POOL_FEE, + tickLower: (_MIN_TICK / _pool.tickSpacing()) * _pool.tickSpacing(), + tickUpper: (_MAX_TICK / _pool.tickSpacing()) * _pool.tickSpacing(), + amount0Desired: amount0, + amount1Desired: amount1, + amount0Min: 0, + amount1Min: 0, + recipient: address(this), + deadline: block.timestamp + }); + + // Create the UniswapV3 position + _nonfungiblePositionManager.mint(mintParams); + vm.stopPrank(); + + // FLUID Contracts Deployment Start DeploySettings memory settings = DeploySettings({ fluid: _fluidSuperToken, governor: ADMIN, deployer: ADMIN, treasury: FLUID_TREASURY, factoryPauseStatus: FACTORY_IS_PAUSED, - unlockStatus: LOCKER_CAN_UNLOCK + unlockStatus: LOCKER_CAN_UNLOCK, + swapRouter: _swapRouter, + nonfungiblePositionManager: _nonfungiblePositionManager, + ethSupPool: _pool }); - // FLUID Contracts Deployment Start vm.startPrank(ADMIN); - ( - , /* address programManagerLogicAddress */ - address programManagerProxyAddress, - , /* address stakingRewardControllerLogicAddress */ - address stakingRewardControllerProxyAddress, - , /* address lockerFactoryLogicAddress */ - address lockerFactoryProxyAddress, - address lockerLogicAddress, - address lockerBeaconAddress, - address fontaineLogicAddress, - address fontaineBeaconAddress - ) = _deployAll(settings); - - _programManager = FluidEPProgramManager(programManagerProxyAddress); - _stakingRewardController = StakingRewardController(stakingRewardControllerProxyAddress); - _fluidLockerFactory = FluidLockerFactory(lockerFactoryProxyAddress); - _fluidLockerLogic = FluidLocker(lockerLogicAddress); - _fontaineLogic = Fontaine(fontaineLogicAddress); + DeployedContracts memory deployedContracts = _deployAll(settings); + + _programManager = FluidEPProgramManager(deployedContracts.programManagerProxyAddress); + _stakingRewardController = StakingRewardController(deployedContracts.stakingRewardControllerProxyAddress); + _fluidLockerFactory = FluidLockerFactory(deployedContracts.lockerFactoryProxyAddress); + _fluidLockerLogic = FluidLocker(payable(deployedContracts.lockerLogicAddress)); + _fontaineLogic = Fontaine(deployedContracts.fontaineLogicAddress); _fluid = ISuperToken(address(_fluidSuperToken)); - _lockerBeacon = UpgradeableBeacon(lockerBeaconAddress); - _fontaineBeacon = UpgradeableBeacon(fontaineBeaconAddress); + _lockerBeacon = UpgradeableBeacon(deployedContracts.lockerBeaconAddress); + _fontaineBeacon = UpgradeableBeacon(deployedContracts.fontaineBeaconAddress); + vm.stopPrank(); // FLUID Contracts Deployment End @@ -228,4 +292,57 @@ contract SFTest is Test { vm.prank(FLUID_TREASURY); _fluidSuperToken.transfer(locker, amount); } + + function _helperCreatePosition(address locker, uint256 wethAmount, uint256 supAmount) + internal + returns (uint256 positionTokenId) + { + _helperFundLocker(locker, supAmount); + vm.startPrank(FluidLocker(payable(locker)).lockerOwner()); + FluidLocker(payable(locker)).provideLiquidity{ value: wethAmount }(supAmount); + vm.stopPrank(); + + positionTokenId = _nonfungiblePositionManager.tokenOfOwnerByIndex( + locker, FluidLocker(payable(locker)).activePositionCount() - 1 + ); + } + + function _helperLockerProvideLiquidity(address locker) internal { + _helperCreatePosition(locker, 1 ether, 20000e18); + } + + function _helperWithdrawLiquidity( + address locker, + uint256 tokenId, + uint128 liquidityToRemove, + uint256 wethAmountToRemove, + uint256 supAmountToRemove + ) internal { + vm.startPrank(FluidLocker(payable(locker)).lockerOwner()); + FluidLocker(payable(locker)).withdrawLiquidity( + tokenId, liquidityToRemove, wethAmountToRemove, supAmountToRemove + ); + vm.stopPrank(); + } + + function _helperLockerWithdrawLiquidity(address locker) internal { + uint256 tokenId = _nonfungiblePositionManager.tokenOfOwnerByIndex( + locker, FluidLocker(payable(locker)).activePositionCount() - 1 + ); + + (,,,,,,, uint128 positionLiquidity,,,,) = _nonfungiblePositionManager.positions(tokenId); + + _helperWithdrawLiquidity(locker, tokenId, positionLiquidity, 1 ether, 20000e18); + } + + function _helperLockerStake(address locker) internal { + _helperFundLocker(locker, 10_000e18); + vm.prank(FluidLocker(payable(locker)).lockerOwner()); + FluidLocker(payable(locker)).stake(10_000e18); + } + + function _helperLockerUnstake(address locker) internal { + vm.prank(FluidLocker(payable(locker)).lockerOwner()); + FluidLocker(payable(locker)).unstake(10_000e18); + } } diff --git a/packages/contracts/test/StakingRewardController.t.sol b/packages/contracts/test/StakingRewardController.t.sol index 45a0d11..7ffbb1d 100644 --- a/packages/contracts/test/StakingRewardController.t.sol +++ b/packages/contracts/test/StakingRewardController.t.sol @@ -14,8 +14,6 @@ import { StakingRewardController, IStakingRewardController } from "../src/Stakin using SuperTokenV1Library for ISuperToken; contract StakingRewardControllerTest is SFTest { - // Units downscaler defined in StakingRewardController.sol - uint128 private constant _UNIT_DOWNSCALER = 1e16; function setUp() public override { super.setUp(); @@ -24,7 +22,7 @@ contract StakingRewardControllerTest is SFTest { function testUpdateStakerUnits(address caller, uint256 stakingAmount) external { vm.assume(caller != address(0)); vm.assume(caller != address(_stakingRewardController.taxDistributionPool())); - stakingAmount = bound(stakingAmount, 1e16, 10_000_000e18); + stakingAmount = bound(stakingAmount, 1e18, 10_000_000e18); vm.prank(caller); vm.expectRevert(IStakingRewardController.NOT_APPROVED_LOCKER.selector); @@ -41,7 +39,7 @@ contract StakingRewardControllerTest is SFTest { assertEq( _stakingRewardController.taxDistributionPool().getUnits(caller), - stakingAmount / _UNIT_DOWNSCALER, + stakingAmount / _STAKING_UNIT_DOWNSCALER, "incorrect amount of units" ); } diff --git a/packages/model/price_to_sqrt_price.ipynb b/packages/model/price_to_sqrt_price.ipynb new file mode 100644 index 0000000..146b2cd --- /dev/null +++ b/packages/model/price_to_sqrt_price.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 92, + "metadata": {}, + "outputs": [], + "source": [ + "import math" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [], + "source": [ + "q96 = 2**96" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [], + "source": [ + "def price_to_sqrtp(p):\n", + " return int(math.sqrt(p) * q96)\n", + "\n", + "\n", + "def sqrtp_to_price(sqrtp):\n", + " return (sqrtp / q96)**2" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SUP PRICE TARGET :\n", + "--------------------------------\n", + "0.045 USD/SUP\n", + "1.0465116279069768e-05 ETH/SUP\n", + "95555.55555555555 SUP/ETH\n" + ] + } + ], + "source": [ + "# PARAMETERS\n", + "ethPriceInUSD = 4300\n", + "\n", + "# SUP PRICE TARGET\n", + "supPriceInUSD = 0.045\n", + "supPriceInETH = supPriceInUSD / ethPriceInUSD\n", + "ethPriceInSUP = 1 / supPriceInETH\n", + "\n", + "print(\"SUP PRICE TARGET :\")\n", + "print(\"--------------------------------\")\n", + "print(supPriceInUSD, \"USD/SUP\")\n", + "print(supPriceInETH, \"ETH/SUP\")\n", + "print(ethPriceInSUP, \"SUP/ETH\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PRICE TO USE IF SUP IS TOKEN 0 IN ETH/SUP POOL\n", + "256301774391774839922753536\n" + ] + }, + { + "data": { + "text/plain": [ + "1.046511627906977e-05" + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(\"PRICE TO USE IF SUP IS TOKEN 0 IN ETH/SUP POOL\")\n", + "\n", + "supPriceInETHQ96 = price_to_sqrtp(supPriceInETH)\n", + "print(supPriceInETHQ96)\n", + "sqrtp_to_price(supPriceInETHQ96)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PRICE TO USE IF SUP IS TOKEN 1 IN ETH/SUP POOL\n", + "24491058441880705072786239913984\n" + ] + }, + { + "data": { + "text/plain": [ + "95555.55555555555" + ] + }, + "execution_count": 97, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(\"PRICE TO USE IF SUP IS TOKEN 1 IN ETH/SUP POOL\")\n", + "ethPriceInSUPQ96 = price_to_sqrtp(ethPriceInSUP)\n", + "print(ethPriceInSUPQ96)\n", + "sqrtp_to_price(ethPriceInSUPQ96)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/packages/tasks/extract-abis-organized.sh b/packages/tasks/extract-abis-organized.sh new file mode 100755 index 0000000..a6e0b14 --- /dev/null +++ b/packages/tasks/extract-abis-organized.sh @@ -0,0 +1,123 @@ +#!/bin/bash + +# Comprehensive script to extract and organize ABIs for all contracts in src/ directory +# Usage: ./extract-abis-organized.sh +# Note: Run from the tasks/ directory, will create abis/ in the contracts/ directory + +set -e + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONTRACTS_DIR="$SCRIPT_DIR/../contracts" + +# Check if contracts directory exists +if [ ! -d "$CONTRACTS_DIR" ]; then + echo "Error: Contracts directory not found at $CONTRACTS_DIR" + exit 1 +fi + +# Change to contracts directory +cd "$CONTRACTS_DIR" + +# Create organized output directories +mkdir -p abis/{main,interfaces,token,vesting} + +echo "Extracting and organizing ABIs..." + +# Main contracts +MAIN_CONTRACTS=( + "FluidLocker" + "FluidLockerFactory" + "FluidEPProgramManager" + "EPProgramManager" + "StakingRewardController" + "Fontaine" +) + +# Token contracts +TOKEN_CONTRACTS=( + "SupToken" + "SupTokenL2" + "BridgedSuperToken" + "OPBridgedSuperToken" +) + +# Vesting contracts +VESTING_CONTRACTS=( + "SupVesting" + "SupVestingFactory" +) + +# Interface contracts +INTERFACE_CONTRACTS=( + "IFluidLocker" + "IFluidLockerFactory" + "IEPProgramManager" + "IStakingRewardController" + "IFontaine" + "IBridgedSuperToken" + "IOPBridgedSuperToken" + "IOptimismMintableERC20" + "IXERC20" + "ISupVesting" + "ISupVestingFactory" +) + +# Function to extract ABI +extract_abi() { + local contract=$1 + local output_dir=$2 + local category=$3 + + if [ -f "out/$contract.sol/$contract.json" ]; then + echo "Extracting ABI for $contract -> abis/$category/" + jq '.abi' "out/$contract.sol/$contract.json" > "abis/$category/$contract.json" + else + echo "Warning: $contract.json not found in out/$contract.sol/" + fi +} + +# Extract main contracts +echo "=== Main Contracts ===" +for contract in "${MAIN_CONTRACTS[@]}"; do + extract_abi "$contract" "main" "main" +done + +# Extract token contracts +echo "=== Token Contracts ===" +for contract in "${TOKEN_CONTRACTS[@]}"; do + extract_abi "$contract" "token" "token" +done + +# Extract vesting contracts +echo "=== Vesting Contracts ===" +for contract in "${VESTING_CONTRACTS[@]}"; do + extract_abi "$contract" "vesting" "vesting" +done + +# Extract interface contracts +echo "=== Interface Contracts ===" +for contract in "${INTERFACE_CONTRACTS[@]}"; do + extract_abi "$contract" "interfaces" "interfaces" +done + +echo "" +echo "ABI extraction complete! Organized structure:" +echo "" +echo "contracts/abis/" +echo "├── main/ # Core protocol contracts" +echo "├── interfaces/ # Contract interfaces" +echo "├── token/ # Token implementations" +echo "└── vesting/ # Vesting contracts" +echo "" + +# Show summary +echo "Summary:" +for category in main interfaces token vesting; do + count=$(find "abis/$category" -name "*.json" 2>/dev/null | wc -l) + echo " $category/: $count ABIs" +done + +echo "" +echo "Total ABIs extracted: $(find abis -name "*.json" | wc -l)" +echo "ABIs are located in: $(pwd)/abis/"