├── .env.example ├── .eslintrc.js ├── .gitignore ├── .gitmodules ├── .husky ├── pre-commit └── pre-push ├── .prettierrc.js ├── .solhint.json ├── Makefile ├── README.md ├── Sandbox.s.sol ├── cloc-report.bash ├── contracts ├── erc721NftLoader │ └── ERC721NftLoader.sol ├── governance │ └── twTAP.sol ├── interfaces │ ├── IMagnitudeMultiplier.sol │ ├── INFTLoader.sol │ ├── IUniswapV3FactoryImpl.sol │ └── IYieldBox.sol ├── mocks │ ├── ERC20Mock.sol │ └── LTapMock.sol ├── option-airdrop │ ├── AirdropBroker.sol │ ├── LTap.sol │ └── aoTAP.sol ├── options │ ├── TapiocaOptionBroker.sol │ ├── TapiocaOptionLiquidityProvision.sol │ ├── oTAP.sol │ └── twAML.sol ├── tapioca-periph-file-loader.sol └── tokens │ ├── BaseTapToken.sol │ ├── BaseTapTokenMsgType.sol │ ├── ITapToken.sol │ ├── TapToken.sol │ ├── TapTokenCodec.sol │ ├── TapTokenReceiver.sol │ ├── TapTokenSender.sol │ ├── Vesting.sol │ ├── extensions │ └── TapTokenHelper.sol │ └── module │ └── ModuleManager.sol ├── foundry.toml ├── hardhat.config.ts ├── hardhat.export.ts ├── hardhat.tasks.ts ├── hardhat_scripts ├── deployment.utils.ts ├── gen.ts └── getDeployments-script.ts ├── lbpUsers.json ├── local.db.json ├── package.json ├── preSeedVesting.json ├── script └── utils │ └── ScriptUtils.s.sol ├── seedVesting.json ├── tasks ├── .DS_Store ├── deploy │ ├── 1-1-deployPreLbpStack.ts │ ├── 1-2-ltapAddLbpTransferAllowed.ts │ ├── 2-1-deployPostLbpStack.ts │ ├── 2-1-sideChain-deployPostLbpStack.ts │ ├── 2-2-deployPostLbpStack.ts │ ├── 3-deployFinalStack.ts │ ├── DEPLOY_CONFIG.ts │ ├── initPostLbpStack.ts │ └── testnet │ │ └── deployMockADB.ts ├── deployBuilds │ ├── finalStack │ │ ├── buildEmptyYbStrategy.ts │ │ ├── buildFinalStackPostDepSetup.ts │ │ └── options │ │ │ ├── buildOTAP.ts │ │ │ ├── buildTOB.ts │ │ │ ├── buildTOLP.ts │ │ │ └── deployTwTap.ts │ ├── mocks │ │ ├── buildERC721Mock.ts │ │ ├── buildLTapMock.ts │ │ ├── buildMockERC20.ts │ │ ├── buildOracleMock.ts │ │ └── buildYieldBoxMock.ts │ ├── postLbpStack │ │ ├── airdrop │ │ │ ├── buildADB.ts │ │ │ └── buildAOTAP.ts │ │ ├── buildPostLbpStackPostDepSetup.ts │ │ ├── cluster │ │ │ └── temp__buildCluster.ts │ │ ├── pearlmit │ │ │ └── temp__buildPearlmit.ts │ │ ├── setTapOptionOracle__postDeployLbp.ts │ │ ├── tapToken │ │ │ ├── buildExtExec.ts │ │ │ ├── buildTapToken.ts │ │ │ ├── buildTapTokenHelper.ts │ │ │ ├── buildTapTokenReceiverModule.ts │ │ │ └── buildTapTokenSenderModule.ts │ │ └── vesting │ │ │ └── buildVesting.ts │ └── preLbpStack │ │ └── buildLTap.ts ├── exec │ ├── adb │ │ ├── 07-ab-setTapOracle.ts │ │ ├── 08-ab-setPhase2MerkleRoots.ts │ │ ├── 09-ab-registerUserForPhase.ts │ │ ├── 10-ab-setPaymentToken.ts │ │ ├── 11-ab-setPaymentTokenBeneficiary.ts │ │ ├── 12-ab-collectPaymentTokens.ts │ │ ├── 13-ab-daoRecoverTAP.ts │ │ ├── adb_addPaymentToken.ts │ │ ├── adb_collectPaymentToken.ts │ │ ├── adb_collectPayments.ts │ │ ├── adb_newEpoch.ts │ │ ├── adb_registerUserForPhase.ts │ │ └── adb_setMerkleRoots.ts │ ├── exec__sendToken__task.ts │ ├── ltap │ │ ├── 23-ltap-setLockedUntil.ts │ │ ├── ltap_deployMock.ts │ │ ├── ltap_mintLtapMock.ts │ │ └── ltap_openRedemptions.ts │ ├── misc │ │ └── sandbox.ts │ ├── setToeEnforcedOptions.ts │ ├── setToePeers.ts │ ├── setterTasks.ts │ ├── tap │ │ ├── 24-tap-rescueEth.ts │ │ ├── 25-tap-setTwTap.ts │ │ ├── 26-tap-setGovernanceChainIdentifier.ts │ │ ├── 27-tap-updatePause.ts │ │ └── 28-tap-setMinter.ts │ ├── tests │ │ ├── test-claimRewards.ts │ │ ├── test-exitCrossChain.ts │ │ └── test-participateCrossChain.ts │ ├── tob │ │ ├── 14-tob-setMinWeightFactor.ts │ │ ├── 15-tob-setTapOracle.ts │ │ ├── 16-tob-setPaymentToken.ts │ │ ├── 17-tob-setPaymentTokenBeneficiary.ts │ │ └── 18-tob-collectPaymentTokens.ts │ ├── tolp │ │ ├── 19-tolp-setRegisterSGL.ts │ │ ├── 20-tolp-setSglPoolWeight.ts │ │ ├── 21-tolp-activateSglPoolRescue.ts │ │ └── 22-tolp-unregisterSingularity.ts │ ├── twTap │ │ ├── 03-twTap-setMaxRewardTokensLength.ts │ │ ├── 04-twTap-setTwTapRewardToken.ts │ │ ├── 05-twTap-setDistributeTwTapRewards.ts │ │ └── 06-twTap-setAdvanceWeek.ts │ └── vesting │ │ ├── registerUsersVesting.ts │ │ └── vestingInit.ts ├── scopes │ ├── adbScope.ts │ ├── deployScope.ts │ ├── lTapScope.ts │ ├── miscScope.ts │ ├── tOBScope.ts │ ├── tOLPScope.ts │ ├── tapOFTScope.ts │ ├── testnetScope.ts │ ├── twTapScope.ts │ ├── utilScope.ts │ └── vestingScope.ts └── utils.ts ├── test ├── AirdropBrokerTest.t.sol ├── ERC721Mock.sol ├── LTap.t.sol ├── LZSetup │ ├── TestHelper.sol │ └── mocks │ │ ├── ERC20Mock.sol │ │ ├── ExecutorFeeLibMock.sol │ │ ├── OFTAdapterMock.sol │ │ ├── OFTComposerMock.sol │ │ ├── OFTInspectorMock.sol │ │ ├── OFTMock.sol │ │ ├── OptionsHelper.sol │ │ ├── SendUln302Mock.sol │ │ └── SimpleMessageLibMock.sol ├── TapTestHelper.t.sol ├── TapToken.t.sol ├── TapTokenMock.sol ├── TapTokenMultiCompose.t.sol ├── TestUtils.t.sol ├── VestingInitialUnlock.t.sol ├── mocks │ └── FailingOracleMock.sol └── unit │ ├── UnitBaseTest.sol │ └── options │ ├── TapiocaOptionBroker │ ├── TOB_exerciseOption.t.sol │ ├── TOB_exerciseOption.tree │ ├── TOB_exitPosition.t.sol │ ├── TOB_exitPosition.tree │ ├── TOB_getCurrentWeek.t.sol │ ├── TOB_getCurrentWeek.tree │ ├── TOB_getOTCDealDetails.t.sol │ ├── TOB_getOTCDealDetails.tree │ ├── TOB_getOptionPosition.t.sol │ ├── TOB_getOptionPosition.tree │ ├── TOB_getSingularityPoolInfo.t.sol │ ├── TOB_getSingularityPoolInfo.tree │ ├── TOB_newEpoch.t.sol │ ├── TOB_newEpoch.tree │ ├── TOB_ownerActions.t.sol │ ├── TOB_ownerActions.tree │ ├── TOB_participate.t.sol │ ├── TOB_participate.tree │ ├── TOB_refreshTotalDeposited.t.sol │ ├── TOB_refreshTotalDeposited.tree │ ├── TOB_timestampToWeek.t.sol │ ├── TOB_timestampToWeek.tree │ └── TobBaseTest.sol │ ├── TapiocaOptionLiquidityProvision │ ├── TOLP_activateSGLPoolRescue.t.sol │ ├── TOLP_activateSGLPoolRescue.tree │ ├── TOLP_getDebtPenaltyAmount.t.sol │ ├── TOLP_getDebtPenaltyAmount.tree │ ├── TOLP_getSingularityPools.t.sol │ ├── TOLP_getSingularityPools.tree │ ├── TOLP_lock.t.sol │ ├── TOLP_lock.tree │ ├── TOLP_ownerActions.t.sol │ ├── TOLP_ownerActions.tree │ ├── TOLP_registerSingularity.t.sol │ ├── TOLP_registerSingularity.tree │ ├── TOLP_requestSglPoolRescue.t.sol │ ├── TOLP_requestSglPoolRescue.tree │ ├── TOLP_setSGLPoolWeight.t.sol │ ├── TOLP_setSGLPoolWeight.tree │ ├── TOLP_unlock.t.sol │ ├── TOLP_unlock.tree │ ├── TOLP_unregisterSingularity.t.sol │ ├── TOLP_unregisterSingularity.tree │ └── TolpBaseTest.sol │ ├── twL │ └── twl_capCumulativeReward.t.sol │ └── twTap │ ├── twTapBaseTest.sol │ ├── twTap_advanceWeek.t.sol │ ├── twTap_advanceWeek.tree │ ├── twTap_batchClaimRewards.t.sol │ ├── twTap_batchClaimRewards.tree │ ├── twTap_claimRewards.t.sol │ ├── twTap_claimRewards.tree │ ├── twTap_distributeReward.t.sol │ ├── twTap_distributeReward.tree │ ├── twTap_emergencySweep.t.sol │ ├── twTap_emergencySweep.tree │ ├── twTap_exitPosition.t.sol │ ├── twTap_exitPosition.tree │ ├── twTap_ownerActions.t.sol │ ├── twTap_ownerActions.tree │ ├── twTap_participate.t.sol │ ├── twTap_participate.tree │ ├── twTap_refreshTotalDeposited.t.sol │ └── twTap_refreshTotalDeposited.tree ├── test_hardhat ├── aoTAP │ ├── adb.test.ts │ ├── aoTapPhase2Fixtures.json │ └── fixture.aoTAP.ts ├── oTAP │ ├── fixtures.ts │ ├── tOB.test.ts │ └── tOLP.test.ts ├── test.utils.ts ├── tokens │ ├── emissionsPerWeek.json │ ├── extraSupplyPerWeek.json │ └── tapOFT.test.ts ├── twTAP │ ├── fixtures.ts │ └── twTAP.test.ts └── vesting.test.ts ├── testnetLbpUsers.json ├── testnetLtapMock.json ├── tsconfig.json └── yarn.lock /.env.example: -------------------------------------------------------------------------------- 1 | # Description: Example of .env file. 2 | # The env file should be renamed to `name_of_chain.env`. The file needs to be in the `.env/` folder. 3 | # dotenv loading can not load `export` env vars for some reasons 4 | 5 | # Global Config 6 | PRIVATE_KEY= # Private key of the deployer. Needs be prefixed with 0x 7 | ALCHEMY_API_KEY= # Alchemy API key 8 | export RPC_URL= 9 | export CHAIN_NAME= # Name of the chain 10 | 11 | # LZ Config 12 | export ENDPOINT= # Endpoint address of the chain 13 | export CHAIN_ID= # Chain ID 14 | export LZ_CHAIN_ID= # LZ Chain ID 15 | export ENVIRONMENT= # Environment (mainnet, testnet) 16 | 17 | # Deployment 18 | export TAPIOCA_DEPLOYER= # TapiocaDeployer address on the target chain 19 | export MULTICALL3=0xcA11bde05977b3631167028862bE2a173976CA11 # Multicall3 address on the target chain 20 | export SCAN_API_KEY= # Arbitrum Sepolia API key -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: false, 4 | es2021: true, 5 | mocha: true, 6 | node: true, 7 | }, 8 | extends: [ 9 | 'plugin:@typescript-eslint/recommended', 10 | 'plugin:prettier/recommended', 11 | ], 12 | parser: '@typescript-eslint/parser', 13 | plugins: ['@typescript-eslint', 'prettier'], 14 | root: true, 15 | parserOptions: { 16 | ecmaVersion: 12, 17 | }, 18 | rules: { 19 | '@typescript-eslint/no-explicit-any': ['off'], 20 | '@typescript-eslint/no-non-null-assertion': ['off'], 21 | 'prettier/prettier': [ 22 | 'error', 23 | { 24 | trailingComma: 'all', 25 | singleQuote: true, 26 | printWidth: 80, 27 | endOfLine: 'auto', 28 | useTabs: false, 29 | tabWidth: 4, 30 | }, 31 | ], 32 | 'comma-dangle': [2, 'always-multiline'], 33 | semi: ['error', 'always'], 34 | 'comma-spacing': ['error', { before: false, after: true }], 35 | quotes: ['error', 'single'], 36 | indent: 'off', 37 | 'key-spacing': ['error', { afterColon: true }], 38 | 'no-multi-spaces': ['error'], 39 | 'no-multiple-empty-lines': ['error', { max: 2 }], 40 | '@typescript-eslint/ban-ts-comment': 'off', 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | package-lock.json 7 | docs 8 | 9 | #Hardhat & forge files 10 | gen 11 | cache 12 | 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | branch = master 5 | [submodule "gitmodule/tapioca-sdk"] 6 | path = gitmodule/tapioca-sdk 7 | url = https://github.com/Tapioca-DAO/tapioca-sdk 8 | branch = main 9 | [submodule "dep/tap-utils"] 10 | path = dep/tap-utils 11 | url = https://github.com/Tapioca-DAO/tap-utils 12 | branch = main 13 | [submodule "dep/tap-yieldbox"] 14 | path = dep/tap-yieldbox 15 | url = https://github.com/Tapioca-DAO/tap-yieldbox 16 | branch = main 17 | [submodule "dep/tapioca-bar"] 18 | path = dep/tapioca-bar 19 | url = https://github.com/Tapioca-DAO/Tapioca-bar 20 | branch = master 21 | [submodule "dep/tapioca-mocks"] 22 | path = dep/tapioca-mocks 23 | url = https://github.com/Tapioca-DAO/tapioca-mocks 24 | branch = main 25 | [submodule "dep/tapiocaz"] 26 | path = dep/tapiocaz 27 | url = https://github.com/Tapioca-DAO/tapiocaz 28 | branch = master 29 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | overrides: [ 3 | { 4 | files: "*.ts", 5 | options: { 6 | trailingComma: 'all', 7 | singleQuote: true, 8 | printWidth: 80, 9 | endOfLine: 'auto', 10 | useTabs: false, 11 | tabWidth: 4, 12 | }, 13 | }, 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:default", 3 | "rules": { 4 | "compiler-version": ["off"], 5 | "no-console":["off"], 6 | "max-line-length": ["off"] 7 | } 8 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | initialize: 2 | git submodule update --init 3 | cd dep/tap-utils/ ; git submodule update --init lib/permitc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | All rights are reserved and the Tapioca codebase is not Open Source or Free. You cannot modify or redistribute this code without explicit written permission from the copyright holder (Tapioca Foundation & BoringCrypto [where applicable]). 2 | 3 | # TapOFT 🍹 🤙 4 | 5 | ## Install 6 | 7 | To install this repository: 8 | 9 | ```bash 10 | yarn 11 | ``` 12 | This will install the necessary npm packages, forge-std and close the submodule dependencies. -------------------------------------------------------------------------------- /Sandbox.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | // Tapioca 5 | import "forge-std/Script.sol"; 6 | 7 | contract ForgeSandbox is Script { 8 | function run() external { 9 | uint256 deployerPrivateKey_ = vm.envUint("PRIVATE_KEY"); 10 | address caller_ = vm.addr(deployerPrivateKey_); 11 | 12 | vm.startBroadcast(deployerPrivateKey_); 13 | 14 | vm.stopBroadcast(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cloc-report.bash: -------------------------------------------------------------------------------- 1 | cloc ./contracts/**/*.sol --by-file --csv --quiet --hide-rate > cloc-report.csv -------------------------------------------------------------------------------- /contracts/erc721NftLoader/ERC721NftLoader.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | // External 5 | import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 6 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 7 | 8 | // Tapioca 9 | import {INFTLoader} from "../interfaces/INFTLoader.sol"; 10 | 11 | /* 12 | 13 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 14 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 15 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 16 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 17 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 18 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 19 | 20 | */ 21 | 22 | /// @title ERC721 NFT Loader 23 | /// @notice An ERC721 token that can load NFT URIs from an NFT loader contract. This helps update image URIs for NFTs. 24 | contract ERC721NftLoader is ERC721, Ownable { 25 | INFTLoader public nftLoader; // NFT URI loader contract 26 | 27 | string public baseURI; 28 | 29 | constructor(string memory _name, string memory _symbol, address _owner) ERC721(_name, _symbol) { 30 | _transferOwnership(_owner); 31 | } 32 | 33 | /** 34 | * @notice Returns the token URI for a given token ID. If the NFT loader contract is not set, it returns an empty string. 35 | * @inheritdoc ERC721 36 | */ 37 | function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { 38 | // If baseURI is set, use it. Otherwise, use the NFT loader contract. 39 | if (bytes(baseURI).length > 0) { 40 | return super.tokenURI(tokenId); 41 | } else { 42 | if (address(nftLoader) == address(0)) { 43 | return ""; 44 | } 45 | return INFTLoader(nftLoader).tokenURI(tokenId); 46 | } 47 | } 48 | 49 | function _baseURI() internal view virtual override returns (string memory) { 50 | return baseURI; 51 | } 52 | 53 | /** 54 | * @notice Set the base URI 55 | */ 56 | function setBaseURI(string memory __baseURI) external onlyOwner { 57 | baseURI = __baseURI; 58 | } 59 | 60 | /** 61 | * @notice Set the NFT loader contract 62 | */ 63 | function setNftLoader(address _nftLoader) external onlyOwner { 64 | nftLoader = INFTLoader(_nftLoader); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /contracts/interfaces/IMagnitudeMultiplier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | interface ITobMagnitudeMultiplier { 5 | function getPositiveMagnitudeMultiplier(uint256 _tOLPTokenID) external view returns (uint256); 6 | function getNegativeMagnitudeMultiplier(uint256 _tOLPTokenID) external view returns (uint256); 7 | } 8 | 9 | interface ITwTapMagnitudeMultiplier { 10 | function getPositiveMagnitudeMultiplier(address _participant, uint256 _amount, uint256 _duration) 11 | external 12 | view 13 | returns (uint256); 14 | function getNegativeMagnitudeMultiplier(address _participant, uint256 _amount, uint256 _duration) 15 | external 16 | view 17 | returns (uint256); 18 | } 19 | -------------------------------------------------------------------------------- /contracts/interfaces/INFTLoader.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | /* 5 | 6 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 7 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 8 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 9 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 10 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 11 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 12 | 13 | */ 14 | 15 | interface INFTLoader { 16 | function tokenURI(uint256 tokenId) external view returns (string memory); 17 | } 18 | -------------------------------------------------------------------------------- /contracts/interfaces/IUniswapV3FactoryImpl.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | /* 5 | 6 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 7 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 8 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 9 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 10 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 11 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 12 | 13 | */ 14 | 15 | import "tap-utils/interfaces/external/uniswap/IUniswapV3Factory.sol"; 16 | -------------------------------------------------------------------------------- /contracts/interfaces/IYieldBox.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | /* 5 | 6 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 7 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 8 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 9 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 10 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 11 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 12 | 13 | */ 14 | 15 | import "tap-utils/interfaces/yieldbox/IYieldBox.sol"; 16 | -------------------------------------------------------------------------------- /contracts/mocks/ERC20Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | // External 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | /* 8 | 9 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 10 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 11 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 12 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 13 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 14 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 15 | 16 | */ 17 | 18 | contract ERC20Mock is ERC20 { 19 | constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {} 20 | 21 | function mint(address _to, uint256 _amount) public { 22 | _mint(_to, _amount); 23 | } 24 | 25 | function freeMint(uint256 _amount) public { 26 | _mint(msg.sender, _amount); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /contracts/mocks/LTapMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {ERC20, ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; 5 | import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 6 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 7 | 8 | /* 9 | 10 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 11 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 12 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 13 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 14 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 15 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 16 | 17 | */ 18 | 19 | contract LTapMock is Ownable, ERC20Permit { 20 | using SafeERC20 for IERC20; 21 | 22 | IERC20 public tapToken; 23 | bool public openRedemption; 24 | 25 | error TapNotSet(); 26 | error RedemptionNotOpen(); 27 | 28 | constructor(address _lbp, address _owner) ERC20("LTAPMock", "LTAPMock") ERC20Permit("LTAPMock") { 29 | _transferOwnership(_owner); 30 | } 31 | 32 | modifier tapExists() { 33 | if (address(tapToken) == address(0)) revert TapNotSet(); 34 | _; 35 | } 36 | 37 | // TESTNET only 38 | function mint(address[] calldata _to, uint256[] calldata _amount) external onlyOwner { 39 | for (uint256 i = 0; i < _to.length; i++) { 40 | _mint(_to[i], _amount[i]); 41 | } 42 | } 43 | 44 | /// @notice Sets the TAP token address 45 | /// @param _tapToken The TAP token address 46 | function setTapToken(address _tapToken) external onlyOwner { 47 | tapToken = IERC20(_tapToken); 48 | } 49 | 50 | function setOpenRedemption() external onlyOwner tapExists { 51 | openRedemption = true; 52 | } 53 | 54 | function redeem() external tapExists { 55 | if (!openRedemption) revert RedemptionNotOpen(); 56 | uint256 amount = balanceOf(msg.sender); 57 | _burn(msg.sender, amount); 58 | tapToken.safeTransfer(msg.sender, amount); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /contracts/option-airdrop/LTap.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {ERC20, ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; 5 | import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 6 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 7 | 8 | /* 9 | 10 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 11 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 12 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 13 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 14 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 15 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 16 | 17 | */ 18 | 19 | /// @title LTAP 20 | /// @notice Locked TAP 21 | contract LTap is Ownable, ERC20Permit { 22 | using SafeERC20 for IERC20; 23 | 24 | IERC20 public tapToken; 25 | bool public openRedemption; 26 | mapping(address operator => bool permitted) public transferAllowList; 27 | 28 | error TapNotSet(); 29 | error RedemptionNotOpen(); 30 | error TransferNotAllowed(); 31 | 32 | /// @notice Creates a new LTAP token 33 | /// @dev LTAP tokens are minted by depositing TAP 34 | constructor(address _lbp, address _owner) ERC20("LTAP", "LTAP") ERC20Permit("LTAP") { 35 | _mint(_lbp, 5_000_000 * 1e18); // 5M LTAP for LBP 36 | _transferOwnership(_owner); 37 | transferAllowList[_lbp] = true; 38 | } 39 | 40 | modifier tapExists() { 41 | if (address(tapToken) == address(0)) revert TapNotSet(); 42 | _; 43 | } 44 | /// @notice Sets the TAP token address 45 | /// @param _tapToken The TAP token address 46 | 47 | function setTapToken(address _tapToken) external onlyOwner { 48 | tapToken = IERC20(_tapToken); 49 | } 50 | 51 | function setTransferAllowList(address _operator, bool _permitted) external onlyOwner { 52 | transferAllowList[_operator] = _permitted; 53 | } 54 | 55 | function setOpenRedemption() external onlyOwner tapExists { 56 | openRedemption = true; 57 | } 58 | 59 | function redeem() external tapExists { 60 | if (!openRedemption) revert RedemptionNotOpen(); 61 | uint256 amount = balanceOf(msg.sender); 62 | _burn(msg.sender, amount); 63 | tapToken.safeTransfer(msg.sender, amount); 64 | } 65 | 66 | function _transfer(address from, address to, uint256 amount) internal override { 67 | if (!transferAllowList[from] && !transferAllowList[to]) revert TransferNotAllowed(); 68 | super._transfer(from, to, amount); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /contracts/tapioca-periph-file-loader.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | 3 | pragma solidity 0.8.22; 4 | 5 | /// THIS FILE IS USED TO LOAD THE TAPIOCA BAR CONTRACTS 6 | /// Comment the imports for faster compilation 7 | 8 | import {IPoolInitializer} from "tap-utils/interfaces/external/uniswap/IPoolInitializer.sol"; 9 | import {SeerUniSolo} from "tap-utils/oracle/SeerUniSolo.sol"; 10 | import {Pearlmit} from "tap-utils/pearlmit/Pearlmit.sol"; 11 | import {Cluster} from "tap-utils/Cluster/Cluster.sol"; 12 | -------------------------------------------------------------------------------- /contracts/tokens/BaseTapToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | // Tapioca 5 | import {BaseTapiocaOmnichainEngine} from "tap-utils/tapiocaOmnichainEngine/BaseTapiocaOmnichainEngine.sol"; 6 | import {IPearlmit} from "tap-utils/interfaces/periph/IPearlmit.sol"; 7 | import {ICluster} from "tap-utils/interfaces/periph/ICluster.sol"; 8 | import {BaseTapTokenMsgType} from "./BaseTapTokenMsgType.sol"; 9 | import {TwTAP} from "contracts/governance/twTAP.sol"; 10 | 11 | /* 12 | 13 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 14 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 15 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 16 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 17 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 18 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 19 | 20 | */ 21 | 22 | abstract contract BaseTapToken is BaseTapiocaOmnichainEngine, BaseTapTokenMsgType { 23 | uint16 internal constant PT_LOCK_TWTAP = 870; 24 | uint16 internal constant PT_UNLOCK_TWTAP = 871; 25 | uint16 internal constant PT_CLAIM_REWARDS = 872; 26 | 27 | /// @dev Can't be set as constructor params because TwTAP is deployed after TapToken. TwTAP constructor needs TapOFT as param. 28 | TwTAP public twTap; 29 | 30 | constructor( 31 | string memory _name, 32 | string memory _symbol, 33 | address _endpoint, 34 | address _delegate, 35 | address _extExec, 36 | IPearlmit _pearlmit, 37 | ICluster _cluster 38 | ) BaseTapiocaOmnichainEngine(_name, _symbol, _endpoint, _delegate, _extExec, _pearlmit, _cluster) {} 39 | 40 | error twTapNotSet(); 41 | 42 | modifier twTapExists() { 43 | if (address(twTap) == address(0)) revert twTapNotSet(); 44 | _; 45 | } 46 | 47 | /** 48 | * @notice set the twTAP address, can be done only once. 49 | */ 50 | function setTwTAP(address _twTap) external virtual {} 51 | } 52 | -------------------------------------------------------------------------------- /contracts/tokens/BaseTapTokenMsgType.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | /* 5 | 6 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 7 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 8 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 9 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 10 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 11 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 12 | 13 | */ 14 | 15 | abstract contract BaseTapTokenMsgType { 16 | uint16 internal constant MSG_LOCK_TWTAP = 870; 17 | uint16 internal constant MSG_UNLOCK_TWTAP = 871; 18 | uint16 internal constant MSG_CLAIM_REWARDS = 872; 19 | } 20 | -------------------------------------------------------------------------------- /contracts/tokens/ITapToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | // Tapioca 5 | import { 6 | ITapiocaOmnichainEngine, 7 | ERC20PermitApprovalMsg, 8 | ERC721PermitApprovalMsg, 9 | LZSendParam, 10 | ERC20PermitStruct, 11 | ERC721PermitStruct, 12 | ERC20PermitApprovalMsg, 13 | ERC721PermitApprovalMsg, 14 | RemoteTransferMsg 15 | } from "tap-utils/interfaces/periph/ITapiocaOmnichainEngine.sol"; 16 | import {IPearlmit} from "tap-utils/interfaces/periph/IPearlmit.sol"; 17 | import {ICluster} from "tap-utils/interfaces/periph/ICluster.sol"; 18 | 19 | /* 20 | 21 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 22 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 23 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 24 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 25 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 26 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 27 | 28 | */ 29 | 30 | interface ITapToken is ITapiocaOmnichainEngine { 31 | /** 32 | * EVENTS 33 | */ 34 | event LockTwTapReceived(address indexed user, uint96 duration, uint256 amount); 35 | /// @dev twTAP unlock operation received. 36 | event UnlockTwTapReceived(uint256 tokenId, uint256 amount); 37 | 38 | /** 39 | * ERRORS 40 | */ 41 | error TwTapAlreadySet(); 42 | error OnlyHostChain(); // Can execute an action only on host chain 43 | 44 | enum Module { 45 | NonModule, //0 46 | TapTokenSender, 47 | TapTokenReceiver 48 | } 49 | 50 | struct TapTokenConstructorData { 51 | uint256 epochDuration; 52 | address endpoint; 53 | address contributors; 54 | address earlySupporters; 55 | address supporters; 56 | address lTap; 57 | address dao; 58 | address airdrop; 59 | uint256 governanceEid; 60 | address owner; 61 | address tapTokenSenderModule; 62 | address tapTokenReceiverModule; 63 | address extExec; 64 | IPearlmit pearlmit; 65 | ICluster cluster; 66 | } 67 | } 68 | 69 | /// ================================ 70 | /// ========= TAP COMPOSE ========== 71 | /// ================================ 72 | 73 | /** 74 | * @param user The user address to lock in the tokens. 75 | * @param duration The duration of the lock. 76 | * @param amount The amount of TAP to lock. 77 | */ 78 | struct LockTwTapPositionMsg { 79 | address user; 80 | uint96 duration; 81 | uint256 amount; 82 | } 83 | 84 | /** 85 | * @param user The user address to unlock the tokens. 86 | * @param tokenId The tokenId of the TwTap position to unlock. 87 | */ 88 | struct UnlockTwTapPositionMsg { 89 | uint256 tokenId; 90 | } 91 | 92 | /** 93 | * @param tokenId The tokenId of the TwTap position to claim rewards from. 94 | * @param sendParam The parameter for the send operation. 95 | */ 96 | struct ClaimTwTapRewardsMsg { 97 | uint256 tokenId; 98 | LZSendParam[] sendParam; 99 | } 100 | -------------------------------------------------------------------------------- /contracts/tokens/TapTokenSender.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | // LZ 5 | import { 6 | MessagingReceipt, OFTReceipt, SendParam 7 | } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/interfaces/IOFT.sol"; 8 | // Tapioca 9 | import {TapiocaOmnichainSender} from "tap-utils/tapiocaOmnichainEngine/TapiocaOmnichainSender.sol"; 10 | import {IPearlmit} from "tap-utils/interfaces/periph/IPearlmit.sol"; 11 | import {ICluster} from "tap-utils/interfaces/periph/ICluster.sol"; 12 | import {BaseTapToken} from "./BaseTapToken.sol"; 13 | 14 | /* 15 | 16 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 17 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 18 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 19 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 20 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 21 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 22 | 23 | */ 24 | 25 | contract TapTokenSender is BaseTapToken, TapiocaOmnichainSender { 26 | /** 27 | * @dev Used as a module for `TapToken`. Only delegate calls with `TapToken` state are used. 28 | * Set the Pearlmit and Cluster to address(0) because they are not used in this contract. 29 | */ 30 | constructor(string memory _name, string memory _symbol, address _endpoint, address _delegate, address _extExec) 31 | BaseTapToken(_name, _symbol, _endpoint, _delegate, _extExec, IPearlmit(address(0)), ICluster(address(0))) 32 | {} 33 | } 34 | -------------------------------------------------------------------------------- /contracts/tokens/extensions/TapTokenHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | // Tapioca 5 | import { 6 | TapiocaOmnichainEngineHelper, 7 | PrepareLzCallData, 8 | PrepareLzCallReturn, 9 | ComposeMsgData 10 | } from "tap-utils/tapiocaOmnichainEngine/extension/TapiocaOmnichainEngineHelper.sol"; 11 | import {ITapToken, LockTwTapPositionMsg, UnlockTwTapPositionMsg, ClaimTwTapRewardsMsg} from "../ITapToken.sol"; 12 | import {BaseTapTokenMsgType} from "../BaseTapTokenMsgType.sol"; 13 | import {TapTokenCodec} from "../TapTokenCodec.sol"; 14 | 15 | /* 16 | 17 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 18 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 19 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 20 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 21 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 22 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 23 | 24 | */ 25 | 26 | /** 27 | * @title TapTokenHelper 28 | * @author TapiocaDAO 29 | * @notice Used as a helper contract to build calls to the TapToken contract and view functions. 30 | */ 31 | contract TapTokenHelper is TapiocaOmnichainEngineHelper, BaseTapTokenMsgType { 32 | /// ======================= 33 | /// Builder functions 34 | /// ======================= 35 | 36 | /** 37 | * @notice Encodes the message for the lockTwTapPosition() operation. 38 | * 39 | */ 40 | function buildLockTwTapPositionMsg(LockTwTapPositionMsg calldata _lockTwTapPositionMsg) 41 | public 42 | pure 43 | returns (bytes memory) 44 | { 45 | return TapTokenCodec.buildLockTwTapPositionMsg(_lockTwTapPositionMsg); 46 | } 47 | 48 | /** 49 | * @notice Encodes the message for the unlockTwTapPosition() operation. 50 | * 51 | */ 52 | function buildUnlockTwpTapPositionMsg(UnlockTwTapPositionMsg memory _unlockTwTapPositionMsg) 53 | public 54 | pure 55 | returns (bytes memory) 56 | { 57 | return TapTokenCodec.buildUnlockTwTapPositionMsg(_unlockTwTapPositionMsg); 58 | } 59 | 60 | /** 61 | * @notice Encodes the message for the `claimTwpTapRewards` operation. 62 | * @dev !!! NOTE: Will get all the claimable rewards for the TwTap position. 63 | * The caller must ensure that the TwTap contract is approved to claim the. 64 | * @dev The amount field is trivial in this message as it'll be overwritten by the receiver contract. 65 | * Any dust amount will be sent to the user on the same chain as TwTap. 66 | * 67 | * @param _claimTwTapRewardsMsg The claim rewards message. 68 | * - tokenId::uint256: The tokenId of the TwTap position to claim rewards from. 69 | * - lzSendParams::LZSendParam[]: The LZ send params to pass on the remote chain. (B->A) 70 | */ 71 | function buildClaimRewardsMsg(ClaimTwTapRewardsMsg memory _claimTwTapRewardsMsg) 72 | public 73 | pure 74 | returns (bytes memory) 75 | { 76 | return TapTokenCodec.buildClaimTwTapRewards(_claimTwTapRewardsMsg); 77 | } 78 | 79 | /** 80 | * @inheritdoc TapiocaOmnichainEngineHelper 81 | */ 82 | function _sanitizeMsgTypeExtended(uint16 _msgType) internal pure override returns (bool) { 83 | if (_msgType == MSG_LOCK_TWTAP || _msgType == MSG_UNLOCK_TWTAP || _msgType == MSG_CLAIM_REWARDS) { 84 | return true; 85 | } 86 | return false; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /contracts/tokens/module/ModuleManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | /* 5 | 6 | ████████╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ █████╗ 7 | ╚══██╔══╝██╔══██╗██╔══██╗██║██╔═══██╗██╔════╝██╔══██╗ 8 | ██║ ███████║██████╔╝██║██║ ██║██║ ███████║ 9 | ██║ ██╔══██║██╔═══╝ ██║██║ ██║██║ ██╔══██║ 10 | ██║ ██║ ██║██║ ██║╚██████╔╝╚██████╗██║ ██║ 11 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ 12 | 13 | */ 14 | 15 | // TODO move to a common file 16 | /** 17 | * @title ModuleManager 18 | * @author TapiocaDAO 19 | * @notice Help to modularize a contract. 20 | * 21 | */ 22 | abstract contract ModuleManager { 23 | /// @notice returns whitelisted modules 24 | mapping(uint8 module => address moduleAddress) internal _moduleAddresses; 25 | 26 | error ModuleManager__ModuleNotAuthorized(); 27 | 28 | /** 29 | * @notice Sets a module to the whitelist. 30 | * @param _module The module to add. 31 | * @param _moduleAddress The module address. 32 | */ 33 | function _setModule(uint8 _module, address _moduleAddress) internal { 34 | _moduleAddresses[_module] = _moduleAddress; 35 | } 36 | 37 | /** 38 | * @dev Returns the module address, if whitelisted. 39 | * @param _module The module we wants to execute. 40 | */ 41 | function _extractModule(uint8 _module) internal view returns (address) { 42 | address module = _moduleAddresses[_module]; 43 | if (module == address(0)) revert ModuleManager__ModuleNotAuthorized(); 44 | 45 | return module; 46 | } 47 | 48 | /** 49 | * @notice Execute an call to a given module. 50 | * 51 | * @param _module The module to execute. 52 | * @param _data The data to execute. 53 | * @param _forwardRevert If true, forward the revert message from the module. 54 | * 55 | * @return returnData The return data from the module execution, if any. 56 | */ 57 | function _executeModule(uint8 _module, bytes memory _data, bool _forwardRevert) 58 | internal 59 | returns (bytes memory returnData) 60 | { 61 | bool success = true; 62 | address module = _extractModule(_module); 63 | 64 | (success, returnData) = module.delegatecall(_data); 65 | if (!success && !_forwardRevert) { 66 | revert(_getRevertMsg(returnData)); 67 | } 68 | } 69 | 70 | /** 71 | * @notice Return the revert message from an external call. 72 | * @param _returnData The return data from the external call. 73 | */ 74 | function _getRevertMsg(bytes memory _returnData) internal pure returns (string memory) { 75 | if (_returnData.length > 1000) return "Module: reason too long"; 76 | 77 | // If the _res length is less than 68, then the transaction failed silently (without a revert message) 78 | if (_returnData.length < 68) return "Module: data"; 79 | // solhint-disable-next-line no-inline-assembly 80 | assembly { 81 | // Slice the sighash. 82 | _returnData := add(_returnData, 0x04) 83 | } 84 | return abi.decode(_returnData, (string)); // All that remains is the revert string 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'contracts' 3 | out = 'gen/out' 4 | libs = ['node_modules', 'lib'] 5 | cache_path = 'gen/cache_forge' 6 | broadcast = 'gen/broadcast' 7 | 8 | solc_version='0.8.22' 9 | evm_version='paris' 10 | optimizer = true 11 | optimizer_runs = 9999 12 | 13 | remappings = [ 14 | "solidity-bytes-utils/=node_modules/@layerzerolabs/solidity-bytes-utils/", 15 | "tapioca-sdk/=dep/tapioca-sdk/contracts/", 16 | "yieldbox/=dep/tap-yieldbox/contracts/", 17 | "tap-utils/=dep/tap-utils/contracts/", 18 | "permitc/=dep/tap-utils/lib/permitc/src/", # Needs to be init in the periph repo 19 | "tapioca-mocks/=dep/tapioca-mocks/contracts/", 20 | "tapioca-bar/=dep/tapioca-bar/contracts/", 21 | "tapiocaz/=dep/tapiocaz/contracts/", 22 | ] 23 | 24 | [profile.default.fuzz] 25 | max_test_rejects = 10_000 26 | seed = "0xee1d0f7d9556539a9c0e26aed5e63556" 27 | runs = 1000 28 | 29 | 30 | [etherscan] 31 | arbitrum-sepolia = { key = "${ARBITRUM_SEPOLIA_API_KEY}", url = "https://api-sepolia.arbiscan.io/api"} -------------------------------------------------------------------------------- /hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import 'tsconfig-paths/register'; // Important. Used to resolve paths in tsconfig.json 2 | 3 | import conf from './hardhat.export'; 4 | import './hardhat.tasks'; 5 | 6 | export default conf; 7 | -------------------------------------------------------------------------------- /hardhat.tasks.ts: -------------------------------------------------------------------------------- 1 | // Import by order as seen in "scopes" folder 2 | import 'tasks/scopes/deployScope'; // Exception to the rule 3 | 4 | import 'tasks/scopes/adbScope'; 5 | import 'tasks/scopes/vestingScope'; 6 | import 'tasks/scopes/lTapScope'; 7 | import 'tasks/scopes/tapOFTScope'; 8 | import 'tasks/scopes/testnetScope'; 9 | import 'tasks/scopes/tOBScope'; 10 | import 'tasks/scopes/tOLPScope'; 11 | import 'tasks/scopes/twTapScope'; 12 | import 'tasks/scopes/utilScope'; 13 | import 'tasks/scopes/vestingScope'; 14 | import 'tasks/scopes/miscScope'; 15 | -------------------------------------------------------------------------------- /hardhat_scripts/deployment.utils.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import SDK from 'tapioca-sdk'; 3 | import { TContract } from 'tapioca-sdk/dist/shared'; 4 | 5 | type TNetwork = ReturnType< 6 | typeof SDK.API.utils.getSupportedChains 7 | >[number]['name']; 8 | 9 | export const verify = async ( 10 | hre: HardhatRuntimeEnvironment, 11 | address: string, 12 | args: any[], 13 | ) => { 14 | console.log(`[+] Verifying ${address}`); 15 | try { 16 | await hre.run('verify', { 17 | address: address, 18 | constructorArgsParams: args, 19 | }); 20 | console.log('[+] Verified'); 21 | } catch (err: any) { 22 | console.log(`[-] failed to verify ${address}; error: ${err.message}\n`); 23 | } 24 | }; 25 | 26 | export const updateDeployments = async ( 27 | contracts: TContract[], 28 | chainId: string, 29 | tag?: string, 30 | ) => { 31 | SDK.API.db.saveLocally( 32 | SDK.API.db.buildLocalDeployment({ chainId, contracts }), 33 | tag, 34 | ); 35 | }; 36 | 37 | export const registerContract = async ( 38 | hre: HardhatRuntimeEnvironment, 39 | contractName: string, 40 | deploymentName: string, 41 | args: any[], 42 | ): Promise => { 43 | const { deployments, getNamedAccounts } = hre; 44 | const { deploy } = deployments; 45 | const { deployer } = await getNamedAccounts(); 46 | 47 | console.log(`\n[+] Deploying ${contractName} as ${deploymentName}`); 48 | await deploy(deploymentName, { 49 | contract: contractName, 50 | from: deployer, 51 | log: true, 52 | args, 53 | }); 54 | 55 | const contract = await deployments.get(deploymentName); 56 | console.log('[+] Deployed', contractName, 'at', contract.address); 57 | await verify(hre, contract.address, args); 58 | 59 | const deploymentMeta = { 60 | name: deploymentName, 61 | address: contract.address, 62 | meta: { constructorArguments: args }, 63 | }; 64 | await updateDeployments([deploymentMeta], await hre.getChainId()); 65 | 66 | return deploymentMeta; 67 | }; 68 | -------------------------------------------------------------------------------- /hardhat_scripts/gen.ts: -------------------------------------------------------------------------------- 1 | import { Wallet } from 'ethers'; 2 | import fs from 'fs'; 3 | import hre from 'hardhat'; 4 | import MerkleTree from 'merkletreejs'; 5 | 6 | const randomSigners = async (amount: number) => { 7 | const signers: { address: string; pk: string }[] = []; 8 | for (let i = 0; i < amount; i++) { 9 | const signer = hre.ethers.Wallet.createRandom(); 10 | signers.push({ 11 | address: signer.address, 12 | pk: signer.privateKey, 13 | }); 14 | } 15 | return { 16 | signers, 17 | }; 18 | }; 19 | 20 | // Using https://docs.tapioca.xyz/tapioca/launch/option-airdrop#phase-two-core-tapioca-guild numbers 21 | const main = async () => { 22 | const data = [ 23 | { 24 | role: 0, // OG Pearls 25 | ...(await randomSigners(45)), 26 | }, 27 | { 28 | role: 1, // Sushi Frens 29 | ...(await randomSigners(365)), 30 | }, 31 | { 32 | role: 2, // Tapiocans 33 | ...(await randomSigners(416)), 34 | }, 35 | { 36 | role: 3, // Oysters 37 | ...(await randomSigners(1870)), 38 | }, 39 | ]; 40 | fs.writeFileSync('./output.json', JSON.stringify(data, null, 2)); 41 | }; 42 | 43 | main() 44 | .then(() => process.exit(0)) 45 | .catch((error) => { 46 | console.log(error); 47 | }); 48 | -------------------------------------------------------------------------------- /hardhat_scripts/getDeployments-script.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | 3 | export const getDeployments = async (_hre: HardhatRuntimeEnvironment) => { 4 | const { deployments } = _hre; 5 | const all = await deployments.all(); 6 | return Object.keys(all).map(async (e) => ({ [e]: all[e].address })); 7 | }; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tap-token", 3 | "license": "MIT", 4 | "scripts": { 5 | "test": "npx hardhat test", 6 | "coverage": "NODE_ENV=coverage npx hardhat coverage", 7 | "compile": "NODE_ENV=compile hardhat compile --quiet && npm run lint:sol", 8 | "solhint": "solhint contracts/**/*.sol --fix", 9 | "clean": "rm -rf ./cache && rm -rf ./artifacts && rm -rf ./.openzeppelin", 10 | "generate-sdk": "npx hardhat exportSDK", 11 | "prepare": "husky install", 12 | "lint:ts": "eslint . --fix", 13 | "lint:sol": "prettier --write \"./contracts/**/*.sol\" && solhint \"./contracts/**/*.sol\" --fix", 14 | "lint": "npm run lint:ts && npm run lint:sol", 15 | "postinstall": "make" 16 | }, 17 | "devDependencies": { 18 | "@boringcrypto/boring-solidity": "git+https://github.com/boringcrypto/BoringSolidity#e0ff4a7771edfa09a90694c4e0f891938cf62a43", 19 | "@ethersproject/abi": "^5.7.0", 20 | "@ethersproject/providers": "^5.7.0", 21 | "@layerzerolabs/lz-evm-messagelib-v2": "2.3.6", 22 | "@layerzerolabs/lz-evm-oapp-v2": "2.3.6", 23 | "@layerzerolabs/lz-evm-protocol-v2": "2.3.6", 24 | "@layerzerolabs/lz-evm-v1-0.7": "2.3.6", 25 | "@layerzerolabs/lz-v2-utilities": "2.3.6", 26 | "@layerzerolabs/solidity-bytes-utils": "^0.8.0", 27 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.3", 28 | "@nomicfoundation/hardhat-foundry": "^1.1.1", 29 | "@nomicfoundation/hardhat-network-helpers": "^1.0.4", 30 | "@nomiclabs/hardhat-ethers": "^2.1.1", 31 | "@nomiclabs/hardhat-etherscan": "^3.1.7", 32 | "@openzeppelin/contracts": "^4.9.5", 33 | "@openzeppelin/contracts-upgradeable": "^4.8.1", 34 | "@primitivefi/hardhat-dodoc": "^0.2.3", 35 | "@swc/core": "^1.5.24", 36 | "@typechain/ethers-v5": "^10.1.0", 37 | "@typechain/hardhat": "^6.1.2", 38 | "@types/chai": "^4.2.22", 39 | "@types/lodash": "^4.14.191", 40 | "@types/mocha": "^9.0.0", 41 | "@types/node": "^16.11.11", 42 | "@types/uuid": "^9.0.1", 43 | "@typescript-eslint/eslint-plugin": "^5.11.0", 44 | "@typescript-eslint/parser": "^5.11.0", 45 | "@wagmi/cli": "^0.1.5", 46 | "chai": "^4.3.6", 47 | "dotenv": "^10.0.0", 48 | "eslint": "^7.32.0", 49 | "eslint-config-prettier": "^8.3.0", 50 | "eslint-plugin-prettier": "^4.0.0", 51 | "ethers": "^5.7.0", 52 | "glob": "^10.3.10", 53 | "hardhat": "2.19.4", 54 | "hardhat-contract-sizer": "^2.5.1", 55 | "hardhat-deploy": "^0.11.45", 56 | "hardhat-gas-reporter": "^1.0.8", 57 | "http-server": "^14.0.0", 58 | "mocha": "^9.1.3", 59 | "prb-math": "^2.4.1", 60 | "prettier": "^2.5.1", 61 | "prettier-plugin-solidity": "^1.0.0-beta.19", 62 | "solc": "^0.8.4", 63 | "solhint": "^3.3.6", 64 | "solidity-coverage": "^0.8.5", 65 | "ts-node": "^10.9.2", 66 | "tsconfig-paths": "^4.2.0", 67 | "typechain": "8.1.0", 68 | "typescript": "^4.4.3", 69 | "uuid": "^9.0.0", 70 | "write-json-file": "^4.3.0" 71 | }, 72 | "dependencies": { 73 | "@layerzerolabs/lz-v2-utilities": "^2.3.16", 74 | "@nomicfoundation/hardhat-verify": "^2.0.8", 75 | "@prb/math": "^2.5.0", 76 | "@types/inquirer": "^9.0.3", 77 | "@uniswap/sdk-core": "^4.0.10", 78 | "@uniswap/smart-order-router": "^3.21.0", 79 | "@uniswap/v3-core": "^1.0.1", 80 | "@uniswap/v3-periphery": "^1.4.3", 81 | "@uniswap/v3-sdk": "^3.10.2", 82 | "bignumber.js": "^9.1.1", 83 | "hardhat-tracer": "^2.5.0", 84 | "husky": "^8.0.1", 85 | "inquirer": "^8.2.5", 86 | "lodash": "^4.17.21", 87 | "merkletreejs": "^0.3.10", 88 | "tapioca-sdk": "^1.8.28" 89 | }, 90 | "resolutions": { 91 | "@ethersproject/providers": "npm:ethersproject-providers-arbitrum-hotfix@5.7.10" 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /script/utils/ScriptUtils.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import "forge-std/Script.sol"; 5 | 6 | contract DeployOTap is Script { 7 | function determineAddress() external {} 8 | } 9 | -------------------------------------------------------------------------------- /tasks/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tapioca-DAO/tap-token/a6615d6cb5ecd8e5356d336c45b004a484ebabc1/tasks/.DS_Store -------------------------------------------------------------------------------- /tasks/deploy/1-1-deployPreLbpStack.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { 3 | TTapiocaDeployTaskArgs, 4 | TTapiocaDeployerVmPass, 5 | } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 6 | import { buildLTap } from 'tasks/deployBuilds/preLbpStack/buildLTap'; 7 | import { DEPLOYMENT_NAMES } from './DEPLOY_CONFIG'; 8 | 9 | /** 10 | * @notice Called after periph perLbp task 11 | * 12 | * Deploys: Arb 13 | * - LTAP 14 | */ 15 | export const deployPreLbpStack__task = async ( 16 | _taskArgs: TTapiocaDeployTaskArgs, 17 | hre: HardhatRuntimeEnvironment, 18 | ) => { 19 | await hre.SDK.DeployerVM.tapiocaDeployTask( 20 | _taskArgs, 21 | { hre }, 22 | tapiocaDeployTask, 23 | ); 24 | }; 25 | 26 | async function tapiocaDeployTask(params: TTapiocaDeployerVmPass) { 27 | const { 28 | hre, 29 | VM, 30 | tapiocaMulticallAddr, 31 | taskArgs, 32 | isTestnet, 33 | isHostChain, 34 | isSideChain, 35 | } = params; 36 | const { tag } = taskArgs; 37 | const owner = tapiocaMulticallAddr; 38 | 39 | if (isHostChain) { 40 | VM.add(await buildLTap(hre, DEPLOYMENT_NAMES.LTAP, [owner, owner], [])); 41 | } else { 42 | console.log( 43 | '[-] Skipping LTAP deployment, current chain is not host chain.', 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tasks/deploy/1-2-ltapAddLbpTransferAllowed.ts: -------------------------------------------------------------------------------- 1 | import * as TAPIOCA_PERIPH_CONFIG from '@tapioca-periph/config'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { loadGlobalContract, loadLocalContract } from 'tapioca-sdk'; 4 | import { 5 | TTapiocaDeployTaskArgs, 6 | TTapiocaDeployerVmPass, 7 | } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 8 | import { DEPLOYMENT_NAMES } from './DEPLOY_CONFIG'; 9 | import { TAPIOCA_PROJECTS_NAME } from '@tapioca-sdk/api/config'; 10 | 11 | /** 12 | * @notice Called after periph perLbp task 13 | * 14 | * Deploys: Arb 15 | * - LTAP 16 | */ 17 | export const deployLbp__task = async ( 18 | _taskArgs: TTapiocaDeployTaskArgs & { 19 | vault: string; 20 | }, 21 | hre: HardhatRuntimeEnvironment, 22 | ) => { 23 | await hre.SDK.DeployerVM.tapiocaDeployTask( 24 | _taskArgs, 25 | { hre }, 26 | // eslint-disable-next-line @typescript-eslint/no-empty-function 27 | async () => {}, 28 | postDeploy, 29 | ); 30 | }; 31 | 32 | async function postDeploy(params: TTapiocaDeployerVmPass) { 33 | const { 34 | hre, 35 | VM, 36 | tapiocaMulticallAddr, 37 | taskArgs, 38 | isTestnet, 39 | isHostChain, 40 | isSideChain, 41 | } = params; 42 | const { tag } = taskArgs; 43 | const owner = tapiocaMulticallAddr; 44 | 45 | const ltap = await hre.ethers.getContractAt( 46 | 'LTap', 47 | loadLocalContract( 48 | hre, 49 | hre.SDK.chainInfo.chainId, 50 | DEPLOYMENT_NAMES.LTAP, 51 | tag, 52 | ).address, 53 | ); 54 | 55 | const vault = loadGlobalContract( 56 | hre, 57 | TAPIOCA_PROJECTS_NAME.TapiocaPeriph, 58 | hre.SDK.chainInfo.chainId, 59 | TAPIOCA_PERIPH_CONFIG.DEPLOYMENT_NAMES.LBP_VAULT, 60 | tag, 61 | ).address; 62 | 63 | console.log('[+] Adding vault to LTAP transfer allow list'); 64 | await VM.executeMulticall([ 65 | { 66 | target: ltap.address, 67 | callData: ltap.interface.encodeFunctionData( 68 | 'setTransferAllowList', 69 | [vault, true], 70 | ), 71 | allowFailure: false, 72 | }, 73 | ]); 74 | } 75 | -------------------------------------------------------------------------------- /tasks/deploy/2-1-sideChain-deployPostLbpStack.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { TTapiocaDeployerVmPass } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 4 | import { addTapTokenContractsVM } from './2-1-deployPostLbpStack'; 5 | import { setLzPeer__task } from 'tapioca-sdk'; 6 | import { DEPLOYMENT_NAMES } from './DEPLOY_CONFIG'; 7 | 8 | /** 9 | * @notice Meant to be called AFTER deployPostLbpStack_1__task 10 | * 11 | * Deploys: Eth 12 | * - TapToken 13 | * 14 | * Post deploy: Arb, Eth 15 | * - Set LZ peer 16 | */ 17 | export const deploySideChainPostLbpStack_1__task = async ( 18 | _taskArgs: TTapiocaDeployTaskArgs, 19 | hre: HardhatRuntimeEnvironment, 20 | ) => { 21 | await hre.SDK.DeployerVM.tapiocaDeployTask( 22 | _taskArgs, 23 | { 24 | hre, 25 | }, 26 | tapiocaDeployTask, 27 | linkTapContract, 28 | ); 29 | }; 30 | 31 | async function tapiocaDeployTask(params: TTapiocaDeployerVmPass) { 32 | // Settings 33 | const { 34 | hre, 35 | VM, 36 | tapiocaMulticallAddr, 37 | taskArgs, 38 | isTestnet, 39 | isHostChain, 40 | isSideChain, 41 | chainInfo, 42 | } = params; 43 | const { tag } = taskArgs; 44 | const owner = tapiocaMulticallAddr; 45 | 46 | // Build contracts 47 | if (isSideChain) { 48 | await addTapTokenContractsVM({ 49 | hre, 50 | tag, 51 | owner, 52 | VM, 53 | lzEndpointAddress: chainInfo.address, 54 | isTestnet, 55 | isHostChain, 56 | chainInfo, 57 | }); 58 | } else { 59 | console.log( 60 | '[-] Skipping TapToken deployment, current chain is not side chain.', 61 | ); 62 | } 63 | } 64 | 65 | async function linkTapContract(params: TTapiocaDeployerVmPass) { 66 | // Settings 67 | const { hre, taskArgs } = params; 68 | 69 | await setLzPeer__task( 70 | { ...taskArgs, targetName: DEPLOYMENT_NAMES.TAP_TOKEN }, 71 | hre, 72 | ); 73 | } 74 | -------------------------------------------------------------------------------- /tasks/deploy/2-2-deployPostLbpStack.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { TTapiocaDeployerVmPass } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 4 | import { setTapOptionOracle__postDeployLbp } from 'tasks/deployBuilds/postLbpStack/setTapOptionOracle__postDeployLbp'; 5 | 6 | /** 7 | * @notice Meant to be called AFTER deployPostLbpStack_1__task AND `tapioca-periph` postLbp task 8 | * 9 | * Scripts: Arb 10 | * - Set Tap Option oracle in ADB 11 | * - Set USDC as payment token in ADB 12 | */ 13 | export const deployPostLbpStack_2__task = async ( 14 | _taskArgs: TTapiocaDeployTaskArgs, 15 | hre: HardhatRuntimeEnvironment, 16 | ) => { 17 | await hre.SDK.DeployerVM.tapiocaDeployTask( 18 | { ..._taskArgs, load: true }, // Load required 19 | { hre }, 20 | // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars 21 | async (_) => {}, 22 | postDeploymentSetup, 23 | ); 24 | }; 25 | 26 | async function postDeploymentSetup(params: TTapiocaDeployerVmPass) { 27 | const { hre, VM, taskArgs, isTestnet, isHostChain } = params; 28 | const { tag } = taskArgs; 29 | 30 | // Setup contracts 31 | if (isHostChain) { 32 | await VM.executeMulticall( 33 | await setTapOptionOracle__postDeployLbp(hre, tag), 34 | ); 35 | } else { 36 | console.log( 37 | '[-] Skipping post LBP2 stack deployment, current chain is not host chain.', 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tasks/deploy/initPostLbpStack.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { loadVM } from '../utils'; 3 | import { DEPLOYMENT_NAMES } from './DEPLOY_CONFIG'; 4 | 5 | export const initPostLbpStack__task = async ( 6 | taskArgs: { tag?: string; load?: boolean }, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | // Settings 10 | const tag = taskArgs.tag ?? 'default'; 11 | const VM = await loadVM(hre, tag); 12 | 13 | console.log('[+] Init post LBP stack'); 14 | const adb = await hre.ethers.getContractAt( 15 | 'AirdropBroker', 16 | getContract(hre, tag, DEPLOYMENT_NAMES.AIRDROP_BROKER).address, 17 | ); 18 | console.log('[+] AirdropBroker found on', adb.address); 19 | console.log('[+] New epoch on ADB'); 20 | await VM.executeMulticall([ 21 | { 22 | target: adb.address, 23 | callData: adb.interface.encodeFunctionData('newEpoch'), 24 | allowFailure: false, 25 | }, 26 | ]); 27 | console.log('[+] ADB new epoch executed'); 28 | }; 29 | 30 | function getContract( 31 | hre: HardhatRuntimeEnvironment, 32 | tag: string, 33 | contractName: string, 34 | ) { 35 | const contract = hre.SDK.db.findLocalDeployment( 36 | String(hre.network.config.chainId), 37 | contractName, 38 | tag, 39 | )!; 40 | if (!contract) { 41 | throw new Error( 42 | `[-] ${contractName} not found on chain ${hre.network.name} tag ${tag}`, 43 | ); 44 | } 45 | return contract; 46 | } 47 | -------------------------------------------------------------------------------- /tasks/deployBuilds/finalStack/buildEmptyYbStrategy.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { ERC20WithoutStrategy__factory } from '@tapioca-sdk/typechain/YieldBox'; 4 | import { IDependentOn } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 5 | 6 | export const buildEmptyYbStrategy = async ( 7 | hre: HardhatRuntimeEnvironment, 8 | deploymentName: string, 9 | args: Parameters, 10 | dependsOn: IDependentOn[], 11 | ): Promise> => { 12 | const signer = (await hre.ethers.getSigners())[0]; 13 | return { 14 | contract: new ERC20WithoutStrategy__factory(signer), 15 | deploymentName, 16 | args, 17 | dependsOn, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /tasks/deployBuilds/finalStack/options/buildOTAP.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { OTAP__factory } from '@typechain/index'; 4 | 5 | export const buildOTAP = async ( 6 | hre: HardhatRuntimeEnvironment, 7 | deploymentName: string, 8 | args: IDeployerVMAdd['args'], 9 | ): Promise> => { 10 | return { 11 | contract: new OTAP__factory(hre.ethers.provider.getSigner()), 12 | deploymentName, 13 | args, 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /tasks/deployBuilds/finalStack/options/buildTOB.ts: -------------------------------------------------------------------------------- 1 | import { IDependentOn } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { TapiocaOptionBroker__factory } from '@typechain/index'; 3 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 4 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 5 | 6 | export const buildTOB = async ( 7 | hre: HardhatRuntimeEnvironment, 8 | deploymentName: string, 9 | args: Parameters, 10 | dependsOn: IDependentOn[], 11 | ): Promise> => { 12 | return { 13 | contract: new TapiocaOptionBroker__factory( 14 | hre.ethers.provider.getSigner(), 15 | ), 16 | deploymentName, 17 | args, 18 | dependsOn, 19 | runStaticSimulation: false, // We don't want to run the simulation for this contract because of the constructor check 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /tasks/deployBuilds/finalStack/options/buildTOLP.ts: -------------------------------------------------------------------------------- 1 | import { TapiocaOptionLiquidityProvision__factory } from '@typechain/index'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 4 | 5 | export const buildTolp = async ( 6 | hre: HardhatRuntimeEnvironment, 7 | deploymentName: string, 8 | args: Parameters, 9 | ): Promise> => ({ 10 | contract: new TapiocaOptionLiquidityProvision__factory( 11 | hre.ethers.provider.getSigner(), 12 | ), 13 | deploymentName, 14 | args, 15 | }); 16 | -------------------------------------------------------------------------------- /tasks/deployBuilds/finalStack/options/deployTwTap.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { TwTAP__factory } from '@typechain/index'; 4 | import { IDependentOn } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 5 | 6 | export const buildTwTap = async ( 7 | hre: HardhatRuntimeEnvironment, 8 | deploymentName: string, 9 | args: Parameters, 10 | dependsOn: IDependentOn[], 11 | ): Promise> => { 12 | return { 13 | contract: new TwTAP__factory(hre.ethers.provider.getSigner()), 14 | deploymentName, 15 | args, 16 | dependsOn, 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /tasks/deployBuilds/mocks/buildERC721Mock.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { ERC721Mock__factory } from '@tapioca-sdk/typechain/tapioca-mocks'; 4 | 5 | export const buildERC721Mock = async ( 6 | hre: HardhatRuntimeEnvironment, 7 | deploymentName: string, 8 | args: Parameters, 9 | ): Promise> => { 10 | return { 11 | contract: new ERC721Mock__factory((await hre.ethers.getSigners())[0]), 12 | deploymentName, 13 | args, 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /tasks/deployBuilds/mocks/buildLTapMock.ts: -------------------------------------------------------------------------------- 1 | import { IDependentOn } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { LTapMock__factory } from '@typechain/index'; 3 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 4 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 5 | 6 | export const buildLTapMock = async ( 7 | hre: HardhatRuntimeEnvironment, 8 | deploymentName: string, 9 | args: Parameters, 10 | dependsOn: IDependentOn[], 11 | ): Promise> => { 12 | return { 13 | contract: await hre.ethers.getContractFactory('LTapMock'), 14 | deploymentName, 15 | args, 16 | dependsOn, 17 | meta: { 18 | isMock: true, 19 | onlyTestnet: true, 20 | }, 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /tasks/deployBuilds/mocks/buildMockERC20.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { ERC20Mock__factory } from '@tapioca-sdk/typechain/tapioca-mocks'; 4 | 5 | export const buildERC20Mock = async ( 6 | hre: HardhatRuntimeEnvironment, 7 | deploymentName: string, 8 | args: Parameters, 9 | ): Promise> => { 10 | return { 11 | contract: new ERC20Mock__factory((await hre.ethers.getSigners())[0]), 12 | deploymentName, 13 | args, 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /tasks/deployBuilds/mocks/buildOracleMock.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { OracleMock__factory } from '@tapioca-sdk/typechain/tapioca-mocks'; 4 | 5 | export const buildOracleMock = async ( 6 | hre: HardhatRuntimeEnvironment, 7 | deploymentName: string, 8 | args: Parameters, 9 | ): Promise> => { 10 | return { 11 | contract: new OracleMock__factory((await hre.ethers.getSigners())[0]), 12 | deploymentName, 13 | args, 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /tasks/deployBuilds/mocks/buildYieldBoxMock.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { 4 | YieldBoxURIBuilder__factory, 5 | YieldBox__factory, 6 | } from 'tapioca-sdk/dist/typechain/YieldBox'; 7 | 8 | // TODO remove this 9 | export const buildYieldBoxMock = async ( 10 | hre: HardhatRuntimeEnvironment, 11 | ): Promise< 12 | [ 13 | IDeployerVMAdd, 14 | IDeployerVMAdd, 15 | ] 16 | > => { 17 | const ybURIBuilder = await hre.ethers.getContractFactory( 18 | 'YieldBoxURIBuilder', 19 | ); 20 | const yb = await hre.ethers.getContractFactory('YieldBoxMock'); 21 | 22 | return [ 23 | { 24 | contract: ybURIBuilder, 25 | deploymentName: 'YieldBoxURIBuilder', 26 | args: [], 27 | }, 28 | { 29 | contract: yb, 30 | deploymentName: 'YieldBoxMock', 31 | args: [ 32 | // Wrapped Native (we don't need it for now, so we replace it with a dummy value) 33 | hre.ethers.constants.AddressZero, 34 | // YieldBoxURIBuilder, to be replaced by VM 35 | hre.ethers.constants.AddressZero, 36 | ], 37 | dependsOn: [ 38 | { argPosition: 0, deploymentName: 'YieldBoxURIBuilder' }, // dummy value 39 | { argPosition: 1, deploymentName: 'YieldBoxURIBuilder' }, 40 | ], 41 | }, 42 | ]; 43 | }; 44 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/airdrop/buildADB.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { IDependentOn } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 4 | import { AirdropBroker__factory } from '@typechain/index'; 5 | 6 | export const buildADB = async ( 7 | hre: HardhatRuntimeEnvironment, 8 | deploymentName: string, 9 | args: Parameters, 10 | dependsOn: IDependentOn[], 11 | ): Promise> => { 12 | return { 13 | contract: (await hre.ethers.getContractFactory( 14 | 'AirdropBroker', 15 | )) as AirdropBroker__factory, 16 | deploymentName, 17 | args, 18 | dependsOn, 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/airdrop/buildAOTAP.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { AOTAP__factory } from '@typechain/index'; 4 | import { IDependentOn } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 5 | 6 | export const buildAOTAP = async ( 7 | hre: HardhatRuntimeEnvironment, 8 | deploymentName: string, 9 | args: Parameters, 10 | dependsOn: IDependentOn[], 11 | ): Promise> => { 12 | return { 13 | contract: await hre.ethers.getContractFactory('AOTAP'), 14 | deploymentName, 15 | args, 16 | dependsOn, 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/buildPostLbpStackPostDepSetup.ts: -------------------------------------------------------------------------------- 1 | import { TapiocaMulticall } from '@tapioca-sdk/typechain/tapioca-periphery'; 2 | import { 3 | AOTAP__factory, 4 | AirdropBroker__factory, 5 | TapToken__factory, 6 | } from '@typechain/index'; 7 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 8 | import { DEPLOYMENT_NAMES } from 'tasks/deploy/DEPLOY_CONFIG'; 9 | import { loadTapTokenLocalContract } from 'tasks/utils'; 10 | 11 | export const buildPostLbpStackPostDepSetup = async ( 12 | hre: HardhatRuntimeEnvironment, 13 | tag: string, 14 | ): Promise => { 15 | const calls: TapiocaMulticall.CallStruct[] = []; 16 | 17 | /** 18 | * Load contracts 19 | */ 20 | const { adb, tapToken, aoTap } = await loadContract(hre, tag); 21 | 22 | /** 23 | * Broker claim for AOTAP 24 | */ 25 | if ((await aoTap.broker()) !== adb.address) { 26 | console.log('[+] +Call queue: AOTAP broker claim'); 27 | calls.push({ 28 | target: adb.address, 29 | allowFailure: false, 30 | callData: adb.interface.encodeFunctionData('aoTAPBrokerClaim'), 31 | }); 32 | } 33 | 34 | /** 35 | * Set tapToken in ADB 36 | */ 37 | if ( 38 | (await adb.tapToken()).toLocaleLowerCase() !== 39 | tapToken.address.toLocaleLowerCase() 40 | ) { 41 | console.log('[+] +Call queue: set TapToken in AirdropBroker'); 42 | calls.push({ 43 | target: adb.address, 44 | allowFailure: false, 45 | callData: adb.interface.encodeFunctionData('setTapToken', [ 46 | tapToken.address, 47 | ]), 48 | }); 49 | console.log('\t- Parameters:', 'TapToken', tapToken.address); 50 | } 51 | 52 | return calls; 53 | }; 54 | 55 | async function loadContract(hre: HardhatRuntimeEnvironment, tag: string) { 56 | const tapToken = TapToken__factory.connect( 57 | loadTapTokenLocalContract(hre, tag, DEPLOYMENT_NAMES.TAP_TOKEN).address, 58 | hre.ethers.provider.getSigner(), 59 | ); 60 | const adb = AirdropBroker__factory.connect( 61 | loadTapTokenLocalContract(hre, tag, DEPLOYMENT_NAMES.AIRDROP_BROKER) 62 | .address, 63 | hre.ethers.provider.getSigner(), 64 | ); 65 | const aoTap = AOTAP__factory.connect( 66 | loadTapTokenLocalContract(hre, tag, DEPLOYMENT_NAMES.AOTAP).address, 67 | hre.ethers.provider.getSigner(), 68 | ); 69 | 70 | return { 71 | tapToken, 72 | adb, 73 | aoTap, 74 | }; 75 | } 76 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/cluster/temp__buildCluster.ts: -------------------------------------------------------------------------------- 1 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { Cluster__factory } from '@typechain/index'; 4 | 5 | // Temporary build function for Cluster. 6 | // use tapioca-periph to deploy the real Cluster 7 | export const temp__buildCluster = async ( 8 | hre: HardhatRuntimeEnvironment, 9 | deploymentName: string, 10 | args: Parameters, 11 | ): Promise> => { 12 | return { 13 | contract: await hre.ethers.getContractFactory('Cluster'), 14 | deploymentName, 15 | args, 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/pearlmit/temp__buildPearlmit.ts: -------------------------------------------------------------------------------- 1 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { Pearlmit__factory } from '@typechain/index'; 4 | 5 | // Temporary build function for Pearlmit. 6 | // use tapioca-periph to deploy the real Pearlmit 7 | export const temp__buildPearlmit = async ( 8 | hre: HardhatRuntimeEnvironment, 9 | deploymentName: string, 10 | args: Parameters, 11 | ): Promise> => { 12 | return { 13 | contract: await hre.ethers.getContractFactory('Pearlmit'), 14 | deploymentName, 15 | args, 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/setTapOptionOracle__postDeployLbp.ts: -------------------------------------------------------------------------------- 1 | import * as PERIPH_DEPLOY_CONFIG from '@tapioca-periph/config'; 2 | import { TAPIOCA_PROJECTS_NAME } from '@tapioca-sdk/api/config'; 3 | import { TapiocaMulticall } from '@tapioca-sdk/typechain/tapioca-periphery'; 4 | import { AirdropBroker__factory } from '@typechain/index'; 5 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 6 | import { loadGlobalContract } from 'tapioca-sdk'; 7 | import { DEPLOYMENT_NAMES, DEPLOY_CONFIG } from 'tasks/deploy/DEPLOY_CONFIG'; 8 | import { loadTapTokenLocalContract } from 'tasks/utils'; 9 | 10 | export const setTapOptionOracle__postDeployLbp = async ( 11 | hre: HardhatRuntimeEnvironment, 12 | tag: string, 13 | ): Promise => { 14 | const calls: TapiocaMulticall.CallStruct[] = []; 15 | 16 | /** 17 | * Load contracts 18 | */ 19 | const { adb, tapAdbOptionOracle, usdcOracleDeployment } = 20 | await loadContract(hre, tag); 21 | 22 | /** 23 | * Set Tap Option oracle in ADB 24 | */ 25 | if ( 26 | (await adb.tapToken()).toLocaleLowerCase() !== 27 | tapAdbOptionOracle.address.toLocaleLowerCase() 28 | ) { 29 | console.log( 30 | '[+] +Call queue: set TapToken Option Oracle in AirdropBroker', 31 | ); 32 | calls.push({ 33 | target: adb.address, 34 | allowFailure: false, 35 | callData: adb.interface.encodeFunctionData('setTapOracle', [ 36 | tapAdbOptionOracle.address, 37 | '0x', 38 | ]), 39 | }); 40 | } 41 | 42 | /** 43 | * Set USDC as payment token in ADB 44 | */ 45 | const usdcAddr = DEPLOY_CONFIG.MISC[hre.SDK.eChainId]!.USDC; 46 | if ( 47 | (await adb.paymentTokens(usdcAddr)).oracle.toLocaleLowerCase() !== 48 | usdcOracleDeployment.address.toLocaleLowerCase() 49 | ) { 50 | console.log( 51 | '[+] +Call queue: set USDC as payment token in AirdropBroker', 52 | ); 53 | calls.push({ 54 | target: adb.address, 55 | allowFailure: false, 56 | callData: adb.interface.encodeFunctionData('setPaymentToken', [ 57 | usdcAddr, 58 | usdcOracleDeployment.address, 59 | '0x', 60 | ]), 61 | }); 62 | console.log( 63 | '\t- Parameters:', 64 | 'USDC', 65 | usdcAddr, 66 | 'USDC Oracle', 67 | usdcOracleDeployment.address, 68 | 'Oracle Data', 69 | '0x', 70 | ); 71 | } 72 | 73 | return calls; 74 | }; 75 | 76 | async function loadContract(hre: HardhatRuntimeEnvironment, tag: string) { 77 | const usdcOracleDeployment = loadGlobalContract( 78 | hre, 79 | TAPIOCA_PROJECTS_NAME.TapiocaPeriph, 80 | hre.SDK.eChainId, 81 | PERIPH_DEPLOY_CONFIG.DEPLOYMENT_NAMES.USDC_SEER_CL_ORACLE, 82 | tag, 83 | ); 84 | const tapAdbOptionOracle = loadGlobalContract( 85 | hre, 86 | TAPIOCA_PROJECTS_NAME.TapiocaPeriph, 87 | hre.SDK.eChainId, 88 | PERIPH_DEPLOY_CONFIG.DEPLOYMENT_NAMES.TAP_ORACLE, 89 | tag, 90 | ); 91 | 92 | const adb = AirdropBroker__factory.connect( 93 | loadTapTokenLocalContract(hre, tag, DEPLOYMENT_NAMES.AIRDROP_BROKER) 94 | .address, 95 | hre.ethers.provider.getSigner(), 96 | ); 97 | 98 | return { 99 | adb, 100 | tapAdbOptionOracle, 101 | usdcOracleDeployment, 102 | }; 103 | } 104 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/tapToken/buildExtExec.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { IDependentOn } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 4 | import { TapiocaOmnichainExtExec__factory } from '@typechain/index'; 5 | 6 | export const buildExtExec = async ( 7 | hre: HardhatRuntimeEnvironment, 8 | deploymentName: string, 9 | args: Parameters, 10 | dependsOn: IDependentOn[], 11 | ): Promise> => { 12 | return { 13 | contract: (await hre.ethers.getContractFactory( 14 | 'TapiocaOmnichainExtExec', 15 | )) as TapiocaOmnichainExtExec__factory, 16 | deploymentName, 17 | args, 18 | dependsOn, 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/tapToken/buildTapToken.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { IDependentOn } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 4 | import { TapToken__factory } from '@typechain/index'; 5 | 6 | export const buildTapToken = async ( 7 | hre: HardhatRuntimeEnvironment, 8 | deploymentName: string, 9 | args: Parameters, 10 | dependsOn: IDependentOn[], 11 | ): Promise> => { 12 | return { 13 | contract: await hre.ethers.getContractFactory('TapToken'), 14 | deploymentName, 15 | args, 16 | dependsOn, 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/tapToken/buildTapTokenHelper.ts: -------------------------------------------------------------------------------- 1 | import { TapTokenHelper__factory } from '@typechain/index'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 4 | import { DEPLOYMENT_NAMES } from 'tasks/deploy/DEPLOY_CONFIG'; 5 | 6 | export const buildTapTokenHelper = async ( 7 | hre: HardhatRuntimeEnvironment, 8 | ): Promise> => { 9 | return { 10 | contract: await hre.ethers.getContractFactory('TapTokenHelper'), 11 | deploymentName: DEPLOYMENT_NAMES.TAP_TOKEN_HELPER, 12 | args: [], 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/tapToken/buildTapTokenReceiverModule.ts: -------------------------------------------------------------------------------- 1 | import { TapTokenReceiver__factory } from '@typechain/index'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 4 | 5 | export const buildTapTokenReceiverModule = async ( 6 | hre: HardhatRuntimeEnvironment, 7 | deploymentName: string, 8 | args: Parameters, 9 | ): Promise> => { 10 | return { 11 | contract: await hre.ethers.getContractFactory('TapTokenReceiver'), 12 | deploymentName, 13 | args, 14 | dependsOn: [], 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/tapToken/buildTapTokenSenderModule.ts: -------------------------------------------------------------------------------- 1 | import { TapTokenSender__factory } from '@typechain/index'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 4 | 5 | export const buildTapTokenSenderModule = async ( 6 | hre: HardhatRuntimeEnvironment, 7 | deploymentName: string, 8 | args: Parameters, 9 | ): Promise> => { 10 | return { 11 | contract: await hre.ethers.getContractFactory('TapTokenSender'), 12 | deploymentName, 13 | args, 14 | dependsOn: [], 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /tasks/deployBuilds/postLbpStack/vesting/buildVesting.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { Vesting__factory } from '@typechain/index'; 4 | 5 | export const buildVesting = async ( 6 | hre: HardhatRuntimeEnvironment, 7 | deploymentName: string, 8 | args: Parameters, 9 | ): Promise> => { 10 | return { 11 | contract: (await hre.ethers.getContractFactory( 12 | 'Vesting', 13 | )) as Vesting__factory, 14 | deploymentName, 15 | args, 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /tasks/deployBuilds/preLbpStack/buildLTap.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { IDeployerVMAdd } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 3 | import { IDependentOn } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 4 | import { LTap__factory } from '@typechain/index'; 5 | 6 | export const buildLTap = async ( 7 | hre: HardhatRuntimeEnvironment, 8 | deploymentName: string, 9 | args: Parameters, 10 | dependsOn: IDependentOn[], 11 | ): Promise> => { 12 | return { 13 | contract: await hre.ethers.getContractFactory('LTap'), 14 | deploymentName, 15 | args, 16 | dependsOn, 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /tasks/exec/adb/07-ab-setTapOracle.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setTapOracle__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'AirdropBroker', 13 | tag, 14 | ); 15 | const ab = await hre.ethers.getContractAt( 16 | 'AirdropBroker', 17 | dep.contract.address, 18 | ); 19 | 20 | const { tapOracle } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'tapOracle', 23 | message: 'TapOracle address', 24 | }); 25 | 26 | const { tapOracleData } = await inquirer.prompt({ 27 | type: 'input', 28 | name: 'tapOracleData', 29 | message: 'TapOracle data', 30 | }); 31 | 32 | await (await ab.setTapOracle(tapOracle, tapOracleData)).wait(3); 33 | }; 34 | -------------------------------------------------------------------------------- /tasks/exec/adb/08-ab-setPhase2MerkleRoots.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setPhase2MerkleRoots__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'AirdropBroker', 13 | tag, 14 | ); 15 | const ab = await hre.ethers.getContractAt( 16 | 'AirdropBroker', 17 | dep.contract.address, 18 | ); 19 | 20 | const { merkleRoots } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'merkleRoots', 23 | message: 'Merkle roots', 24 | }); 25 | 26 | await (await ab.setPhase2MerkleRoots(merkleRoots)).wait(3); 27 | }; 28 | -------------------------------------------------------------------------------- /tasks/exec/adb/09-ab-registerUserForPhase.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const registerUserForPhase__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'AirdropBroker', 13 | tag, 14 | ); 15 | const ab = await hre.ethers.getContractAt( 16 | 'AirdropBroker', 17 | dep.contract.address, 18 | ); 19 | 20 | const { phase } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'phase', 23 | message: 'Airdrop phase', 24 | }); 25 | 26 | const { users } = await inquirer.prompt({ 27 | type: 'input', 28 | name: 'users', 29 | message: 'Users addresses (split by comma , )', 30 | }); 31 | 32 | const { amounts } = await inquirer.prompt({ 33 | type: 'input', 34 | name: 'amounts', 35 | message: 'Users amounts (split by comma , )', 36 | }); 37 | 38 | const usersArray = users.split(','); 39 | const usersAmounts = amounts.split(','); 40 | if (usersArray.length == usersAmounts.length) 41 | throw new Error('[-] Length mismatch'); 42 | 43 | await ( 44 | await ab.registerUserForPhase(phase, usersArray, usersAmounts) 45 | ).wait(3); 46 | }; 47 | -------------------------------------------------------------------------------- /tasks/exec/adb/10-ab-setPaymentToken.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setPaymentTokenOnAB__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'AirdropBroker', 13 | tag, 14 | ); 15 | const ab = await hre.ethers.getContractAt( 16 | 'AirdropBroker', 17 | dep.contract.address, 18 | ); 19 | 20 | const { paymentToken } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'paymentToken', 23 | message: 'Payment token', 24 | }); 25 | 26 | const { paymentTokenOracle } = await inquirer.prompt({ 27 | type: 'input', 28 | name: 'paymentTokenOracle', 29 | message: 'Choose the oracle address of the payment token', 30 | }); 31 | 32 | const { paymentTokenData } = await inquirer.prompt({ 33 | type: 'input', 34 | name: 'paymentTokenData', 35 | message: 'Choose the payment token oracle data', 36 | }); 37 | 38 | const tx = await ab.setPaymentToken( 39 | paymentToken, 40 | paymentTokenOracle, 41 | paymentTokenData, 42 | ); 43 | const token = hre.ethers.getContractAt('ERC20', paymentToken); 44 | 45 | console.log( 46 | `[+] Setting AB payment token to ${( 47 | await token 48 | ).name()}:${paymentToken}`, 49 | ); 50 | console.log('[+] Transaction hash: ', tx.hash); 51 | await tx.wait(3); 52 | }; 53 | -------------------------------------------------------------------------------- /tasks/exec/adb/11-ab-setPaymentTokenBeneficiary.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setPaymentTokenBeneficiaryAB__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'AirdropBroker', 13 | tag, 14 | ); 15 | const ab = await hre.ethers.getContractAt( 16 | 'AirdropBroker', 17 | dep.contract.address, 18 | ); 19 | 20 | const { paymentTokenBeneficiary } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'paymentTokenBeneficiary', 23 | message: 'Payment token beneficiary', 24 | }); 25 | 26 | await ( 27 | await ab.setPaymentTokenBeneficiary(paymentTokenBeneficiary) 28 | ).wait(3); 29 | }; 30 | -------------------------------------------------------------------------------- /tasks/exec/adb/12-ab-collectPaymentTokens.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const collectPaymentTokensOnAB__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'AirdropBroker', 13 | tag, 14 | ); 15 | const ab = await hre.ethers.getContractAt( 16 | 'AirdropBroker', 17 | dep.contract.address, 18 | ); 19 | 20 | const { paymentTokens } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'paymentTokens', 23 | message: 'Payment tokens (split by comma ,)', 24 | }); 25 | const arr = paymentTokens.split(','); 26 | await (await ab.collectPaymentTokens(arr)).wait(3); 27 | }; 28 | -------------------------------------------------------------------------------- /tasks/exec/adb/13-ab-daoRecoverTAP.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | 4 | export const daoRecoverTAPFromAB__task = async ( 5 | {}, 6 | hre: HardhatRuntimeEnvironment, 7 | ) => { 8 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 9 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 10 | hre, 11 | 'AirdropBroker', 12 | tag, 13 | ); 14 | const ab = await hre.ethers.getContractAt( 15 | 'AirdropBroker', 16 | dep.contract.address, 17 | ); 18 | 19 | await (await ab.daoRecoverTAP()).wait(3); 20 | }; 21 | -------------------------------------------------------------------------------- /tasks/exec/adb/adb_addPaymentToken.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { loadLocalContract } from 'tapioca-sdk'; 4 | import { TTapiocaDeployerVmPass } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 5 | import { DEPLOYMENT_NAMES } from 'tasks/deploy/DEPLOY_CONFIG'; 6 | 7 | export const adb_addPaymentToken__task = async ( 8 | _taskArgs: TTapiocaDeployTaskArgs & { 9 | paymentToken: string; 10 | oracle: string; 11 | }, 12 | hre: HardhatRuntimeEnvironment, 13 | ) => { 14 | await hre.SDK.DeployerVM.tapiocaDeployTask( 15 | _taskArgs, 16 | { hre }, 17 | // eslint-disable-next-line @typescript-eslint/no-empty-function 18 | async () => {}, 19 | tapiocaTask, 20 | ); 21 | }; 22 | 23 | async function tapiocaTask( 24 | params: TTapiocaDeployerVmPass<{ 25 | paymentToken: string; 26 | oracle: string; 27 | }>, 28 | ) { 29 | // Settings 30 | const { hre, VM, tapiocaMulticallAddr, taskArgs, isTestnet, chainInfo } = 31 | params; 32 | const { tag, oracle, paymentToken } = taskArgs; 33 | 34 | const adb = await hre.ethers.getContractAt( 35 | 'AirdropBroker', 36 | loadLocalContract( 37 | hre, 38 | chainInfo.chainId, 39 | DEPLOYMENT_NAMES.AIRDROP_BROKER, 40 | tag, 41 | ).address, 42 | ); 43 | 44 | const oracleContract = await hre.ethers.getContractAt( 45 | 'ITapiocaOracle', 46 | oracle, 47 | ); 48 | 49 | // await adb.setPaymentToken(paymentToken, oracle, '0x'); 50 | await VM.executeMulticall([ 51 | { 52 | target: adb.address, 53 | allowFailure: false, 54 | callData: adb.interface.encodeFunctionData('setPaymentToken', [ 55 | paymentToken, 56 | oracle, 57 | '0x', 58 | ]), 59 | }, 60 | ]); 61 | console.log( 62 | `[+] Payment token set to ${paymentToken}, oracle set to ${oracle}, data set to 0x in ADB contract`, 63 | ); 64 | console.log( 65 | '[+] Oracle rate', 66 | hre.ethers.utils.formatEther((await oracleContract.peek('0x')).rate), 67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /tasks/exec/adb/adb_collectPaymentToken.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { loadLocalContract } from 'tapioca-sdk'; 4 | import { TTapiocaDeployerVmPass } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 5 | import { DEPLOYMENT_NAMES } from 'tasks/deploy/DEPLOY_CONFIG'; 6 | 7 | export const adb_collectPaymentToken__task = async ( 8 | _taskArgs: TTapiocaDeployTaskArgs & { 9 | paymentToken: string; 10 | oracle: string; 11 | }, 12 | hre: HardhatRuntimeEnvironment, 13 | ) => { 14 | await hre.SDK.DeployerVM.tapiocaDeployTask( 15 | _taskArgs, 16 | { hre }, 17 | // eslint-disable-next-line @typescript-eslint/no-empty-function 18 | async () => {}, 19 | tapiocaTask, 20 | ); 21 | }; 22 | 23 | async function tapiocaTask( 24 | params: TTapiocaDeployerVmPass<{ 25 | paymentToken: string; 26 | }>, 27 | ) { 28 | // Settings 29 | const { hre, VM, tapiocaMulticallAddr, taskArgs, isTestnet, chainInfo } = 30 | params; 31 | const { tag, paymentToken } = taskArgs; 32 | 33 | const adb = await hre.ethers.getContractAt( 34 | 'AirdropBroker', 35 | loadLocalContract( 36 | hre, 37 | chainInfo.chainId, 38 | DEPLOYMENT_NAMES.AIRDROP_BROKER, 39 | tag, 40 | ).address, 41 | ); 42 | 43 | await VM.executeMulticall([ 44 | { 45 | target: adb.address, 46 | allowFailure: false, 47 | callData: adb.interface.encodeFunctionData('collectPaymentTokens', [ 48 | [paymentToken], 49 | ]), 50 | }, 51 | ]); 52 | console.log(`[+] Payment token set to ${paymentToken}`); 53 | } 54 | -------------------------------------------------------------------------------- /tasks/exec/adb/adb_collectPayments.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { loadLocalContract } from 'tapioca-sdk'; 4 | import { TTapiocaDeployerVmPass } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 5 | import { DEPLOYMENT_NAMES, DEPLOY_CONFIG } from 'tasks/deploy/DEPLOY_CONFIG'; 6 | 7 | export const adb_collectPayments = async ( 8 | _taskArgs: TTapiocaDeployTaskArgs, 9 | hre: HardhatRuntimeEnvironment, 10 | ) => { 11 | await hre.SDK.DeployerVM.tapiocaDeployTask( 12 | _taskArgs, 13 | { hre }, 14 | // eslint-disable-next-line @typescript-eslint/no-empty-function 15 | async () => {}, 16 | tapiocaTask, 17 | ); 18 | }; 19 | 20 | async function tapiocaTask(params: TTapiocaDeployerVmPass) { 21 | // Settings 22 | const { hre, VM, tapiocaMulticallAddr, taskArgs, isTestnet, chainInfo } = 23 | params; 24 | const { tag } = taskArgs; 25 | 26 | const adb = await hre.ethers.getContractAt( 27 | 'AirdropBroker', 28 | loadLocalContract( 29 | hre, 30 | chainInfo.chainId, 31 | DEPLOYMENT_NAMES.AIRDROP_BROKER, 32 | tag, 33 | ).address, 34 | ); 35 | 36 | await VM.executeMulticall([ 37 | { 38 | target: adb.address, 39 | allowFailure: false, 40 | callData: adb.interface.encodeFunctionData('collectPaymentTokens', [ 41 | [DEPLOY_CONFIG.MISC[hre.SDK.eChainId]!.USDC], 42 | ]), 43 | }, 44 | ]); 45 | } 46 | -------------------------------------------------------------------------------- /tasks/exec/adb/adb_newEpoch.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { loadLocalContract } from 'tapioca-sdk'; 4 | import { TTapiocaDeployerVmPass } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 5 | import { DEPLOYMENT_NAMES } from 'tasks/deploy/DEPLOY_CONFIG'; 6 | 7 | export const adb_newEpoch__task = async ( 8 | _taskArgs: TTapiocaDeployTaskArgs, 9 | hre: HardhatRuntimeEnvironment, 10 | ) => { 11 | await hre.SDK.DeployerVM.tapiocaDeployTask( 12 | _taskArgs, 13 | { hre }, 14 | // eslint-disable-next-line @typescript-eslint/no-empty-function 15 | async () => {}, 16 | tapiocaTask, 17 | ); 18 | }; 19 | 20 | async function tapiocaTask(params: TTapiocaDeployerVmPass) { 21 | // Settings 22 | const { hre, VM, tapiocaMulticallAddr, taskArgs, isTestnet, chainInfo } = 23 | params; 24 | const { tag } = taskArgs; 25 | 26 | const adb = await hre.ethers.getContractAt( 27 | 'AirdropBroker', 28 | loadLocalContract( 29 | hre, 30 | chainInfo.chainId, 31 | DEPLOYMENT_NAMES.AIRDROP_BROKER, 32 | tag, 33 | ).address, 34 | ); 35 | // await adb.setPaymentToken(paymentToken, oracle, '0x'); 36 | await VM.executeMulticall([ 37 | { 38 | target: adb.address, 39 | allowFailure: false, 40 | callData: adb.interface.encodeFunctionData('newEpoch'), 41 | }, 42 | ]); 43 | console.log('[+] New epoch started. Current epoch', await adb.epoch()); 44 | } 45 | -------------------------------------------------------------------------------- /tasks/exec/adb/adb_registerUserForPhase.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { loadLocalContract } from 'tapioca-sdk'; 4 | import { TTapiocaDeployerVmPass } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 5 | import { DEPLOYMENT_NAMES } from 'tasks/deploy/DEPLOY_CONFIG'; 6 | import fs from 'fs'; 7 | import path from 'path'; 8 | import { BigNumberish } from 'ethers'; 9 | 10 | export const adb_setPhase2Roots__task = async ( 11 | _taskArgs: TTapiocaDeployTaskArgs & { phase: string; userFile: string }, 12 | hre: HardhatRuntimeEnvironment, 13 | ) => { 14 | await hre.SDK.DeployerVM.tapiocaDeployTask( 15 | _taskArgs, 16 | { hre }, 17 | // eslint-disable-next-line @typescript-eslint/no-empty-function 18 | async () => {}, 19 | tapiocaTask, 20 | ); 21 | }; 22 | 23 | async function tapiocaTask( 24 | params: TTapiocaDeployerVmPass<{ phase: string; userFile: string }>, 25 | ) { 26 | // Settings 27 | const { hre, VM, tapiocaMulticallAddr, taskArgs, isTestnet, chainInfo } = 28 | params; 29 | const { tag, userFile, phase } = taskArgs; 30 | 31 | // get the json data in the userFile 32 | const jsonData = (await getJsonData(userFile)) as { 33 | user: string; 34 | amount: string; 35 | }[]; 36 | 37 | const adb = await hre.ethers.getContractAt( 38 | 'AirdropBroker', 39 | loadLocalContract( 40 | hre, 41 | chainInfo.chainId, 42 | DEPLOYMENT_NAMES.AIRDROP_BROKER, 43 | tag, 44 | ).address, 45 | ); 46 | 47 | const users: string[] = []; 48 | const amounts: BigNumberish[] = []; 49 | jsonData.forEach((data) => { 50 | users.push(data.user); 51 | amounts.push(data.amount); 52 | }); 53 | 54 | const batchUsers = splitIntoBatches(users, 200); 55 | const batchAmounts = splitIntoBatches(amounts, 200); 56 | 57 | for (let i = 0; i < batchUsers.length; i++) { 58 | const userSlice = batchUsers[i]; 59 | const amountSlice = batchAmounts[i]; 60 | 61 | await VM.executeMulticall([ 62 | { 63 | target: adb.address, 64 | allowFailure: false, 65 | callData: adb.interface.encodeFunctionData( 66 | 'registerUsersForPhase', 67 | [phase, userSlice, amountSlice], 68 | ), 69 | }, 70 | ]); 71 | } 72 | } 73 | 74 | async function getJsonData(filePath: string) { 75 | const fileData = fs.readFileSync(filePath, 'utf-8'); 76 | const jsonData = JSON.parse(fileData); 77 | return jsonData; 78 | } 79 | 80 | function splitIntoBatches(array: T[], batchSize: number): T[][] { 81 | const batches: T[][] = []; 82 | 83 | for (let i = 0; i < array.length; i += batchSize) { 84 | const batch = array.slice(i, i + batchSize); 85 | batches.push(batch); 86 | } 87 | 88 | return batches; 89 | } 90 | -------------------------------------------------------------------------------- /tasks/exec/adb/adb_setMerkleRoots.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { loadLocalContract } from 'tapioca-sdk'; 4 | import { TTapiocaDeployerVmPass } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 5 | import { DEPLOYMENT_NAMES } from 'tasks/deploy/DEPLOY_CONFIG'; 6 | 7 | export const adb_setMerkleRoots__task = async ( 8 | _taskArgs: TTapiocaDeployTaskArgs & { 9 | role0: string; 10 | role1: string; 11 | role2: string; 12 | role3: string; 13 | }, 14 | hre: HardhatRuntimeEnvironment, 15 | ) => { 16 | await hre.SDK.DeployerVM.tapiocaDeployTask( 17 | _taskArgs, 18 | { hre }, 19 | // eslint-disable-next-line @typescript-eslint/no-empty-function 20 | async () => {}, 21 | tapiocaTask, 22 | ); 23 | }; 24 | 25 | async function tapiocaTask( 26 | params: TTapiocaDeployerVmPass<{ 27 | role0: string; 28 | role1: string; 29 | role2: string; 30 | role3: string; 31 | }>, 32 | ) { 33 | // Settings 34 | const { hre, VM, tapiocaMulticallAddr, taskArgs, isTestnet, chainInfo } = 35 | params; 36 | const { tag, role0, role1, role2, role3 } = taskArgs; 37 | const adb = await hre.ethers.getContractAt( 38 | 'AirdropBroker', 39 | loadLocalContract( 40 | hre, 41 | chainInfo.chainId, 42 | DEPLOYMENT_NAMES.AIRDROP_BROKER, 43 | tag, 44 | ).address, 45 | ); 46 | 47 | const data = [role0, role1, role2, role3].map((e) => '0x' + e) as [ 48 | string, 49 | string, 50 | string, 51 | string, 52 | ]; 53 | 54 | // await adb.setPhase2MerkleRoots(roots as [string, string, string, string]); 55 | await VM.executeMulticall([ 56 | { 57 | target: adb.address, 58 | allowFailure: false, 59 | callData: adb.interface.encodeFunctionData('setPhase2MerkleRoots', [ 60 | data, 61 | ]), 62 | }, 63 | ]); 64 | } 65 | -------------------------------------------------------------------------------- /tasks/exec/ltap/23-ltap-setLockedUntil.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setLockedUntilOnLtap__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract(hre, 'LTap', tag); 11 | const ltap = await hre.ethers.getContractAt('LTap', dep.contract.address); 12 | 13 | const { lockedUntil } = await inquirer.prompt({ 14 | type: 'input', 15 | name: 'lockedUntil', 16 | message: 'Locked until', 17 | }); 18 | 19 | await (await ltap.setLockedUntil(lockedUntil)).wait(3); 20 | }; 21 | -------------------------------------------------------------------------------- /tasks/exec/ltap/ltap_deployMock.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { 3 | TTapiocaDeployTaskArgs, 4 | TTapiocaDeployerVmPass, 5 | } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 6 | import { DEPLOYMENT_NAMES } from 'tasks/deploy/DEPLOY_CONFIG'; 7 | import { buildLTapMock } from 'tasks/deployBuilds/mocks/buildLTapMock'; 8 | 9 | export const ltap__deployMock__task = async ( 10 | _taskArgs: TTapiocaDeployTaskArgs, 11 | hre: HardhatRuntimeEnvironment, 12 | ) => { 13 | await hre.SDK.DeployerVM.tapiocaDeployTask( 14 | _taskArgs, 15 | { hre, staticSimulation: false }, 16 | tapiocaDeployTask, 17 | ); 18 | }; 19 | 20 | async function tapiocaDeployTask(params: TTapiocaDeployerVmPass) { 21 | const { hre, VM, tapiocaMulticallAddr, taskArgs, isTestnet } = params; 22 | const { tag } = taskArgs; 23 | const owner = tapiocaMulticallAddr; 24 | 25 | if (!isTestnet) { 26 | throw new Error('[+] This task is only for testnet'); 27 | } 28 | 29 | VM.add(await buildLTapMock(hre, DEPLOYMENT_NAMES.LTAP, [owner, owner], [])); 30 | } 31 | -------------------------------------------------------------------------------- /tasks/exec/ltap/ltap_mintLtapMock.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { loadLocalContract } from 'tapioca-sdk'; 4 | import { TTapiocaDeployerVmPass } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 5 | import { DEPLOYMENT_NAMES } from 'tasks/deploy/DEPLOY_CONFIG'; 6 | import fs from 'fs'; 7 | 8 | export const ltap_mintLtapMock__task = async ( 9 | _taskArgs: TTapiocaDeployTaskArgs & { userFile: string }, 10 | hre: HardhatRuntimeEnvironment, 11 | ) => { 12 | await hre.SDK.DeployerVM.tapiocaDeployTask( 13 | _taskArgs, 14 | { hre }, 15 | // eslint-disable-next-line @typescript-eslint/no-empty-function 16 | async () => {}, 17 | tapiocaTask, 18 | ); 19 | }; 20 | 21 | async function tapiocaTask( 22 | params: TTapiocaDeployerVmPass<{ userFile: string }>, 23 | ) { 24 | // Settings 25 | const { hre, VM, tapiocaMulticallAddr, taskArgs, isTestnet, chainInfo } = 26 | params; 27 | const { tag, userFile } = taskArgs; 28 | 29 | const ltap = await hre.ethers.getContractAt( 30 | 'LTapMock', 31 | loadLocalContract(hre, chainInfo.chainId, DEPLOYMENT_NAMES.LTAP, tag) 32 | .address, 33 | ); 34 | // get the json data in the userFile 35 | const jsonData = (await getJsonData(userFile)) as { 36 | user: string; 37 | amount: string; 38 | }[]; 39 | 40 | const users: string[] = []; 41 | const amounts: string[] = []; 42 | jsonData.forEach((data) => { 43 | users.push(data.user); 44 | amounts.push(data.amount); 45 | }); 46 | 47 | await VM.executeMulticall([ 48 | { 49 | target: ltap.address, 50 | allowFailure: false, 51 | callData: ltap.interface.encodeFunctionData('mint', [ 52 | users, 53 | amounts, 54 | ]), 55 | }, 56 | ]); 57 | } 58 | 59 | async function getJsonData(filePath: string) { 60 | const fileData = fs.readFileSync(filePath, 'utf-8'); 61 | const jsonData = JSON.parse(fileData); 62 | return jsonData; 63 | } 64 | -------------------------------------------------------------------------------- /tasks/exec/ltap/ltap_openRedemptions.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { loadLocalContract } from 'tapioca-sdk'; 4 | import { TTapiocaDeployerVmPass } from 'tapioca-sdk/dist/ethers/hardhat/DeployerVM'; 5 | import { DEPLOYMENT_NAMES } from 'tasks/deploy/DEPLOY_CONFIG'; 6 | 7 | export const ltap_openRedemptions__task = async ( 8 | _taskArgs: TTapiocaDeployTaskArgs, 9 | hre: HardhatRuntimeEnvironment, 10 | ) => { 11 | await hre.SDK.DeployerVM.tapiocaDeployTask( 12 | _taskArgs, 13 | { hre }, 14 | // eslint-disable-next-line @typescript-eslint/no-empty-function 15 | async () => {}, 16 | tapiocaTask, 17 | ); 18 | }; 19 | 20 | async function tapiocaTask(params: TTapiocaDeployerVmPass) { 21 | // Settings 22 | const { hre, VM, tapiocaMulticallAddr, taskArgs, isTestnet, chainInfo } = 23 | params; 24 | const { tag } = taskArgs; 25 | 26 | const ltap = await hre.ethers.getContractAt( 27 | 'LTap', 28 | loadLocalContract(hre, chainInfo.chainId, DEPLOYMENT_NAMES.LTAP, tag) 29 | .address, 30 | ); 31 | const tapToken = loadLocalContract( 32 | hre, 33 | chainInfo.chainId, 34 | DEPLOYMENT_NAMES.TAP_TOKEN, 35 | tag, 36 | ); 37 | 38 | await VM.executeMulticall([ 39 | { 40 | target: ltap.address, 41 | allowFailure: false, 42 | callData: ltap.interface.encodeFunctionData('setTapToken', [ 43 | tapToken.address, 44 | ]), 45 | }, 46 | { 47 | target: ltap.address, 48 | allowFailure: false, 49 | callData: ltap.interface.encodeFunctionData('setOpenRedemption'), 50 | }, 51 | ]); 52 | } 53 | -------------------------------------------------------------------------------- /tasks/exec/misc/sandbox.ts: -------------------------------------------------------------------------------- 1 | import { TTapiocaDeployTaskArgs } from '@tapioca-sdk/ethers/hardhat/DeployerVM'; 2 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 3 | import { loadLocalContract } from 'tapioca-sdk'; 4 | import { DEPLOYMENT_NAMES } from '../../deploy/DEPLOY_CONFIG'; 5 | 6 | export const sandbox__task = async ( 7 | _taskArgs: TTapiocaDeployTaskArgs, 8 | hre: HardhatRuntimeEnvironment, 9 | ) => { 10 | const { tag } = _taskArgs; 11 | const VM = hre.SDK.DeployerVM.loadVM({ hre, tag }); 12 | const tapiocaMulticallAddr = await VM.getMulticall(); 13 | const signer = (await hre.ethers.getSigners())[0]; 14 | 15 | const cluster = await hre.ethers.getContractAt( 16 | 'TapiocaOptionBroker', 17 | loadLocalContract( 18 | hre, 19 | hre.SDK.eChainId, 20 | DEPLOYMENT_NAMES.TAPIOCA_OPTION_BROKER, 21 | tag, 22 | ).address, 23 | ); 24 | 25 | // set tapioca oracle 26 | await VM.executeMulticall([ 27 | { 28 | target: cluster.address, 29 | allowFailure: false, 30 | callData: cluster.interface.encodeFunctionData('setTapOracle', [ 31 | '0x3C8637521c16FAD5F498CA5d2808Db957d034744', 32 | '0x', 33 | ]), 34 | }, 35 | ]); 36 | }; 37 | -------------------------------------------------------------------------------- /tasks/exec/tap/24-tap-rescueEth.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const rescueEthOnTap__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract(hre, 'TapOFT', tag); 11 | const tap = await hre.ethers.getContractAt('TapOFT', dep.contract.address); 12 | 13 | const { amount } = await inquirer.prompt({ 14 | type: 'input', 15 | name: 'amount', 16 | message: 'Rescue amount', 17 | }); 18 | 19 | const { to } = await inquirer.prompt({ 20 | type: 'input', 21 | name: 'to', 22 | message: 'Receiver', 23 | }); 24 | 25 | await (await tap.rescueEth(amount, to)).wait(3); 26 | }; 27 | -------------------------------------------------------------------------------- /tasks/exec/tap/25-tap-setTwTap.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setTwTapOnTap__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract(hre, 'TapOFT', tag); 11 | const tap = await hre.ethers.getContractAt('TapOFT', dep.contract.address); 12 | 13 | const { twTap } = await inquirer.prompt({ 14 | type: 'input', 15 | name: 'twTap', 16 | message: 'twTap address', 17 | }); 18 | 19 | await (await tap.setTwTap(twTap)).wait(3); 20 | }; 21 | -------------------------------------------------------------------------------- /tasks/exec/tap/26-tap-setGovernanceChainIdentifier.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setGovernanceChainIdentifierOnTap__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract(hre, 'TapOFT', tag); 11 | const tap = await hre.ethers.getContractAt('TapOFT', dep.contract.address); 12 | 13 | const { identifier } = await inquirer.prompt({ 14 | type: 'input', 15 | name: 'identifier', 16 | message: 'Governance chain identifier', 17 | }); 18 | 19 | await (await tap.setGovernanceChainIdentifier(identifier)).wait(3); 20 | }; 21 | -------------------------------------------------------------------------------- /tasks/exec/tap/27-tap-updatePause.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const updatePauseOnTap__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract(hre, 'TapOFT', tag); 11 | const tap = await hre.ethers.getContractAt('TapOFT', dep.contract.address); 12 | 13 | const { status } = await inquirer.prompt({ 14 | type: 'confirm', 15 | name: 'status', 16 | message: 'Enable?', 17 | }); 18 | 19 | await (await tap.updatePause(status)).wait(3); 20 | }; 21 | -------------------------------------------------------------------------------- /tasks/exec/tap/28-tap-setMinter.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setMinterOnTap__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract(hre, 'TapOFT', tag); 11 | const tap = await hre.ethers.getContractAt('TapOFT', dep.contract.address); 12 | 13 | const { minter } = await inquirer.prompt({ 14 | type: 'input', 15 | name: 'minter', 16 | message: 'Minter address', 17 | }); 18 | 19 | await (await tap.setMinter(minter)).wait(3); 20 | }; 21 | -------------------------------------------------------------------------------- /tasks/exec/tob/14-tob-setMinWeightFactor.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setMinWeightFactorOnTOB__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TapiocaOptionBroker', 13 | tag, 14 | ); 15 | const tOB = await hre.ethers.getContractAt( 16 | 'TapiocaOptionBroker', 17 | dep.contract.address, 18 | ); 19 | 20 | const { minWeightFactor } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'minWeightFactor', 23 | message: 'Min weight factor', 24 | }); 25 | 26 | await (await tOB.setMinWeightFactor(minWeightFactor)).wait(3); 27 | }; 28 | -------------------------------------------------------------------------------- /tasks/exec/tob/15-tob-setTapOracle.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setTapOracleOnTOB__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TapiocaOptionBroker', 13 | tag, 14 | ); 15 | const tOB = await hre.ethers.getContractAt( 16 | 'TapiocaOptionBroker', 17 | dep.contract.address, 18 | ); 19 | 20 | const { tapOracle } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'tapOracle', 23 | message: 'TapOracle address', 24 | }); 25 | 26 | const { tapOracleData } = await inquirer.prompt({ 27 | type: 'input', 28 | name: 'tapOracleData', 29 | message: 'TapOracle data', 30 | }); 31 | 32 | await (await tOB.setTapOracle(tapOracle, tapOracleData)).wait(3); 33 | }; 34 | -------------------------------------------------------------------------------- /tasks/exec/tob/16-tob-setPaymentToken.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import inquirer from 'inquirer'; 3 | import { TAPIOCA_PROJECTS_NAME } from '@tapioca-sdk/api/config'; 4 | import { Singularity__factory } from '@tapioca-sdk/typechain/tapioca-bar/factories/markets/singularity'; 5 | import { TContract } from 'tapioca-sdk/dist/shared'; 6 | 7 | export const setPaymentTokenOnTOB__task = async ( 8 | {}, 9 | hre: HardhatRuntimeEnvironment, 10 | ) => { 11 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 12 | 13 | const tOBDep = await hre.SDK.hardhatUtils.getLocalContract( 14 | hre, 15 | 'TapiocaOptionBroker', 16 | tag, 17 | ); 18 | const tOB = await hre.ethers.getContractAt( 19 | 'TapiocaOptionBroker', 20 | tOBDep.contract.address, 21 | ); 22 | 23 | const { paymentToken } = await inquirer.prompt({ 24 | type: 'input', 25 | name: 'paymentToken', 26 | message: 'Choose the payment token address', 27 | }); 28 | 29 | const { paymentTokenOracle } = await inquirer.prompt({ 30 | type: 'input', 31 | name: 'paymentTokenOracle', 32 | message: 'Choose the oracle address of the payment token', 33 | }); 34 | 35 | const { paymentTokenData } = await inquirer.prompt({ 36 | type: 'input', 37 | name: 'paymentTokenData', 38 | message: 'Choose the payment token oracle data', 39 | }); 40 | 41 | const tx = await tOB.setPaymentToken( 42 | paymentToken, 43 | paymentTokenOracle, 44 | paymentTokenData, 45 | ); 46 | const token = hre.ethers.getContractAt('ERC20', paymentToken); 47 | 48 | console.log( 49 | `[+] Setting tOB payment token to ${( 50 | await token 51 | ).name()}:${paymentToken}`, 52 | ); 53 | console.log('[+] Transaction hash: ', tx.hash); 54 | await tx.wait(3); 55 | }; 56 | -------------------------------------------------------------------------------- /tasks/exec/tob/17-tob-setPaymentTokenBeneficiary.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setPaymentTokenBeneficiaryOnTOB__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TapiocaOptionBroker', 13 | tag, 14 | ); 15 | const tOB = await hre.ethers.getContractAt( 16 | 'TapiocaOptionBroker', 17 | dep.contract.address, 18 | ); 19 | 20 | const { paymentTokenBeneficiary } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'paymentTokenBeneficiary', 23 | message: 'Payment token beneficiary', 24 | }); 25 | 26 | await ( 27 | await tOB.setPaymentTokenBeneficiary(paymentTokenBeneficiary) 28 | ).wait(3); 29 | }; 30 | -------------------------------------------------------------------------------- /tasks/exec/tob/18-tob-collectPaymentTokens.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const collectPaymentTokensOnTOB__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TapiocaOptionBroker', 13 | tag, 14 | ); 15 | const tOB = await hre.ethers.getContractAt( 16 | 'TapiocaOptionBroker', 17 | dep.contract.address, 18 | ); 19 | 20 | const { paymentTokens } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'paymentTokens', 23 | message: 'Payment tokens (split by comma ,)', 24 | }); 25 | const arr = paymentTokens.split(','); 26 | await (await tOB.collectPaymentTokens(arr)).wait(3); 27 | }; 28 | -------------------------------------------------------------------------------- /tasks/exec/tolp/19-tolp-setRegisterSGL.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import inquirer from 'inquirer'; 3 | import { TAPIOCA_PROJECTS_NAME } from '@tapioca-sdk/api/config'; 4 | import { Singularity__factory } from '@tapioca-sdk/typechain/tapioca-bar/factories/markets/singularity'; 5 | import { TContract } from 'tapioca-sdk/dist/shared'; 6 | import { ERC20WithoutStrategy__factory } from '@tapioca-sdk/typechain/YieldBox'; 7 | import { YieldBox__factory } from '@tapioca-sdk/typechain/YieldBox'; 8 | 9 | export const setRegisterSGLOnTOLP__task = async ( 10 | {}, 11 | hre: HardhatRuntimeEnvironment, 12 | ) => { 13 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 14 | const signer = (await hre.ethers.getSigners())[0]; 15 | 16 | const tOLPDep = await hre.SDK.hardhatUtils.getLocalContract( 17 | hre, 18 | 'TapiocaOptionLiquidityProvision', 19 | tag, 20 | ); 21 | const tOLP = await hre.ethers.getContractAt( 22 | 'TapiocaOptionLiquidityProvision', 23 | tOLPDep.contract.address, 24 | ); 25 | const yieldBox = YieldBox__factory.connect(await tOLP.yieldBox(), signer); 26 | 27 | const choices = hre.SDK.db 28 | .loadGlobalDeployment( 29 | tag, 30 | TAPIOCA_PROJECTS_NAME.TapiocaBar, 31 | await hre.getChainId(), 32 | ) 33 | .filter((e) => !!e.meta.isSGLMarket); 34 | 35 | const { sglToRegister } = await inquirer.prompt({ 36 | type: 'checkbox', 37 | name: 'sglToRegister', 38 | message: 'Choose a Singularity market', 39 | choices, 40 | }); 41 | const filteredChoices: TContract[] = sglToRegister.map((e: any) => 42 | choices.find((c) => c.name === e), 43 | ); 44 | 45 | for (const e of filteredChoices) { 46 | const sgl = Singularity__factory.connect( 47 | e.address, 48 | hre.ethers.provider, 49 | ); 50 | 51 | const strategy = await new ERC20WithoutStrategy__factory(signer).deploy( 52 | yieldBox.address, 53 | sgl.address, 54 | ); 55 | 56 | await ( 57 | await yieldBox.registerAsset(1, sgl.address, strategy.address, 0) 58 | ).wait(3); 59 | 60 | const assetID = await yieldBox.ids(1, sgl.address, strategy.address, 0); 61 | const tx = await tOLP.registerSingularity(sgl.address, assetID, 1); 62 | console.log( 63 | '[+] Registering Singularity market: ', 64 | e.name, 65 | 'with assetID', 66 | assetID, 67 | ); 68 | console.log('[+] Transaction hash: ', tx.hash); 69 | await tx.wait(3); 70 | } 71 | }; 72 | -------------------------------------------------------------------------------- /tasks/exec/tolp/20-tolp-setSglPoolWeight.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setSglPoolWeightOnTOLP__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TapiocaOptionLiquidityProvision', 13 | tag, 14 | ); 15 | const tOLP = await hre.ethers.getContractAt( 16 | 'TapiocaOptionLiquidityProvision', 17 | dep.contract.address, 18 | ); 19 | 20 | const { singularity } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'singularity', 23 | message: 'Singularity address', 24 | }); 25 | 26 | const { weight } = await inquirer.prompt({ 27 | type: 'input', 28 | name: 'weight', 29 | message: 'Singularity weight', 30 | }); 31 | 32 | await (await tOLP.setSGLPoolWeight(singularity, weight)).wait(3); 33 | }; 34 | -------------------------------------------------------------------------------- /tasks/exec/tolp/21-tolp-activateSglPoolRescue.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const activateSglPoolRescueOnTOLP__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TapiocaOptionLiquidityProvision', 13 | tag, 14 | ); 15 | const tOLP = await hre.ethers.getContractAt( 16 | 'TapiocaOptionLiquidityProvision', 17 | dep.contract.address, 18 | ); 19 | 20 | const { singularity } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'singularity', 23 | message: 'Singularity address', 24 | }); 25 | 26 | await (await tOLP.activateSGLPoolRescue(singularity)).wait(3); 27 | }; 28 | -------------------------------------------------------------------------------- /tasks/exec/tolp/22-tolp-unregisterSingularity.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const unregisterSingularityOnTOLP__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const dep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TapiocaOptionLiquidityProvision', 13 | tag, 14 | ); 15 | const tOLP = await hre.ethers.getContractAt( 16 | 'TapiocaOptionLiquidityProvision', 17 | dep.contract.address, 18 | ); 19 | 20 | const { singularity } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'singularity', 23 | message: 'Singularity address', 24 | }); 25 | 26 | await (await tOLP.unregisterSingularity(singularity)).wait(3); 27 | }; 28 | -------------------------------------------------------------------------------- /tasks/exec/twTap/03-twTap-setMaxRewardTokensLength.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import _ from 'lodash'; 3 | import inquirer from 'inquirer'; 4 | 5 | export const setMaxRewardTokensLength__task = async ( 6 | {}, 7 | hre: HardhatRuntimeEnvironment, 8 | ) => { 9 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 10 | const twTAPDep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TwTAP', 13 | tag, 14 | ); 15 | const twTAP = await hre.ethers.getContractAt( 16 | 'TwTAP', 17 | twTAPDep.contract.address, 18 | ); 19 | const { length } = await inquirer.prompt({ 20 | type: 'input', 21 | name: 'length', 22 | message: 'Max length', 23 | }); 24 | await (await twTAP.setMaxRewardTokensLength(length)).wait(3); 25 | }; 26 | -------------------------------------------------------------------------------- /tasks/exec/twTap/04-twTap-setTwTapRewardToken.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import inquirer from 'inquirer'; 3 | 4 | export const setTwTapRewardToken__task = async ( 5 | {}, 6 | hre: HardhatRuntimeEnvironment, 7 | ) => { 8 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 9 | 10 | const twTAPDep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TwTAP', 13 | tag, 14 | ); 15 | const twTAP = await hre.ethers.getContractAt( 16 | 'TwTAP', 17 | twTAPDep.contract.address, 18 | ); 19 | 20 | const { rewardTokenAddress } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'rewardTokenAddress', 23 | message: 'Choose the reward token address', 24 | }); 25 | 26 | const tx = await twTAP.addRewardToken(rewardTokenAddress); 27 | console.log(`[+] Setting twTAP reward token to ${rewardTokenAddress}`); 28 | console.log('[+] Transaction hash: ', tx.hash); 29 | await tx.wait(3); 30 | }; 31 | -------------------------------------------------------------------------------- /tasks/exec/twTap/05-twTap-setDistributeTwTapRewards.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import inquirer from 'inquirer'; 3 | 4 | export const setDistributeTwTapRewards__task = async ( 5 | {}, 6 | hre: HardhatRuntimeEnvironment, 7 | ) => { 8 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 9 | 10 | const twTAPDep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TwTAP', 13 | tag, 14 | ); 15 | const twTAP = await hre.ethers.getContractAt( 16 | 'TwTAP', 17 | twTAPDep.contract.address, 18 | ); 19 | 20 | const { rewardTokenID } = await inquirer.prompt({ 21 | type: 'input', 22 | name: 'rewardTokenID', 23 | message: 'Choose the reward token ID', 24 | }); 25 | 26 | const amount = hre.ethers.utils.parseEther('0.1'); 27 | 28 | const rewardToken = await hre.ethers.getContractAt( 29 | 'ERC20', 30 | await twTAP.rewardTokens(rewardTokenID), 31 | ); 32 | await (await rewardToken.approve(twTAP.address, amount)).wait(3); 33 | const tx = await twTAP.distributeReward(rewardTokenID, amount); 34 | 35 | console.log(`[+] Distributing twTAP reward token to ${rewardTokenID}`); 36 | console.log('[+] Transaction hash: ', tx.hash); 37 | await tx.wait(3); 38 | }; 39 | -------------------------------------------------------------------------------- /tasks/exec/twTap/06-twTap-setAdvanceWeek.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import inquirer from 'inquirer'; 3 | 4 | export const setAdvanceWeek__task = async ( 5 | {}, 6 | hre: HardhatRuntimeEnvironment, 7 | ) => { 8 | const tag = await hre.SDK.hardhatUtils.askForTag(hre, 'local'); 9 | 10 | const twTAPDep = await hre.SDK.hardhatUtils.getLocalContract( 11 | hre, 12 | 'TwTAP', 13 | tag, 14 | ); 15 | const twTAP = await hre.ethers.getContractAt( 16 | 'TwTAP', 17 | twTAPDep.contract.address, 18 | ); 19 | const tx = await twTAP.advanceWeek(50); 20 | console.log('[+] Advancing week by a max of 50'); 21 | console.log('[+] Transaction hash: ', tx.hash); 22 | await tx.wait(3); 23 | }; 24 | -------------------------------------------------------------------------------- /tasks/scopes/deployScope.ts: -------------------------------------------------------------------------------- 1 | import '@nomiclabs/hardhat-ethers'; 2 | import { scope } from 'hardhat/config'; 3 | import { deployFinalStack__task } from '../deploy/3-deployFinalStack'; 4 | import { deployPreLbpStack__task } from 'tasks/deploy/1-1-deployPreLbpStack'; 5 | import { TAP_TASK } from 'tapioca-sdk'; 6 | import { deployPostLbpStack_1__task } from 'tasks/deploy/2-1-deployPostLbpStack'; 7 | import { deployPostLbpStack_2__task } from 'tasks/deploy/2-2-deployPostLbpStack'; 8 | import { deploySideChainPostLbpStack_1__task } from 'tasks/deploy/2-1-sideChain-deployPostLbpStack'; 9 | import { deployLbp__task } from 'tasks/deploy/1-2-ltapAddLbpTransferAllowed'; 10 | 11 | const deployScope = scope('deploys', 'Deployment tasks'); 12 | 13 | TAP_TASK( 14 | deployScope.task( 15 | 'preLbp', 16 | 'Deploy the Pre LBP stack of the tap-token repo. Includes the LTAP.', 17 | deployPreLbpStack__task, 18 | ), 19 | ); 20 | 21 | TAP_TASK( 22 | deployScope.task( 23 | 'ltapLbp', 24 | 'Set the LBP as whitelisted in LTAP transfer.', 25 | deployLbp__task, 26 | ), 27 | ); 28 | 29 | TAP_TASK( 30 | deployScope.task( 31 | 'postLbp1', 32 | 'Deploy the Post LBP stack of the tap-token repo. Includes AOTAP, ADB, Vesting, TapToken. Call postLbp2 after this task.', 33 | deployPostLbpStack_1__task, 34 | ), 35 | ); 36 | TAP_TASK( 37 | deployScope.task( 38 | 'postLbp1-sideChain', 39 | 'Deploy tap-token on side chain, different than the governance chain. Should be called after `postLbp1`.\n periph `preLbp` should be deployed on the said side chain', 40 | deploySideChainPostLbpStack_1__task, 41 | ), 42 | ); 43 | TAP_TASK( 44 | deployScope.task( 45 | 'postLbp2', 46 | 'Setup the contracts of the Post LBP stack of the tap-token repo. Should be called after `postLbp1` and tapioca-periph `postLbp` tasks', 47 | deployPostLbpStack_2__task, 48 | ), 49 | ); 50 | 51 | TAP_TASK( 52 | deployScope.task( 53 | 'final', 54 | 'Deploy and init the final stack of the tap-token repo. Includes the TOB, TOLP, OTAP, TwTap.', 55 | deployFinalStack__task, 56 | ), 57 | ); 58 | -------------------------------------------------------------------------------- /tasks/scopes/lTapScope.ts: -------------------------------------------------------------------------------- 1 | import { scope } from 'hardhat/config'; 2 | import { TAP_TASK } from 'tapioca-sdk'; 3 | import { setLockedUntilOnLtap__task } from 'tasks/exec/ltap/23-ltap-setLockedUntil'; 4 | import { ltap__deployMock__task } from 'tasks/exec/ltap/ltap_deployMock'; 5 | import { ltap_mintLtapMock__task } from 'tasks/exec/ltap/ltap_mintLtapMock'; 6 | import { ltap_openRedemptions__task } from 'tasks/exec/ltap/ltap_openRedemptions'; 7 | 8 | const lTapScope = scope('ltap', 'LockedTap setter tasks'); 9 | 10 | TAP_TASK( 11 | lTapScope.task( 12 | 'openRedemptions', 13 | 'Open redemptions on LTAP.', 14 | ltap_openRedemptions__task, 15 | ), 16 | ); 17 | 18 | // TESTNET 19 | TAP_TASK( 20 | lTapScope.task( 21 | 'deployMock', 22 | 'Deploy a mock LTAP contract.', 23 | ltap__deployMock__task, 24 | ), 25 | ); 26 | TAP_TASK( 27 | lTapScope 28 | .task( 29 | 'mintMock', 30 | 'Mint LTAP tokens to an address.', 31 | ltap_mintLtapMock__task, 32 | ) 33 | .addParam('userFile', 'Path to the JSON file with users and amounts'), 34 | ); 35 | 36 | // --- LTAP 37 | lTapScope.task( 38 | 'setLockedUntilOnLtap', 39 | 'Set locked until on LTAP', 40 | setLockedUntilOnLtap__task, 41 | ); 42 | -------------------------------------------------------------------------------- /tasks/scopes/miscScope.ts: -------------------------------------------------------------------------------- 1 | import { scope } from 'hardhat/config'; 2 | import { TAP_TASK } from 'tapioca-sdk'; 3 | import { sandbox__task } from 'tasks/exec/misc/sandbox'; 4 | 5 | const miscScope = scope('misc', ' Miscellaneous tasks'); 6 | 7 | // Sandbox 8 | TAP_TASK(miscScope.task('sandbox', 'Sandbox', sandbox__task)); 9 | -------------------------------------------------------------------------------- /tasks/scopes/tOBScope.ts: -------------------------------------------------------------------------------- 1 | import { scope } from 'hardhat/config'; 2 | import { setMinWeightFactorOnTOB__task } from 'tasks/exec/tob/14-tob-setMinWeightFactor'; 3 | import { setTapOracleOnTOB__task } from 'tasks/exec/tob/15-tob-setTapOracle'; 4 | import { setPaymentTokenOnTOB__task } from 'tasks/exec/tob/16-tob-setPaymentToken'; 5 | import { setPaymentTokenBeneficiaryOnTOB__task } from 'tasks/exec/tob/17-tob-setPaymentTokenBeneficiary'; 6 | import { collectPaymentTokensOnTOB__task } from 'tasks/exec/tob/18-tob-collectPaymentTokens'; 7 | import { setTOBPaymentToken__task } from 'tasks/exec/setterTasks'; 8 | 9 | const tOBScope = scope('tob', 'TapiocaOptionBroker setter tasks'); 10 | 11 | tOBScope 12 | .task( 13 | 'setTOBPaymentToken', 14 | 'Set a payment token on tOB', 15 | setTOBPaymentToken__task, 16 | ) 17 | .addParam('tknAddress', 'Address of the payment token') 18 | .addParam('oracleAddress', 'Address of the oracle') 19 | .addParam('oracleData', 'Oracle data') 20 | .addOptionalParam('tag', 'Tag of the deployment'); 21 | 22 | tOBScope.task( 23 | 'setPaymentTokenOnTOB', 24 | 'Register an oracle on tOB', 25 | setPaymentTokenOnTOB__task, 26 | ); 27 | 28 | tOBScope.task( 29 | 'setMinWeightFactorOnTOB', 30 | 'Sets the minimum weight factor', 31 | setMinWeightFactorOnTOB__task, 32 | ); 33 | 34 | tOBScope.task( 35 | 'setTapOracleOnTOB', 36 | 'Sets the Tap oracle on tOB', 37 | setTapOracleOnTOB__task, 38 | ); 39 | 40 | tOBScope.task( 41 | 'setPaymentTokenBeneficiaryOnTOB', 42 | 'Sets the payment token beneficiary on tOB', 43 | setPaymentTokenBeneficiaryOnTOB__task, 44 | ); 45 | 46 | tOBScope.task( 47 | 'collectPaymentTokensOnTOB', 48 | 'Collects payment tokens from tOB', 49 | collectPaymentTokensOnTOB__task, 50 | ); 51 | -------------------------------------------------------------------------------- /tasks/scopes/tOLPScope.ts: -------------------------------------------------------------------------------- 1 | import { scope } from 'hardhat/config'; 2 | import { setRegisterSGLOnTOLP__task } from 'tasks/exec/tolp/19-tolp-setRegisterSGL'; 3 | import { setSglPoolWeightOnTOLP__task } from 'tasks/exec/tolp/20-tolp-setSglPoolWeight'; 4 | import { activateSglPoolRescueOnTOLP__task } from 'tasks/exec/tolp/21-tolp-activateSglPoolRescue'; 5 | import { unregisterSingularityOnTOLP__task } from 'tasks/exec/tolp/22-tolp-unregisterSingularity'; 6 | import { 7 | setTOLPRegisterSingularity__task, 8 | setTOLPUnregisterSingularity__task, 9 | } from 'tasks/exec/setterTasks'; 10 | 11 | const tOLPScope = scope('tolp', 'TapiocaOptionLiquidityPool setter tasks'); 12 | 13 | tOLPScope 14 | .task( 15 | 'setTOLPRegisterSingularity', 16 | 'Register an SGL on tOLP ', 17 | setTOLPRegisterSingularity__task, 18 | ) 19 | .addParam('sglAddress', 'Address of the SGL receipt token') 20 | .addParam('weight', 'Weight of the gauge') 21 | .addOptionalParam('tag', 'Tag of the deployment'); 22 | 23 | tOLPScope 24 | .task( 25 | 'setTOLPUnregisterSingularity', 26 | 'Unregister an SGL on tOLP ', 27 | setTOLPUnregisterSingularity__task, 28 | ) 29 | .addParam('sglAddress', 'Address of the SGL receipt token'); 30 | 31 | tOLPScope.task( 32 | 'setRegisterSGLOnTOLP', 33 | 'Register an SGL on tOLP', 34 | setRegisterSGLOnTOLP__task, 35 | ); 36 | 37 | tOLPScope.task( 38 | 'setSglPoolWeightOnTOLP', 39 | 'Sets a registered SGL weight', 40 | setSglPoolWeightOnTOLP__task, 41 | ); 42 | 43 | tOLPScope.task( 44 | 'activateSglPoolRescueOnTOLP', 45 | 'Activates SGL pool rescue on tOLP', 46 | activateSglPoolRescueOnTOLP__task, 47 | ); 48 | 49 | tOLPScope.task( 50 | 'unregisterSingularityOnTOLP', 51 | 'Unregisters SGL on tOLP', 52 | unregisterSingularityOnTOLP__task, 53 | ); 54 | -------------------------------------------------------------------------------- /tasks/scopes/tapOFTScope.ts: -------------------------------------------------------------------------------- 1 | import { scope, task } from 'hardhat/config'; 2 | import { rescueEthOnTap__task } from 'tasks/exec/tap/24-tap-rescueEth'; 3 | import { setTwTapOnTap__task } from 'tasks/exec/tap/25-tap-setTwTap'; 4 | import { setGovernanceChainIdentifierOnTap__task } from 'tasks/exec/tap/26-tap-setGovernanceChainIdentifier'; 5 | import { updatePauseOnTap__task } from 'tasks/exec/tap/27-tap-updatePause'; 6 | import { setMinterOnTap__task } from 'tasks/exec/tap/28-tap-setMinter'; 7 | import { setOFTPeers__task } from 'tasks/exec/setToePeers'; 8 | import { setOracleMockRate__task } from 'tasks/exec/setterTasks'; 9 | import { TAP_TASK } from 'tapioca-sdk'; 10 | import { exec__sendToken__task } from 'tasks/exec/exec__sendToken__task'; 11 | 12 | const tapOFTScope = scope('tapoft', 'TapOFT setter tasks'); 13 | 14 | task( 15 | 'setOracleMockRate', 16 | 'Set exchange rate for a mock oracle', 17 | setOracleMockRate__task, 18 | ) 19 | .addParam('oracleAddress', 'Address of the oracle') 20 | .addParam('rate', 'Exchange rate'); 21 | 22 | // --- TapOFT 23 | tapOFTScope.task( 24 | 'rescueEthOnTap', 25 | 'Rescue ETH on TapOFT', 26 | rescueEthOnTap__task, 27 | ); 28 | tapOFTScope.task('setTwTapOnTap', 'Set twTap on TapOFT', setTwTapOnTap__task); 29 | tapOFTScope.task( 30 | 'setGovernanceChainIdentifierOnTap', 31 | 'Set Governance chain identifier on TapOFT', 32 | setGovernanceChainIdentifierOnTap__task, 33 | ); 34 | tapOFTScope.task( 35 | 'updatePauseOnTap', 36 | 'Toggle pause on TapOFT', 37 | updatePauseOnTap__task, 38 | ); 39 | tapOFTScope.task( 40 | 'setMinterOnTap', 41 | 'Set minter on TapOFT', 42 | setMinterOnTap__task, 43 | ); 44 | 45 | tapOFTScope 46 | .task('setOFTPeers', 'Set OFT peers', setOFTPeers__task) 47 | .addParam( 48 | 'target', 49 | 'Name of the target contract, as deployed in local__db.', 50 | ); 51 | 52 | TAP_TASK( 53 | tapOFTScope 54 | .task( 55 | 'sendToken', 56 | 'Send tokens to a destination contract crosschain', 57 | exec__sendToken__task, 58 | ) 59 | .addParam('amount', 'Amount of tokens to send') 60 | .addParam('targetNetwork', 'Name of the target network') 61 | .addParam('targetAddress', 'Address of the target contract') 62 | .addFlag('isMulticall', 'Whether to use multicall or not'), 63 | ); 64 | -------------------------------------------------------------------------------- /tasks/scopes/testnetScope.ts: -------------------------------------------------------------------------------- 1 | import { scope } from 'hardhat/config'; 2 | import { testClaimRewards__task } from 'tasks/exec/tests/test-claimRewards'; 3 | import { testExitCrossChain__task } from 'tasks/exec/tests/test-exitCrossChain'; 4 | import { testParticipateCrossChain__task } from 'tasks/exec/tests/test-participateCrossChain'; 5 | 6 | const testnetScope = scope('testnet', 'Testnet setter tasks'); 7 | 8 | testnetScope.task( 9 | 'testParticipateCrossChain', 10 | 'Test a cross-chain participation in twTAP', 11 | testParticipateCrossChain__task, 12 | ); 13 | testnetScope.task( 14 | 'testExitCrossChain', 15 | 'Test a cross-chain exit in twTAP', 16 | testExitCrossChain__task, 17 | ); 18 | testnetScope.task( 19 | 'testClaimRewards', 20 | 'Test a cross-chain reward claim in twTAP', 21 | testClaimRewards__task, 22 | ); 23 | -------------------------------------------------------------------------------- /tasks/scopes/twTapScope.ts: -------------------------------------------------------------------------------- 1 | import { scope } from 'hardhat/config'; 2 | import { setMaxRewardTokensLength__task } from 'tasks/exec/twTap/03-twTap-setMaxRewardTokensLength'; 3 | import { setTwTapRewardToken__task } from 'tasks/exec/twTap/04-twTap-setTwTapRewardToken'; 4 | import { setDistributeTwTapRewards__task } from 'tasks/exec/twTap/05-twTap-setDistributeTwTapRewards'; 5 | import { setAdvanceWeek__task } from 'tasks/exec/twTap/06-twTap-setAdvanceWeek'; 6 | 7 | const twTAPScope = scope('twtap', 'twTAP setter tasks'); 8 | 9 | twTAPScope.task( 10 | 'setTwTapRewardToken', 11 | 'Set the reward token for twTAP', 12 | setTwTapRewardToken__task, 13 | ); 14 | 15 | twTAPScope.task( 16 | 'setMaxRewardTokensLength', 17 | 'Set max reward array length', 18 | setMaxRewardTokensLength__task, 19 | ); 20 | 21 | twTAPScope.task( 22 | 'setDistributeTwTapRewards', 23 | 'Distribute rewards for twTAP', 24 | setDistributeTwTapRewards__task, 25 | ); 26 | 27 | twTAPScope.task('setAdvanceWeek', 'Advance by 1 week', setAdvanceWeek__task); 28 | -------------------------------------------------------------------------------- /tasks/scopes/utilScope.ts: -------------------------------------------------------------------------------- 1 | import '@nomiclabs/hardhat-ethers'; 2 | import { glob } from 'glob'; 3 | import { scope } from 'hardhat/config'; 4 | 5 | const utilScope = scope('utils', 'Utility tasks'); 6 | 7 | utilScope.task( 8 | 'accounts', 9 | 'Prints the list of accounts', 10 | async (taskArgs, hre) => { 11 | const accounts = await hre.ethers.getSigners(); 12 | 13 | for (const account of accounts) { 14 | console.log(account.address); 15 | } 16 | }, 17 | ); 18 | 19 | utilScope.task( 20 | 'getContractNames', 21 | 'Get the names of all contracts deployed on the current chain ID.', 22 | async (taskArgs, hre) => { 23 | console.log( 24 | ( 25 | await glob([`${hre.config.paths.artifacts}/**/!(*.dbg).json`]) 26 | ).map((e) => e.split('/').slice(-1)[0]), 27 | ); 28 | }, 29 | ); 30 | utilScope 31 | .task( 32 | 'balanceOf', 33 | 'Get the balance of an account. Default is signer.', 34 | async (taskArgs: { account?: string }, hre) => { 35 | const accounts = await hre.ethers.getSigners(); 36 | const signer = accounts[0]; 37 | const balance = taskArgs.account 38 | ? await hre.ethers.provider.getBalance(taskArgs.account) 39 | : await signer.getBalance(); 40 | console.log(hre.ethers.utils.formatEther(balance), 'ETH'); 41 | }, 42 | ) 43 | .addOptionalParam('account', 'The account to check the balance of.'); 44 | 45 | utilScope.task( 46 | 'currentAccount', 47 | 'Get the address of the loaded private key.', 48 | async (taskArgs: { account?: string }, hre) => { 49 | const accounts = await hre.ethers.getSigners(); 50 | const signer = accounts[0]; 51 | console.log(signer.address); 52 | }, 53 | ); 54 | -------------------------------------------------------------------------------- /tasks/scopes/vestingScope.ts: -------------------------------------------------------------------------------- 1 | import { scope } from 'hardhat/config'; 2 | import { TAP_TASK } from 'tapioca-sdk'; 3 | import { registerUsersVesting__task } from 'tasks/exec/vesting/registerUsersVesting'; 4 | import { vestingInit__task } from 'tasks/exec/vesting/vestingInit'; 5 | 6 | const vestingScope = scope('vesting', 'Vesting setter tasks'); 7 | 8 | TAP_TASK( 9 | vestingScope 10 | .task( 11 | 'registerVestingUsers', 12 | 'Add users for a given vesting', 13 | registerUsersVesting__task, 14 | ) 15 | .addParam('contributorAddress', 'Address of the contributor multisig') 16 | .addParam('seedFile', 'Path to the seed file') 17 | .addParam('preSeedFile', 'Path to the pre-seed file'), 18 | ); 19 | 20 | TAP_TASK( 21 | vestingScope.task('initVesting', 'Inits user vesting', vestingInit__task), 22 | ); 23 | -------------------------------------------------------------------------------- /tasks/utils.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from 'hardhat/types'; 2 | import { loadLocalContract } from 'tapioca-sdk'; 3 | 4 | export const loadVM = async (hre: HardhatRuntimeEnvironment, tag?: string) => { 5 | const VM = new hre.SDK.DeployerVM(hre, { 6 | // Change this if you get bytecode size error / gas required exceeds allowance (550000000)/ anything related to bytecode size 7 | // Could be different by network/RPC provider 8 | bytecodeSizeLimit: 100_000, 9 | debugMode: true, 10 | tag, 11 | }); 12 | return VM; 13 | }; 14 | 15 | export function loadTapTokenLocalContract( 16 | hre: HardhatRuntimeEnvironment, 17 | tag: string, 18 | contractName: string, 19 | ) { 20 | return loadLocalContract(hre, hre.SDK.eChainId, contractName, tag); 21 | } 22 | -------------------------------------------------------------------------------- /test/ERC721Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {ERC721PermitStruct} from "contracts/tokens/ITapToken.sol"; 5 | import {ERC721Permit} from "tap-utils/utils/ERC721Permit.sol"; 6 | import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 7 | 8 | contract ERC721Mock is ERC721, ERC721Permit { 9 | constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) ERC721Permit(name_) {} 10 | 11 | function mint(address to, uint256 tokenId) external { 12 | _mint(to, tokenId); 13 | } 14 | 15 | /** 16 | * @dev Returns the hash of the struct used by the permit function. 17 | * @param _permitData Struct containing permit data. 18 | */ 19 | function getTypedDataHash(ERC721PermitStruct calldata _permitData) public view returns (bytes32) { 20 | bytes32 permitTypeHash_ = keccak256("Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)"); 21 | 22 | bytes32 structHash_ = keccak256( 23 | abi.encode( 24 | permitTypeHash_, _permitData.spender, _permitData.tokenId, _permitData.nonce, _permitData.deadline 25 | ) 26 | ); 27 | return _hashTypedDataV4(structHash_); 28 | } 29 | 30 | function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) 31 | internal 32 | virtual 33 | override(ERC721, ERC721Permit) 34 | { 35 | super._afterTokenTransfer(from, to, firstTokenId, batchSize); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/LTap.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | import {LTap} from "contracts/option-airdrop/LTap.sol"; 7 | 8 | library LTapErrors { 9 | error TransferNotAllowed(); 10 | } 11 | 12 | contract LTapTest is Test { 13 | LTap public ltap; 14 | 15 | uint256 internal aliceKey = 0x1; 16 | address public alice = vm.addr(aliceKey); 17 | uint256 internal bobKey = 0x2; 18 | address public bob = vm.addr(bobKey); 19 | 20 | uint256 public constant INITIAL_SUPPLY = 5_000_000 * 1e18; 21 | 22 | function setUp() public { 23 | ltap = new LTap(address(this), address(this)); 24 | vm.label(address(this), "owner"); 25 | vm.label(alice, "alice"); 26 | } 27 | 28 | function test_setup() public { 29 | assertEq(ltap.totalSupply(), INITIAL_SUPPLY); 30 | assertEq(ltap.balanceOf(address(this)), INITIAL_SUPPLY); 31 | assertEq(ltap.owner(), address(this)); 32 | assertEq(ltap.transferAllowList(address(this)), true); 33 | 34 | assertEq(ltap.openRedemption(), false); 35 | 36 | assertEq(ltap.decimals(), 18); 37 | assertEq(ltap.symbol(), "LTAP"); 38 | assertEq(ltap.name(), "LTAP"); 39 | } 40 | 41 | function test_transfer_allow_list() public { 42 | assertEq(ltap.transferAllowList(alice), false); 43 | 44 | vm.prank(alice); 45 | vm.expectRevert(LTapErrors.TransferNotAllowed.selector); 46 | ltap.transfer(bob, 1 ether); 47 | 48 | deal(address(ltap), alice, 1 ether); 49 | ltap.setTransferAllowList(alice, true); 50 | assertEq(ltap.transferAllowList(alice), true); 51 | vm.prank(alice); 52 | ltap.transfer(bob, 1 ether); 53 | assertEq(ltap.balanceOf(bob), 1 ether); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/LZSetup/mocks/ERC20Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.22; 3 | 4 | import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract ERC20Mock is ERC20 { 7 | constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {} 8 | 9 | function mint(address _to, uint256 _amount) public { 10 | _mint(_to, _amount); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/LZSetup/mocks/ExecutorFeeLibMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | 3 | pragma solidity ^0.8.22; 4 | 5 | import {ExecutorFeeLib} from "@layerzerolabs/lz-evm-messagelib-v2/contracts/ExecutorFeeLib.sol"; 6 | 7 | contract ExecutorFeeLibMock is ExecutorFeeLib { 8 | constructor() ExecutorFeeLib(1e18) {} 9 | 10 | function _isV1Eid(uint32 /*_eid*/ ) internal pure override returns (bool) { 11 | return false; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/LZSetup/mocks/OFTAdapterMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | // import {OFTAdapter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFTAdapter.sol"; 5 | 6 | // contract OFTAdapterMock is OFTAdapter { 7 | // constructor(address _token, address _lzEndpoint, address _owner) OFTAdapter(_token, _lzEndpoint, _owner) {} 8 | 9 | // // @dev expose internal functions for testing purposes 10 | // function debit(uint256 _amountToSendLD, uint256 _minAmountToCreditLD, uint32 _dstEid) 11 | // public 12 | // returns (uint256 amountDebitedLD, uint256 amountToCreditLD) 13 | // { 14 | // return _debit(_amountToSendLD, _minAmountToCreditLD, _dstEid); 15 | // } 16 | 17 | // function debitView(uint256 _amountToSendLD, uint256 _minAmountToCreditLD, uint32 _dstEid) 18 | // public 19 | // view 20 | // returns (uint256 amountDebitedLD, uint256 amountToCreditLD) 21 | // { 22 | // return _debitView(_amountToSendLD, _minAmountToCreditLD, _dstEid); 23 | // } 24 | 25 | // function credit(address _to, uint256 _amountToCreditLD, uint32 _srcEid) public returns (uint256 amountReceivedLD) { 26 | // return _credit(_to, _amountToCreditLD, _srcEid); 27 | // } 28 | 29 | // function increaseOutboundAmount(uint256 _amount) public { 30 | // outboundAmount += _amount; 31 | // } 32 | 33 | // function removeDust(uint256 _amountLD) public view returns (uint256 amountLD) { 34 | // return _removeDust(_amountLD); 35 | // } 36 | // } 37 | -------------------------------------------------------------------------------- /test/LZSetup/mocks/OFTComposerMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import {IOAppComposer} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppComposer.sol"; 5 | 6 | contract OFTComposerMock is IOAppComposer { 7 | // default empty values for testing a lzCompose received message 8 | address public from; 9 | bytes32 public guid; 10 | bytes public message; 11 | address public executor; 12 | bytes public extraData; 13 | 14 | function lzCompose( 15 | address _from, 16 | bytes32 _guid, 17 | bytes calldata _message, 18 | address _executor, 19 | bytes calldata /*_extraData*/ 20 | ) external payable { 21 | from = _from; 22 | guid = _guid; 23 | message = _message; 24 | executor = _executor; 25 | extraData = _message; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/LZSetup/mocks/OFTInspectorMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import {IOAppMsgInspector} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppMsgInspector.sol"; 5 | 6 | contract OFTInspectorMock is IOAppMsgInspector { 7 | function inspect(bytes calldata _message, bytes calldata _options) external pure returns (bool) { 8 | revert InspectionFailed(_message, _options); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/LZSetup/mocks/OFTMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import {OFT} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFT.sol"; 5 | import {SendParam} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFTCore.sol"; 6 | 7 | contract OFTMock is OFT { 8 | constructor(string memory _name, string memory _symbol, address _lzEndpoint, address _owner) 9 | OFT(_name, _symbol, _lzEndpoint, _owner) 10 | {} 11 | 12 | function mint(address _to, uint256 _amount) public { 13 | _mint(_to, _amount); 14 | } 15 | 16 | // @dev expose internal functions for testing purposes 17 | function debit(uint256 _amountToSendLD, uint256 _minAmountToCreditLD, uint32 _dstEid) 18 | public 19 | returns (uint256 amountDebitedLD, uint256 amountToCreditLD) 20 | { 21 | return _debit(msg.sender, _amountToSendLD, _minAmountToCreditLD, _dstEid); 22 | } 23 | 24 | function debitView(uint256 _amountToSendLD, uint256 _minAmountToCreditLD, uint32 _dstEid) 25 | public 26 | view 27 | returns (uint256 amountDebitedLD, uint256 amountToCreditLD) 28 | { 29 | return _debitView(_amountToSendLD, _minAmountToCreditLD, _dstEid); 30 | } 31 | 32 | function removeDust(uint256 _amountLD) public view returns (uint256 amountLD) { 33 | return _removeDust(_amountLD); 34 | } 35 | 36 | function toLD(uint64 _amountSD) public view returns (uint256 amountLD) { 37 | return _toLD(_amountSD); 38 | } 39 | 40 | function toSD(uint256 _amountLD) public view returns (uint64 amountSD) { 41 | return _toSD(_amountLD); 42 | } 43 | 44 | function credit(address _to, uint256 _amountToCreditLD, uint32 _srcEid) public returns (uint256 amountReceivedLD) { 45 | return _credit(_to, _amountToCreditLD, _srcEid); 46 | } 47 | 48 | function buildMsgAndOptions( 49 | SendParam calldata _sendParam, 50 | bytes calldata _extraOptions, 51 | bytes calldata _composeMsg, 52 | uint256 _amountToCreditLD 53 | ) public view returns (bytes memory message, bytes memory options) { 54 | return _buildMsgAndOptions(_sendParam, _amountToCreditLD); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/LZSetup/mocks/SendUln302Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import {MessagingFee} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; 5 | import {SendUln302} from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/uln302/SendUln302.sol"; 6 | import {Packet} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol"; 7 | 8 | import {TestHelper} from "../TestHelper.sol"; 9 | 10 | contract SendUln302Mock is SendUln302 { 11 | // offchain packets schedule 12 | TestHelper public testHelper; 13 | 14 | constructor( 15 | address payable _verifyHelper, 16 | address _endpoint, 17 | uint256 _treasuryGasCap, 18 | uint256 _treasuryGasForFeeCap 19 | ) SendUln302(_endpoint, _treasuryGasCap, _treasuryGasForFeeCap) { 20 | testHelper = TestHelper(_verifyHelper); 21 | } 22 | 23 | function send(Packet calldata _packet, bytes calldata _options, bool _payInLzToken) 24 | public 25 | override 26 | returns (MessagingFee memory fee, bytes memory encodedPacket) 27 | { 28 | (fee, encodedPacket) = super.send(_packet, _options, _payInLzToken); 29 | testHelper.schedulePacket(encodedPacket, _options); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/LZSetup/mocks/SimpleMessageLibMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import {SimpleMessageLib} from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/SimpleMessageLib.sol"; 5 | 6 | import {TestHelper} from "../TestHelper.sol"; 7 | 8 | contract SimpleMessageLibMock is SimpleMessageLib { 9 | // offchain packets schedule 10 | TestHelper public testHelper; 11 | 12 | constructor(address payable _verifyHelper, address _endpoint) SimpleMessageLib(_endpoint, address(0x0)) { 13 | testHelper = TestHelper(_verifyHelper); 14 | } 15 | 16 | function _handleMessagingParamsHook(bytes memory _encodedPacket, bytes memory _options) internal override { 17 | testHelper.schedulePacket(_encodedPacket, _options); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/TapTestHelper.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | 3 | pragma solidity 0.8.22; 4 | 5 | // Lz 6 | import {TestHelper} from "./LZSetup/TestHelper.sol"; 7 | 8 | // Tapioca 9 | import {TestUtils} from "./TestUtils.t.sol"; 10 | 11 | contract TapTestHelper is TestHelper, TestUtils {} 12 | -------------------------------------------------------------------------------- /test/TapTokenMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | // Tapioca 5 | import {ITapToken} from "contracts/tokens/ITapToken.sol"; 6 | import {TapToken} from "contracts/tokens/TapToken.sol"; 7 | 8 | /* 9 | __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____ 10 | _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__ 11 | _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_ 12 | _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_ 13 | _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_ 14 | _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_ 15 | _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_ 16 | _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_ 17 | _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__ 18 | 19 | */ 20 | 21 | contract TapTokenMock is TapToken { 22 | constructor(ITapToken.TapTokenConstructorData memory _data) TapToken(_data) {} 23 | 24 | function freeMint(address _to, uint256 _amount) external virtual { 25 | _mint(_to, _amount); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/TestUtils.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | 3 | pragma solidity 0.8.22; 4 | 5 | // Tapioca 6 | import { 7 | ERC20PermitApprovalMsg, 8 | ERC20PermitStruct, 9 | ERC721PermitApprovalMsg, 10 | ERC721PermitStruct 11 | } from "contracts/tokens/ITapToken.sol"; 12 | 13 | import "forge-std/Test.sol"; 14 | 15 | contract TestUtils is Test { 16 | /** 17 | * @dev Helper to build an ERC20PermitApprovalMsg. 18 | * @param _permit The permit data. 19 | * @param _digest The typed data digest. 20 | * @param _token The token contract to receive the permit. 21 | * @param _pkSigner The private key signer. 22 | */ 23 | function __getERC20PermitData(ERC20PermitStruct memory _permit, bytes32 _digest, address _token, uint256 _pkSigner) 24 | internal 25 | pure 26 | returns (ERC20PermitApprovalMsg memory permitApproval_) 27 | { 28 | (uint8 v_, bytes32 r_, bytes32 s_) = vm.sign(_pkSigner, _digest); 29 | 30 | permitApproval_ = ERC20PermitApprovalMsg({ 31 | token: _token, 32 | owner: _permit.owner, 33 | spender: _permit.spender, 34 | value: _permit.value, 35 | deadline: _permit.deadline, 36 | v: v_, 37 | r: r_, 38 | s: s_ 39 | }); 40 | } 41 | 42 | /** 43 | * @dev Helper to build an ERC721PermitApprovalMsg. 44 | * @param _permit The permit data. 45 | * @param _digest The typed data digest. 46 | * @param _token The token contract to receive the permit. 47 | * @param _pkSigner The private key signer. 48 | */ 49 | function __getERC721PermitData( 50 | ERC721PermitStruct memory _permit, 51 | bytes32 _digest, 52 | address _token, 53 | uint256 _pkSigner 54 | ) internal pure returns (ERC721PermitApprovalMsg memory permitApproval_) { 55 | (uint8 v_, bytes32 r_, bytes32 s_) = vm.sign(_pkSigner, _digest); 56 | 57 | permitApproval_ = ERC721PermitApprovalMsg({ 58 | token: _token, 59 | tokenId: _permit.tokenId, 60 | spender: _permit.spender, 61 | deadline: _permit.deadline, 62 | v: v_, 63 | r: r_, 64 | s: s_ 65 | }); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /test/VestingInitialUnlock.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import "forge-std/Test.sol"; 5 | import {Vesting} from "contracts/tokens/Vesting.sol"; 6 | 7 | contract VestingInitialUnlockTest is Test, Vesting { 8 | // Early Supporters: 9 | // totalAmount = 3,500,000 TAP 10 | // initial unlock = 210,000 TAP 11 | // duration = 2 years 12 | 13 | uint256 totalAmount = 3500000; // 3,500,000 TAP 14 | uint256 initialUnlockAmount = 210000; // 210,000 TAP 15 | 16 | address public __owner = address(123); //owner of the contract 17 | 18 | constructor() Vesting(0, 2 * 365 days, __owner) {} 19 | 20 | function setUp() public { 21 | start = 1718286203; 22 | } 23 | 24 | function test_initial() public { 25 | console.log("start : ", start); 26 | console.log("duration: ", duration); 27 | console.log("totalAmount : ", totalAmount); 28 | console.log("initialUnlockAmount : ", initialUnlockAmount); 29 | 30 | uint256 initialUnlockTimeOffset = _computeTimeFromAmount(start, totalAmount, initialUnlockAmount, duration); 31 | console.log("initialUnlockTimeOffset : ", initialUnlockTimeOffset); 32 | __initialUnlockTimeOffset = initialUnlockTimeOffset; 33 | 34 | { 35 | vm.warp(start + 0 days); 36 | uint256 vestedAmount = _vested(totalAmount); 37 | // assertLt(vestedAmount, totalAmount); 38 | console.log("vestedAmount before the duration is completed : ", vestedAmount); 39 | } 40 | 41 | { 42 | vm.warp(start + 686 days); 43 | uint256 vestedAmount = _vested(totalAmount); 44 | // assertLt(vestedAmount, totalAmount); 45 | console.log("vestedAmount before the duration is completed : ", vestedAmount); 46 | } 47 | { 48 | vm.warp(start + 687 days); 49 | uint256 vestedAmount = _vested(totalAmount); 50 | // assertEq(vestedAmount, totalAmount); 51 | console.log("vestedAmount after the duration is completed : ", vestedAmount); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/mocks/FailingOracleMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | contract FailingOracleMock { 5 | // Get the latest exchange rate 6 | function get(bytes calldata) public view returns (bool, uint256) { 7 | return (false, 0); 8 | } 9 | 10 | // Check the last exchange rate without any state changes 11 | function peek(bytes calldata) public view returns (bool, uint256) { 12 | return (false, 0); 13 | } 14 | 15 | function peekSpot(bytes calldata) public view returns (uint256) { 16 | return 0; 17 | } 18 | 19 | function name(bytes calldata) public view returns (string memory) { 20 | return "Failing Oracle Mock"; 21 | } 22 | 23 | function symbol(bytes calldata) public view returns (string memory) { 24 | return "Failing Oracle Mock"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_exerciseOption.tree: -------------------------------------------------------------------------------- 1 | TOB_exerciseOption 2 | ├── when paused 3 | │ └── it should revert 4 | └── when not paused 5 | ├── when option is expired 6 | │ └── it should revert 7 | └── when option is not expired 8 | ├── when payment token oracle is not set 9 | │ └── it should revert 10 | └── when payment token oracle is set 11 | ├── when caller is not authorized 12 | │ └── it should revert 13 | └── when caller is authorized 14 | ├── when epoch is not advanced 15 | │ └── it should revert 16 | └── when epoch is advanced 17 | ├── when option is in cooldown 18 | │ └── it should revert 19 | └── when option is not in cooldown 20 | ├── when tap amount to buy is lower than 1e18 21 | │ ├── it should revert 22 | │ └── when tap amount is equal to 0 23 | │ ├── it should not revert 24 | │ └── it should emits `ExerciseOption` with max eligible tap as chosen amount 25 | └── when tap amount to buy is bigger than 1e18 26 | ├── when payment token oracle fails to fetch 27 | │ └── it reverts 28 | └── when payment token oracle succeed to fetch 29 | ├── when tap amount is 0 30 | │ └── it continues 31 | ├── it update the exercised amount of the option for the epoch 32 | ├── it sends TAP from the tOB to the `msg.sender` 33 | └── it emits `ExerciseOption` -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_exitPosition.tree: -------------------------------------------------------------------------------- 1 | TOB_exitPosition 2 | ├── when position doesn't exist 3 | │ └── it should revert 4 | └── when position exists 5 | ├── when lock is not expired 6 | │ ├── when sgl is in rescue mode 7 | │ │ ├── it should bypass twAML changes 8 | │ │ └── it should continue 9 | │ └── when sgl is not in rescue mode 10 | │ └── it should revert 11 | └── when lock is expired 12 | ├── it should emit ExitPosition 13 | ├── it should update twAML cumulative 14 | ├── it should delete participation mapping 15 | ├── it should burn the oTAP 16 | └── it should transfer the tOLP to the oTAP owner -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_getCurrentWeek.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TobBaseTest} from "test/unit/options/TapiocaOptionBroker/TobBaseTest.sol"; 5 | 6 | contract TOB_getCurrentWeek is TobBaseTest { 7 | function test_ShouldReturnTheRightTimestampToWeek() external tobInit { 8 | // it should return the right timestamp to week 9 | assertEq(tob.getCurrentWeek(), 0, "TOB_getCurrentWeek: test_ShouldReturnTheRightTimestampToWeek"); 10 | vm.warp(block.timestamp + 1 weeks); 11 | assertEq(tob.getCurrentWeek(), 1, "TOB_getCurrentWeek: test_ShouldReturnTheRightTimestampToWeek"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_getCurrentWeek.tree: -------------------------------------------------------------------------------- 1 | TOB_getCurrentWeek 2 | └── it should return the right timestamp to week -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_getOTCDealDetails.tree: -------------------------------------------------------------------------------- 1 | TOB_getOTCDealDetails 2 | ├── when option expired 3 | │ └── it should revert 4 | ├── when payment token not supported 5 | │ └── it should revert 6 | ├── when in epoch cooldown 7 | │ └── it should revert 8 | ├── when tap amount bigger than eligible 9 | │ └── it should revert 10 | ├── when tap amount less than 1 11 | │ └── it should revert 12 | └── it should return the right OTC deal details -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_getOptionPosition.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TobBaseTest} from "test/unit/options/TapiocaOptionBroker/TobBaseTest.sol"; 5 | import {LockPosition} from "contracts/options/TapiocaOptionLiquidityProvision.sol"; 6 | import {TapOption} from "contracts/options/oTAP.sol"; 7 | 8 | contract TOB_getOptionPosition is TobBaseTest { 9 | function test_ShouldReturnTheRightOptionPosition(uint128 _amount, uint128 _lockDuration) 10 | external 11 | tobInit 12 | registerSingularityPool 13 | { 14 | (_amount, _lockDuration) = _boundValues(_amount, _lockDuration); 15 | _tobParticipate(aliceAddr, _amount, _lockDuration); 16 | // it should return the right option position 17 | (LockPosition memory tOLPLockPosition, TapOption memory oTAPPosition,) = tob.getOptionPosition(1, 0); 18 | assertEq(tOLPLockPosition.sglAssetID, 102, "TOB_getOptionPosition: Invalid sglAssetID"); 19 | assertEq(oTAPPosition.tOLP, 1, "TOB_getOptionPosition: Invalid tOLP"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_getOptionPosition.tree: -------------------------------------------------------------------------------- 1 | TOB_getOptionPosition 2 | └── it should return the right option position -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_getSingularityPoolInfo.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TobBaseTest, IERC20} from "test/unit/options/TapiocaOptionBroker/TobBaseTest.sol"; 5 | 6 | contract getSingularityPoolInfo is TobBaseTest { 7 | function test_ShouldReturnTheRightValues(uint128 _lockAmount, uint128 _lockDuration) external { 8 | (_lockAmount, _lockDuration) = _boundValues(_lockAmount, _lockDuration); 9 | _setupAndParticipate(aliceAddr, _lockAmount, _lockDuration); 10 | 11 | // it should return the right values 12 | (uint256 assetId, uint256 totalDeposited, uint256 weight, bool isInRescue,,,,) = 13 | tob.getSingularityPoolInfo(IERC20(address(toftSglEthMarket)), 1); 14 | assertEq(assetId, ybAssetIdToftSglEthMarket, "TOB_getSingularityPoolInfo: Invalid assetId"); 15 | assertEq(totalDeposited, _lockAmount, "TOB_getSingularityPoolInfo: Invalid totalDeposited"); 16 | assertEq(weight, 1, "TOB_getSingularityPoolInfo: Invalid weight"); 17 | assertEq(isInRescue, false, "TOB_getSingularityPoolInfo: Invalid isInRescue"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_getSingularityPoolInfo.tree: -------------------------------------------------------------------------------- 1 | getSingularityPoolInfo 2 | └── it should return the right values -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_newEpoch.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TobBaseTest, TapiocaOptionBroker, ITapiocaOracle} from "test/unit/options/TapiocaOptionBroker/TobBaseTest.sol"; 5 | 6 | contract TOB_newEpoch is TobBaseTest { 7 | function test_RevertWhen_NotAuthorized() external { 8 | // it should revert 9 | vm.expectRevert(TapiocaOptionBroker.NotAuthorized.selector); 10 | tob.newEpoch(); 11 | } 12 | 13 | modifier whenAuthorized() { 14 | vm.startPrank(adminAddr); 15 | cluster.setRoleForContract(adminAddr, keccak256("NEW_EPOCH"), true); 16 | _; 17 | } 18 | 19 | function test_RevertWhen_EpochNotOver() external whenAuthorized { 20 | vm.warp(0); 21 | // it should revert 22 | vm.expectRevert(TapiocaOptionBroker.TooSoon.selector); 23 | tob.newEpoch(); 24 | } 25 | 26 | modifier whenEpochIsOver() { 27 | skip(tob.EPOCH_DURATION()); 28 | _; 29 | } 30 | 31 | function test_RevertWhen_NotActiveSingularities() external whenAuthorized whenEpochIsOver { 32 | // it should revert 33 | vm.expectRevert(TapiocaOptionBroker.NoActiveSingularities.selector); 34 | tob.newEpoch(); 35 | } 36 | 37 | modifier whenActiveSingularitiesExist() { 38 | _registerSingularityPool(); 39 | _; 40 | } 41 | 42 | function test_RevertWhen_TapOracleFailsToQuery() 43 | external 44 | tobInit 45 | whenEpochIsOver 46 | whenActiveSingularitiesExist 47 | whenAuthorized 48 | { 49 | tob.setTapOracle(ITapiocaOracle(address(failingOracleMock)), "0x"); 50 | // it should revert 51 | vm.expectRevert(TapiocaOptionBroker.Failed.selector); 52 | tob.newEpoch(); 53 | } 54 | 55 | function test_WhenTapOracleQueryWorks() 56 | external 57 | tobInit 58 | whenEpochIsOver 59 | whenActiveSingularitiesExist 60 | whenAuthorized 61 | { 62 | // it should emit new epoch event 63 | vm.expectEmit(true, false, false, false); 64 | emit TapiocaOptionBroker.NewEpoch(1, 0, 0); 65 | tob.newEpoch(); 66 | // it should increment `epoch` by 1 67 | assertEq(tob.epoch(), 1, "TOB_newEpoch::test_ShouldAdvanceTheEpoch: Invalid epoch"); 68 | // it should extract and emit tap to gauges 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_newEpoch.tree: -------------------------------------------------------------------------------- 1 | TOB_newEpoch 2 | ├── when not authorized 3 | │ └── it should revert 4 | └── when authorized 5 | ├── when epoch not over 6 | │ └── it should revert 7 | └── when epoch is over 8 | ├── when not active singularities 9 | │ └── it should revert 10 | └── when active singularities exist 11 | ├── when tap oracle fails to query 12 | │ └── it should revert 13 | └── when tap oracle query works 14 | ├── it should emit new epoch event 15 | ├── it should increment `epoch` by 1 16 | └── it should extract and emit tap to gauges -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_ownerActions.tree: -------------------------------------------------------------------------------- 1 | TOB_ownerActions 2 | ├── when calling init 3 | │ └── it should revert if called multiple times 4 | ├── when calling setVirtualTotalAmount 5 | │ └── it should revert if not owner 6 | ├── when calling setMinWeightFactor 7 | │ └── it should revert if not owner 8 | ├── when calling setTapOracle 9 | │ └── it should revert if not owner 10 | ├── when calling setPaymentToken 11 | │ └── it should revert if not owner 12 | ├── when calling setPaymentTokenBeneficiary 13 | │ └── it should revert if not owner 14 | ├── when calling collectPaymentTokens 15 | │ └── it should revert if not owner 16 | ├── when calling setCluster 17 | │ └── it should revert if not owner 18 | └── when calling setPause 19 | └── it should revert if not owner -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_participate.tree: -------------------------------------------------------------------------------- 1 | TOB_participate 2 | ├── when paused 3 | │ └── it should revert 4 | └── when not paused 5 | ├── when lock expired 6 | │ └── it should revert 7 | └── when lock not expired 8 | ├── when epoch not advanced 9 | │ └── it should revert 10 | └── when epoch is advanced 11 | ├── when position expired 12 | │ └── it should revert 13 | └── when position is active 14 | ├── when lock duration too small 15 | │ └── it should revert 16 | └── when lock duration is big enough 17 | ├── when lock duration is not a multiple of epoch duration 18 | │ └── it should revert 19 | └── when lock duration is a multiple of epoch duration 20 | ├── when Pearlmit transfer fails 21 | │ └── it should revert 22 | └── when Pearlmit transfer succeed 23 | ├── when rewards are lower than minReward 24 | │ └── it should revert 25 | └── when rewards are bigger than minReward 26 | ├── when magnitude bigger than the max cap 27 | │ └── it should revert 28 | └── when magnitude is in range 29 | ├── when locker does not have voting power 30 | │ ├── it should not update cumulative 31 | │ └── it should participate 32 | ├── when locker have voting power 33 | │ ├── it should update cumulative 34 | │ └── it should participate 35 | └── when it should participate 36 | ├── it should emit Participate 37 | ├── it should save the twAML participation 38 | ├── it should record the amount for next epoch and decrease it on the last 39 | └── it should mint a new oTAP -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_refreshTotalDeposited.tree: -------------------------------------------------------------------------------- 1 | TOB_refreshTotalDeposited 2 | ├── when param array is empty 3 | │ └── it should do nothing 4 | └── when param array is set 5 | ├── when refresh cooldown is not met 6 | │ └── it should return the previously set value 7 | └── when refresh cooldown is met 8 | ├── it should update lastTotalDepositedForSgl with the newly fetch value 9 | ├── it should update lastTotalDepositRefreshSgl to block.timestamp 10 | └── it should return the new value of lastTotalDepositedForSgl -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_timestampToWeek.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TobBaseTest} from "test/unit/options/TapiocaOptionBroker/TobBaseTest.sol"; 5 | 6 | contract TOB_timestampToWeek is TobBaseTest { 7 | function test_WhenTimestampIs0() external tobInit { 8 | // it should return 0 9 | assertEq(tob.timestampToWeek(block.timestamp), 0, "TOB_timestampToWeek: test_WhenTimestampIs0"); 10 | } 11 | 12 | function test_WhenTimestampIsLessThanEmissionStartTime() external tobInit { 13 | // it should return 0 14 | assertEq( 15 | tob.timestampToWeek(block.timestamp - 1 weeks), 16 | 0, 17 | "TOB_timestampToWeek: test_WhenTimestampIsLessThanEmissionStartTime" 18 | ); 19 | } 20 | 21 | function test_ShouldReturnTheRightTimestampToWeek() external tobInit { 22 | // it should return the right timestamp to week 23 | assertEq( 24 | tob.timestampToWeek(block.timestamp + 1 weeks), 25 | 1, 26 | "TOB_timestampToWeek: test_ShouldReturnTheRightTimestampToWeek" 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionBroker/TOB_timestampToWeek.tree: -------------------------------------------------------------------------------- 1 | TOB_timestampToWeek 2 | ├── when timestamp is 0 3 | │ └── it should return 0 4 | ├── when timestamp is less than emissionStartTime 5 | │ └── it should return 0 6 | └── it should return the right timestamp to week -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_activateSGLPoolRescue.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TolpBaseTest, IERC20, SingularityPool} from "./TolpBaseTest.sol"; 5 | 6 | contract TOLP_activateSGLPoolRescue is TolpBaseTest { 7 | function test_ShouldSetRescueToTrue() external registerSingularityPool { 8 | // it should set rescue to true 9 | vm.startPrank(adminAddr); 10 | 11 | tolp.requestSglPoolRescue(ybAssetIdToftSglEthMarket); 12 | vm.warp(block.timestamp + tolp.rescueCooldown()); 13 | tolp.activateSGLPoolRescue(IERC20(address(toftSglEthMarket))); 14 | (,,, bool rescue) = tolp.activeSingularities(IERC20(address(toftSglEthMarket))); 15 | assertEq(rescue, true, "TOLP_activateSGLPoolRescue: Invalid rescue"); 16 | } 17 | 18 | function test_RevertWhen_SglAssetIdIs0() external { 19 | // it should revert 20 | vm.startPrank(adminAddr); 21 | 22 | vm.expectRevert(NotRegistered.selector); 23 | tolp.activateSGLPoolRescue(IERC20(address(toftSglEthMarket))); 24 | } 25 | 26 | function test_RevertWhen_SglRescueIsTrue() external registerSingularityPool { 27 | // it should revert 28 | vm.startPrank(adminAddr); 29 | 30 | tolp.requestSglPoolRescue(ybAssetIdToftSglEthMarket); 31 | vm.warp(block.timestamp + tolp.rescueCooldown()); 32 | tolp.activateSGLPoolRescue(IERC20(address(toftSglEthMarket))); 33 | vm.expectRevert(AlreadyActive.selector); 34 | tolp.activateSGLPoolRescue(IERC20(address(toftSglEthMarket))); 35 | } 36 | 37 | function test_RevertWhen_SglRescueRequestIs0() external registerSingularityPool { 38 | // it should revert 39 | vm.startPrank(adminAddr); 40 | 41 | vm.expectRevert(NotActive.selector); 42 | tolp.activateSGLPoolRescue(IERC20(address(toftSglEthMarket))); 43 | } 44 | 45 | function test_RevertWhen_RescueCooldownNotMet() external registerSingularityPool { 46 | // it should revert 47 | vm.startPrank(adminAddr); 48 | 49 | tolp.requestSglPoolRescue(ybAssetIdToftSglEthMarket); 50 | vm.expectRevert(RescueCooldownNotReached.selector); 51 | tolp.activateSGLPoolRescue(IERC20(address(toftSglEthMarket))); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_activateSGLPoolRescue.tree: -------------------------------------------------------------------------------- 1 | TOLP_activateSGLPoolRescue 2 | ├── when sgl assetId is 0 3 | │ └── it should revert 4 | ├── when sgl rescue is true 5 | │ └── it should revert 6 | ├── when sglRescueRequest is 0 7 | │ └── it should revert 8 | ├── when rescue cooldown not met 9 | │ └── it should revert 10 | └── it should set rescue to true -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_getDebtPenaltyAmount.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TolpBaseTest, IERC20, TapiocaOptionLiquidityProvision} from "./TolpBaseTest.sol"; 5 | import {LockPosition} from "contracts/options/TapiocaOptionLiquidityProvision.sol"; 6 | import {Module as BBModule} from "tap-utils/interfaces/bar/IMarket.sol"; 7 | 8 | contract TOLP_getDebtPenaltyAmount is TolpBaseTest { 9 | uint256 constant TOLP_TOKEN_ID = 1; 10 | IERC20 SGL_ADDRESS; 11 | uint256 SGL_ASSET_ID; 12 | 13 | function setUp() public virtual override { 14 | super.setUp(); 15 | SGL_ADDRESS = IERC20(address(toftSglEthMarket)); 16 | SGL_ASSET_ID = ybAssetIdToftSglEthMarket; 17 | } 18 | 19 | // TODO use proper BB/SGL setup to simulate real values, tests are failing because of that 20 | function test_WhenUserIsLockedAndDoesNotHaveEnoughBBDebt(uint128 _weight, uint128 _lockDuration) 21 | external 22 | initAndCreateLock(aliceAddr, _weight, _lockDuration) 23 | { 24 | vm.skip(true); 25 | (_weight,) = _boundValues(_weight, _lockDuration); 26 | _repayDebt(aliceAddr, bigBangEthMarket._userBorrowPart(aliceAddr) / 2); 27 | vm.prank(adminAddr); 28 | // tolp.setMaxDebtBuffer(100000); 29 | (bool canLock,,) = 30 | tolp.canLockWithDebt(aliceAddr, SGL_ASSET_ID, tolp.userLockedUsdo(ybAssetIdToftSglEthMarket, aliceAddr)); 31 | assertEq(canLock, false, "TOLP_getDebtPenaltyAmount::test_WhenUserIsLockedAndDoesNotHaveEnoughBBDebt canLock"); 32 | // it should unlock earlier 33 | tolp.unlock(TOLP_TOKEN_ID, SGL_ADDRESS); 34 | // it should apply the penalty 35 | uint256 penalty = tolp.totalPenalties(SGL_ASSET_ID); 36 | assertGt(penalty, 0, "TOLP_getDebtPenaltyAmount::test_WhenUserIsLockedAndDoesNotHaveEnoughBBDebt penalty"); 37 | // it should allow admin to withdraw the penalty 38 | cluster.setRoleForContract(adminAddr, keccak256("HARVEST_TOLP"), true); 39 | tolp.harvestPenalties(adminAddr, penalty, SGL_ASSET_ID); 40 | assertEq( 41 | yieldBox.toAmount(SGL_ASSET_ID, yieldBox.balanceOf(adminAddr, SGL_ASSET_ID), false), 42 | penalty, 43 | "TOLP_getDebtPenaltyAmount::test_WhenUserIsLockedAndDoesNotHaveEnoughBBDebt penalty harvest" 44 | ); 45 | } 46 | 47 | function _repayDebt(address _user, uint256 _amount) internal { 48 | vm.startPrank(_user); 49 | // approvals 50 | usdoMock.approve(address(yieldBox), type(uint256).max); 51 | usdoMock.approve(address(pearlmit), type(uint256).max); 52 | yieldBox.setApprovalForAll(address(bigBangEthMarket), true); 53 | yieldBox.setApprovalForAll(address(pearlmit), true); 54 | pearlmit.approve( 55 | 1155, 56 | address(yieldBox), 57 | usdoMockTokenId, 58 | address(bigBangEthMarket), 59 | type(uint200).max, 60 | uint48(block.timestamp) 61 | ); 62 | 63 | // repay the debt 64 | deal(address(usdoMock), _user, _amount); 65 | uint256 share = yieldBox.toShare(usdoMockTokenId, _amount, false); 66 | yieldBox.depositAsset(usdoMockTokenId, _user, share); 67 | 68 | (BBModule[] memory modules, bytes[] memory calls) = marketHelper.repay(_user, _user, false, _amount); 69 | bigBangEthMarket.execute(modules, calls, true); 70 | vm.stopPrank(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_getDebtPenaltyAmount.tree: -------------------------------------------------------------------------------- 1 | TOLP_getDebtPenaltyAmount 2 | └── when user is locked and does not have enough BB debt 3 | ├── it should unlock earlier 4 | ├── it should apply the penalty 5 | └── it should allow admin to withdraw the penalty -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_getSingularityPools.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TolpBaseTest, SingularityPool} from "./TolpBaseTest.sol"; 5 | 6 | contract TOLP_getSingularityPools is TolpBaseTest { 7 | function test_ShouldReturnTheRightArrayOfPools() external registerSingularityPool { 8 | // it should return the right array of pools 9 | SingularityPool[] memory pools = tolp.getSingularityPools(); 10 | 11 | assertEq(pools.length, 5, "TOLP_getSingularityPools: Invalid pools length"); 12 | } 13 | 14 | function test_WhenThereIsAPoolInRescue() external registerSingularityPool setPoolRescue { 15 | // it should return the array without the rescue pool 16 | SingularityPool[] memory pools = tolp.getSingularityPools(); 17 | assertEq(pools[0].sglAssetID, 0, "TOLP_getSingularityPools: Invalid pools length in rescue mode"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_getSingularityPools.tree: -------------------------------------------------------------------------------- 1 | TOLP_getSingularityPools 2 | ├── it should return the right array of pools 3 | └── when there is a pool in rescue 4 | └── it should return the array without the rescue pool -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_lock.tree: -------------------------------------------------------------------------------- 1 | TOLP_lock 2 | ├── when paused paused 3 | │ └── it should revert 4 | └── when not paused 5 | ├── when duration is too short 6 | │ └── it should revert 7 | └── when duration is not too short 8 | ├── when duration is too long 9 | │ └── it should revert 10 | └── when duration is right 11 | ├── when shares equal to 0 12 | │ └── it should revert 13 | └── when shares bigger than 0 14 | ├── when sgl is in rescue mode 15 | │ └── it should revert 16 | └── when sgl not in rescue mode 17 | ├── when rescue cooldown activated 18 | │ └── it should revert 19 | └── when rescue cooldown not activated 20 | ├── when sgl not active 21 | │ └── it should revert 22 | └── when sgl is active 23 | ├── when Pearlmit transfer fails 24 | │ └── it should revert 25 | └── when Pearlmit transfer succeed 26 | ├── it should emit Mint event 27 | ├── it should mint a tOLP position 28 | ├── it should add shares to the sgl total deposited 29 | └── it should create a lock position with the right data -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_ownerActions.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TolpBaseTest, IERC20, ICluster} from "./TolpBaseTest.sol"; 5 | 6 | contract TOLP_ownerActions is TolpBaseTest { 7 | function test_WhenNotOwner() external { 8 | // it should revert on setCluster 9 | vm.expectRevert("Ownable: caller is not the owner"); 10 | tolp.setCluster(ICluster(address(0x1))); 11 | 12 | // it should revert on setPause 13 | vm.expectRevert(NotAuthorized.selector); 14 | tolp.setPause(true); 15 | 16 | // it should revert on setEmergencySweepCooldown 17 | vm.expectRevert("Ownable: caller is not the owner"); 18 | tolp.setEmergencySweepCooldown(1); 19 | 20 | // it should revert on emergencySweep 21 | vm.expectRevert("Ownable: caller is not the owner"); 22 | tolp.activateEmergencySweep(); 23 | 24 | // it should revert on activateEmergencySweep 25 | vm.expectRevert("Ownable: caller is not the owner"); 26 | tolp.activateEmergencySweep(); 27 | 28 | // it should revert on emergencySweep 29 | vm.expectRevert("Ownable: caller is not the owner"); 30 | tolp.emergencySweep(); 31 | } 32 | 33 | function test_WhenNoRightRole() external { 34 | // it should revert on emergencySweep 35 | vm.startPrank(adminAddr); 36 | 37 | tolp.setEmergencySweepCooldown(0); 38 | tolp.activateEmergencySweep(); 39 | vm.expectRevert(NotAuthorized.selector); 40 | tolp.emergencySweep(); 41 | } 42 | 43 | function test_WhenRightRole() external { 44 | vm.startPrank(adminAddr); 45 | 46 | // it should set the cluster 47 | uint256 snapshotId = vm.snapshot(); 48 | tolp.setCluster(ICluster(address(0x1))); 49 | vm.revertTo(snapshotId); 50 | 51 | // it should set the pause 52 | tolp.setPause(true); 53 | 54 | // it should set the emergency sweep cooldown 55 | tolp.setEmergencySweepCooldown(1); 56 | 57 | //it should revert on activateEmergencySweep 58 | tolp.activateEmergencySweep(); 59 | 60 | // it should set the emergency sweep 61 | vm.warp(block.timestamp + 1); 62 | tolp.cluster().setRoleForContract(adminAddr, keccak256("TOLP_EMERGENCY_SWEEP"), true); 63 | tolp.emergencySweep(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_ownerActions.tree: -------------------------------------------------------------------------------- 1 | TOLP_ownerActions 2 | ├── when not owner 3 | │ ├── it should revert on setCluster 4 | │ ├── it should revert on setPause 5 | │ ├── it should revert on setEmergencySweepCooldown 6 | │ ├── it should revert on activateEmergencySweep 7 | │ └── it should revert on emergencySweep 8 | ├── when no right role 9 | │ └── it should revert on emergencySweep 10 | └── when right role 11 | ├── it should set the cluster 12 | ├── it should set the pause 13 | ├── it should set the emergency sweep cooldown 14 | ├── it should revert on activateEmergencySweep 15 | └── it should set the emergency sweep -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_registerSingularity.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TolpBaseTest, IERC20} from "./TolpBaseTest.sol"; 5 | 6 | contract TOLP_registerSingularity is TolpBaseTest { 7 | function test_RevertWhen_NotOwner() external { 8 | // it should revert 9 | vm.expectRevert("Ownable: caller is not the owner"); 10 | tolp.registerSingularity(IERC20(address(toftSglEthMarket)), ybAssetIdToftSglEthMarket, 0); 11 | } 12 | 13 | function test_RevertWhen_AssetIdNotValid() external { 14 | // it should revert 15 | vm.startPrank(adminAddr); 16 | 17 | vm.expectRevert(AssetIdNotValid.selector); 18 | tolp.registerSingularity(IERC20(address(toftSglEthMarket)), 0, 0); 19 | } 20 | 21 | function test_RevertWhen_AssetIdAlreadyRegistered() external registerSingularityPool { 22 | // it should revert 23 | vm.startPrank(adminAddr); 24 | 25 | vm.expectRevert(DuplicateAssetId.selector); 26 | tolp.registerSingularity(IERC20(address(toftSglEthMarket)), ybAssetIdToftSglEthMarket, 0); 27 | } 28 | 29 | function test_RevertWhen_SglIsAlreadyRegistered() external registerSingularityPool { 30 | // it should revert 31 | vm.startPrank(adminAddr); 32 | 33 | vm.expectRevert(AlreadyRegistered.selector); 34 | tolp.registerSingularity(IERC20(address(toftSglEthMarket)), 10, 0); 35 | } 36 | 37 | function test_ShouldRegisterTheSingularity() external registerSingularityPool { 38 | // it should register the singularity 39 | vm.startPrank(adminAddr); 40 | 41 | tolp.registerSingularity(IERC20(address(0x6)), 6, 0); 42 | // update the activeSingularities 43 | (uint256 assetId,,,) = tolp.activeSingularities(IERC20(address(0x6))); 44 | assertEq(assetId, 6, "TOLP_registerSingularity::test_ShouldRegisterTheSingularity: Invalid assetId"); 45 | // register sglAssetIDToAddress 46 | assertEq( 47 | address(tolp.sglAssetIDToAddress(6)), 48 | address(0x6), 49 | "TOLP_registerSingularity::test_ShouldRegisterTheSingularity: Invalid sglAssetToAddress" 50 | ); 51 | // updateTotalSGLPoolWeights 52 | assertEq( 53 | tolp.totalSingularityPoolWeights(), 54 | 6, 55 | "TOLP_registerSingularity::test_ShouldRegisterTheSingularity: Invalid total weight" 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_registerSingularity.tree: -------------------------------------------------------------------------------- 1 | TOLP_registerSingularity 2 | ├── when not owner 3 | │ └── it should revert 4 | ├── when assetId not valid 5 | │ └── it should revert 6 | ├── when assetId already registered 7 | │ └── it should revert 8 | ├── when sgl is already registered 9 | │ └── it should revert 10 | └── it should register the singularity 11 | ├── update the activeSingularities 12 | ├── register sglAssetIDToAddress 13 | └── updateTotalSGLPoolWeights -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_requestSglPoolRescue.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TolpBaseTest, IERC20} from "./TolpBaseTest.sol"; 5 | 6 | contract TOLP_requestSglPoolRescue is TolpBaseTest { 7 | function test_ShouldRequestTheSglPoolToRescueWithTheBlockTimestamp() external registerSingularityPool { 8 | // it should request the sgl pool to rescue with the block timestamp 9 | vm.startPrank(adminAddr); 10 | 11 | tolp.requestSglPoolRescue(1); 12 | assertEq(tolp.sglRescueRequest(1), block.timestamp, "TOLP_requestSglPoolRescue: Invalid rescue request"); 13 | } 14 | 15 | function test_RevertWhen_SglAssetIdIs0() external { 16 | // it should revert 17 | vm.startPrank(adminAddr); 18 | vm.expectRevert(NotRegistered.selector); 19 | tolp.requestSglPoolRescue(0); 20 | } 21 | 22 | function test_RevertWhen_SglRescueIsAlreadyActivated() external registerSingularityPool { 23 | // it should revert 24 | vm.startPrank(adminAddr); 25 | tolp.requestSglPoolRescue(1); 26 | vm.expectRevert(AlreadyActive.selector); 27 | tolp.requestSglPoolRescue(1); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_requestSglPoolRescue.tree: -------------------------------------------------------------------------------- 1 | TOLP_requestSglPoolRescue 2 | ├── when sgl asset id is 0 3 | │ └── it should revert 4 | ├── when sgl rescue is already activated 5 | │ └── it should revert 6 | └── it should request the sgl pool to rescue with the block timestamp -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_setSGLPoolWeight.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TolpBaseTest, IERC20} from "./TolpBaseTest.sol"; 5 | 6 | contract TOLP_setSGLPoolWeight is TolpBaseTest { 7 | function test_RevertWhen_AssetIdIs0() external { 8 | // it should revert 9 | vm.startPrank(adminAddr); 10 | vm.expectRevert(NotRegistered.selector); 11 | tolp.setSGLPoolWeight(IERC20(address(toftSglEthMarket)), ybAssetIdToftSglEthMarket); 12 | } 13 | 14 | function test_ShouldSetTheWeightOfThePool() external registerSingularityPool { 15 | // it should set the weight of the pool 16 | vm.startPrank(adminAddr); 17 | tolp.setSGLPoolWeight(IERC20(address(toftSglEthMarket)), 3); 18 | 19 | (,, uint256 poolWeight,) = tolp.activeSingularities(IERC20(address(toftSglEthMarket))); 20 | assertEq(poolWeight, 3, "TOLP_setSGLPoolWeight: Invalid weight"); 21 | // and also update the total weights 22 | assertEq(tolp.totalSingularityPoolWeights(), 7, "TOLP_setSGLPoolWeight: Invalid total weight"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_setSGLPoolWeight.tree: -------------------------------------------------------------------------------- 1 | TOLP_setSGLPoolWeight 2 | ├── when asset id is 0 3 | │ └── it should revert 4 | └── it should set the weight of the pool 5 | └── and also update the total weights -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_unlock.tree: -------------------------------------------------------------------------------- 1 | TOLP_unlock 2 | ├── when paused 3 | │ └── it should revert 4 | └── when not paused 5 | ├── when position is expired 6 | │ └── it should revert 7 | └── when position is not expired 8 | ├── when tob is holder of the token 9 | │ └── it should revert 10 | └── when user is holder of the token 11 | ├── when lock is not expired 12 | │ ├── when sgl is not in rescue 13 | │ │ └── it should revert 14 | │ └── when sgl is in rescue 15 | │ └── it should continue 16 | └── when lock is expired 17 | └── when continuing 18 | ├── when sgl asset id doesnt match 19 | │ └── it should revert 20 | └── when sgl asset id matches 21 | ├── it should emit Burn 22 | ├── it should burn the token 23 | ├── it should delete the lock position 24 | ├── it should transfer the yieldbox sgl shares 25 | └── it should decrement total deposited -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_unregisterSingularity.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TolpBaseTest, IERC20} from "./TolpBaseTest.sol"; 5 | 6 | contract TOLP_unregisterSingularity is TolpBaseTest { 7 | function test_RevertWhen_NotOwner() external { 8 | // it should revert 9 | vm.expectRevert("Ownable: caller is not the owner"); 10 | tolp.unregisterSingularity(IERC20(address(toftSglEthMarket))); 11 | } 12 | 13 | function test_RevertWhen_AssetId0() external { 14 | // it should revert 15 | vm.startPrank(adminAddr); 16 | 17 | vm.expectRevert(NotRegistered.selector); 18 | tolp.unregisterSingularity(IERC20(address(toftSglEthMarket))); 19 | } 20 | 21 | function test_RevertWhen_NotInRescue() external registerSingularityPool { 22 | // it should revert 23 | vm.startPrank(adminAddr); 24 | 25 | vm.expectRevert(NotInRescueMode.selector); 26 | tolp.unregisterSingularity(IERC20(address(toftSglEthMarket))); 27 | } 28 | 29 | function test_ShouldUnregisterTheSingularity() 30 | external 31 | registerSingularityPool 32 | setSglInRescue(IERC20(address(toftSglEthMarket)), ybAssetIdToftSglEthMarket) 33 | { 34 | // it should unregister the singularity 35 | vm.startPrank(adminAddr); 36 | 37 | tolp.unregisterSingularity(IERC20(address(toftSglEthMarket))); 38 | // delete the activeSingularities 39 | (uint256 assetId,,,) = tolp.activeSingularities(IERC20(address(toftSglEthMarket))); 40 | assertEq(assetId, 0, "TOLP_unregisterSingularity: Invalid assetId"); 41 | // delete sglAssetIDToAddress 42 | assertEq( 43 | address(tolp.sglAssetIDToAddress(ybAssetIdToftSglEthMarket)), 44 | address(0), 45 | "TOLP_unregisterSingularity: Invalid sglAssetToAddress" 46 | ); 47 | // delete sglRescueRequest 48 | assertEq( 49 | tolp.sglRescueRequest(ybAssetIdToftSglEthMarket), 0, "TOLP_unregisterSingularity: Invalid sglRescueRequest" 50 | ); 51 | // delete singularities array 52 | assertEq(tolp.getSingularities().length, 4, "TOLP_unregisterSingularity: Invalid singularities array"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/unit/options/TapiocaOptionLiquidityProvision/TOLP_unregisterSingularity.tree: -------------------------------------------------------------------------------- 1 | TOLP_unregisterSingularity 2 | ├── when not owner 3 | │ └── it should revert 4 | ├── when assetId 0 5 | │ └── it should revert 6 | ├── when not in rescue 7 | │ └── it should revert 8 | └── it should unregister the singularity 9 | ├── delete the activeSingularities 10 | ├── delete sglAssetIDToAddress 11 | ├── delete sglRescueRequest 12 | └── delete singularities array -------------------------------------------------------------------------------- /test/unit/options/twL/twl_capCumulativeReward.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {TWAML} from "contracts/options/twAML.sol"; 5 | 6 | import "forge-std/Test.sol"; 7 | 8 | contract twl_CapCumulativeReward is TWAML, Test { 9 | uint256 constant TOB_MULTIPLIER = 5 * 1e4; 10 | uint256 constant TOB_CAP = 2 * 1e4; 11 | uint256 constant MIN_TOB_AMOUNT = 1e4; 12 | uint256 constant MAX_TOB_AMOUNT = 50 * 1e4; 13 | 14 | uint256 constant TWTAP_MULTIPLIER = 10 * 1e4; 15 | uint256 constant TWTAP_CAP = 5 * 1e4; 16 | uint256 constant MIN_TWTAP_AMOUNT = 1e4; 17 | uint256 constant MAX_TWTAP_AMOUNT = 100 * 1e4; 18 | 19 | /** 20 | * @dev It should cap the cumulative reward to the nearest multiplier of 5. 21 | */ 22 | function test_shouldCapCumulativeRewardOnTob(uint256 _amount) external { 23 | _amount = bound(_amount, MIN_TOB_AMOUNT, MAX_TOB_AMOUNT); 24 | 25 | // it should cap the cumulative reward 26 | assertEq( 27 | capCumulativeReward(_amount, TOB_MULTIPLIER, TOB_CAP) % TOB_MULTIPLIER, 28 | 0, 29 | "twl_CapCumulativeReward::test_shouldCapCumulativeRewardOnTob: Invalid amount" 30 | ); 31 | } 32 | 33 | /** 34 | * @dev It should cap the cumulative reward to the nearest multiplier of 10. 35 | */ 36 | function test_shouldCapCumulativeRewardOnTwTap(uint256 _amount) external { 37 | _amount = bound(_amount, MIN_TWTAP_AMOUNT, MAX_TWTAP_AMOUNT); 38 | 39 | // it should cap the cumulative reward 40 | assertEq( 41 | capCumulativeReward(_amount, TWTAP_MULTIPLIER, TWTAP_CAP) % TWTAP_MULTIPLIER, 42 | 0, 43 | "twl_CapCumulativeReward::test_shouldCapCumulativeRewardOnTwTap: Invalid amount" 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_advanceWeek.tree: -------------------------------------------------------------------------------- 1 | twTap_advanceWeek 2 | ├── when caller does not have role 3 | │ └── it should revert 4 | └── when caller has role 5 | ├── when time did not advance enough to advance week 6 | │ └── it should do nothing 7 | └── when time advanced enough 8 | ├── it should emit AdvanceEpoch 9 | ├── it should pass week net active votes 10 | ├── it should update lastProcessedWeek 11 | ├── when decay rate is not set 12 | │ └── it should do nothing 13 | └── when decay rate is bigger than 0 14 | ├── when epoch smaller than 2 15 | │ └── it should revert 16 | └── when epoch bigger or equal 2 17 | ├── when liquidity decreased 18 | │ ├── when liquidity decreased more than the decay activation 19 | │ │ └── it should decay 20 | │ └── when liquidity did not decreased more than he decay activation 21 | │ └── it should not decay 22 | └── when liquidity did not decrease 23 | └── it should not decay -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_batchClaimRewards.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {twTapBaseTest, TwTAP} from "test/unit/options/twTap/twTapBaseTest.sol"; 5 | 6 | contract twTap_batchClaimRewards is twTapBaseTest { 7 | function test_RevertWhen_Paused() external participate(100,1) skipWeeks(1) advanceWeeks(1) distributeRewards { 8 | // it should revert 9 | vm.prank(adminAddr); 10 | twTap.setPause(true); 11 | 12 | vm.expectRevert("Pausable: paused"); 13 | uint256[] memory tokenIds = new uint256[](2); 14 | tokenIds[0] = 1; 15 | tokenIds[1] = 2; 16 | twTap.batchClaimRewards(tokenIds); 17 | } 18 | 19 | function test_ShouldReturnTheClaimableRewards() 20 | external 21 | participate(100, 1) 22 | participate(100, 1) 23 | skipWeeks(1) 24 | advanceWeeks(1) 25 | distributeRewards 26 | { 27 | // it should return the claimable rewards 28 | vm.startPrank(aliceAddr); 29 | uint256[] memory tokenIds = new uint256[](2); 30 | tokenIds[0] = 1; 31 | tokenIds[1] = 2; 32 | twTap.batchClaimRewards(tokenIds); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_batchClaimRewards.tree: -------------------------------------------------------------------------------- 1 | twTap_batchClaimRewards 2 | ├── when paused 3 | │ └── it should revert 4 | └── it should return the claimable rewards -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_claimRewards.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {twTapBaseTest, TwTAP} from "test/unit/options/twTap/twTapBaseTest.sol"; 5 | 6 | contract twTap_claimRewards is twTapBaseTest { 7 | function test_RevertWhen_Paused() external { 8 | // it should revert 9 | vm.prank(adminAddr); 10 | twTap.setPause(true); 11 | 12 | vm.expectRevert("Pausable: paused"); 13 | twTap.claimRewards(1); 14 | } 15 | 16 | function test_ShouldReturnTheClaimableRewards() 17 | external 18 | participate(100, 1) 19 | skipWeeks(1) 20 | advanceWeeks(1) 21 | distributeRewards 22 | { 23 | // it should return the claimable rewards 24 | vm.startPrank(aliceAddr); 25 | twTap.claimRewards(1); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_claimRewards.tree: -------------------------------------------------------------------------------- 1 | twTap_claimRewards 2 | ├── when paused 3 | │ └── it should revert 4 | └── it should return the claimable rewards -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_distributeReward.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {twTapBaseTest, TwTAP} from "test/unit/options/twTap/twTapBaseTest.sol"; 5 | 6 | contract twTap_distributeReward is twTapBaseTest { 7 | function test_RevertWhen_WeekNotAdvanced() external skipWeeks(1) { 8 | // it should revert 9 | vm.expectRevert(TwTAP.AdvanceWeekFirst.selector); 10 | twTap.distributeReward(1, 1e18); 11 | } 12 | 13 | function test_RevertWhen_AmountIsZero() external skipWeeks(1) advanceWeeks(1) { 14 | // it should revert 15 | vm.expectRevert(TwTAP.NotValid.selector); 16 | twTap.distributeReward(1, 0); 17 | } 18 | 19 | function test_RevertWhen_RewardTokenIsZero() external skipWeeks(1) advanceWeeks(1) { 20 | // it should revert 21 | vm.expectRevert(TwTAP.NotValid.selector); 22 | twTap.distributeReward(0, 1e18); 23 | } 24 | 25 | function test_ShouldDistributeTheReward() 26 | external 27 | addRewardTokens 28 | participate(100, 1) 29 | skipWeeks(1) 30 | advanceWeeks(1) 31 | { 32 | // it should distribute the reward 33 | vm.startPrank(adminAddr); 34 | daiMock.mintTo(adminAddr, 1e18); 35 | daiMock.approve(address(twTap), type(uint256).max); 36 | 37 | vm.expectEmit(true, true, true, true); 38 | emit TwTAP.DistributeReward(address(daiMock), adminAddr, 1e18, 1); 39 | twTap.distributeReward(1, 1e18); 40 | 41 | assertEq( 42 | daiMock.balanceOf(address(twTap)), 43 | 1e18, 44 | "twTap_distributeReward::test_ShouldDistributeTheReward: Invalid balance" 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_distributeReward.tree: -------------------------------------------------------------------------------- 1 | twTap_distributeReward 2 | ├── when week not advanced 3 | │ └── it should revert 4 | ├── when amount is zero 5 | │ └── it should revert 6 | ├── when reward token is zero 7 | │ └── it should revert 8 | └── it should distribute the reward -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_emergencySweep.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {twTapBaseTest, TwTAP} from "test/unit/options/twTap/twTapBaseTest.sol"; 5 | 6 | contract twTap_emergencySweep is twTapBaseTest { 7 | function test_RevertWhen_EmergencyCooldownNotReached() external { 8 | // it should revert 9 | vm.startPrank(adminAddr); 10 | vm.expectRevert(TwTAP.EmergencySweepCooldownNotReached.selector); 11 | twTap.emergencySweep(); 12 | } 13 | 14 | function test_RevertWhen_NotOwner() external { 15 | // it should revert 16 | vm.startPrank(adminAddr); 17 | twTap.setEmergencySweepCooldown(0); 18 | twTap.activateEmergencySweep(); 19 | vm.stopPrank(); 20 | vm.expectRevert("Ownable: caller is not the owner"); 21 | twTap.emergencySweep(); 22 | } 23 | 24 | function test_ShouldSweepTheLocks() external participate(1e20, 1) skipWeeks(1) advanceWeeks(1) distributeRewards { 25 | // it should sweep the locks 26 | vm.startPrank(adminAddr); 27 | twTap.setEmergencySweepCooldown(0); 28 | twTap.activateEmergencySweep(); 29 | twTap.emergencySweep(); 30 | 31 | // Test lock sweep 32 | assertEq( 33 | twTap.lastEmergencySweep(), 34 | 0, 35 | "twTap_emergencySweep::test_ShouldSweepTheLocks: Invalid last emergency sweep" 36 | ); 37 | assertEq(tapOFT.balanceOf(adminAddr), 1e20, "twTap_emergencySweep::test_ShouldSweepTheLocks: Invalid balance"); 38 | 39 | // Test rewards sweep 40 | 41 | assertEq( 42 | daiMock.balanceOf(adminAddr), 1e25, "twTap_emergencySweepRewards::test_ShouldSweepTheLocks: Invalid balance" 43 | ); 44 | assertEq( 45 | usdcMock.balanceOf(adminAddr), 46 | 1e13, 47 | "twTap_emergencySweepRewards::test_ShouldSweepTheLocks: Invalid balance" 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_emergencySweep.tree: -------------------------------------------------------------------------------- 1 | twTap_emergencySweepLocks 2 | ├── when emergency cooldown not reached 3 | │ └── it should revert 4 | ├── when not owner 5 | │ └── it should revert 6 | └── it should sweep the locks -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_exitPosition.tree: -------------------------------------------------------------------------------- 1 | TWTAP_exitPosition 2 | ├── when paused 3 | │ └── it should revert 4 | └── when not paused 5 | ├── when lock not expired 6 | │ ├── when not in rescue mode 7 | │ │ └── it should revert 8 | │ └── when in rescue mode 9 | │ └── it should continue 10 | └── when lock expired 11 | ├── when tap released 12 | │ └── it should stop execution and return 0 13 | └── when tap was not released 14 | ├── when user has no voting power 15 | │ ├── it should not change AML 16 | │ └── it should continue 17 | ├── when user has voting power 18 | │ ├── it should update the AML with the inverse recorded 19 | │ └── it should continue 20 | └── when it should continue 21 | ├── it should emit ExitPosition 22 | ├── it should mark the participant tap as released 23 | └── it should transfer the Tap tokens to the owner of the lock -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_ownerActions.tree: -------------------------------------------------------------------------------- 1 | twTap_ownerActions 2 | ├── when advancingWeek and not owner 3 | │ └── it should revert 4 | ├── when set rescue mode and not owner 5 | │ └── it should revert 6 | ├── when SetVirtualTotalAmount and not owner 7 | │ └── it should revert 8 | ├── when setMinWeightFactor and not owner 9 | │ └── it should revert 10 | ├── when setMaxRewardTokensLength and not owner 11 | │ └── it should revert 12 | ├── when addRewardToken and not owner 13 | │ └── it should revert 14 | ├── when setCluster and not owner 15 | │ └── it should revert 16 | ├── when setPause and not owner 17 | │ └── it should revert 18 | ├── when setEmergencySweepCooldown and not owner 19 | │ └── it should revert 20 | └── when activateEmergencySweep and not owner 21 | └── it should revert -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_participate.tree: -------------------------------------------------------------------------------- 1 | TWTAP_participate 2 | ├── when paused 3 | │ └── it should revert 4 | └── when not paused 5 | ├── when rescue mode is active 6 | │ └── it should revert 7 | └── when rescue mode is not active 8 | ├── when emergency sweep active 9 | │ └── it should revert 10 | └── when emergency sweep not active 11 | ├── when lock duration is less than a week 12 | │ └── it should revert 13 | └── when lock duration is more than a week 14 | ├── when lock duration is more than max duration 15 | │ └── it should revert 16 | └── when lock duration is less than max duration 17 | ├── when lock duration is not a multiple of epoch duration 18 | │ └── it should revert 19 | └── when lock duration is a multiple of epoch duration 20 | ├── when week was not advanced 21 | │ └── it should revert 22 | └── when week was advanced 23 | ├── when pearlmit transfer fails 24 | │ └── it should revert 25 | └── when pearlmit transfer succeed 26 | ├── when minReward is not met 27 | │ └── it should revert 28 | └── when minReward is met 29 | ├── when locker does not have voting power 30 | │ └── it should participate without changing AML 31 | ├── when lock has voting power 32 | │ └── it should participate and change AML 33 | └── when it should participate 34 | ├── it should emit Participate 35 | ├── it should update AML if hasVotingPower is true 36 | ├── it should create a participation entry 37 | ├── it should update weekTotals 38 | └── it should mint a twTAP token -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_refreshTotalDeposited.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.22; 3 | 4 | import {twTapBaseTest} from "test/unit/options/twTap/twTapBaseTest.sol"; 5 | 6 | contract twTap_refreshTotalDeposited is twTapBaseTest { 7 | uint256 public PARTICIPATE_AMOUNT; 8 | uint256 constant PARTICIPATE_WEEKS = 4; 9 | 10 | function setUp() public virtual override { 11 | super.setUp(); 12 | PARTICIPATE_AMOUNT = twTap.VIRTUAL_TOTAL_AMOUNT(); 13 | } 14 | 15 | modifier whenParamArrayIsSet() { 16 | _participateUser(aliceAddr); 17 | _; 18 | } 19 | 20 | function _participateUser(address _user) internal { 21 | (uint256 _lockAmount, uint256 _lockDuration) = _boundValues(PARTICIPATE_AMOUNT, PARTICIPATE_WEEKS); 22 | _participate(_user, _lockAmount, _lockDuration); 23 | } 24 | 25 | function test_WhenRefreshCooldownIsNotMet() external whenParamArrayIsSet { 26 | skip(twTap.refreshCooldown() + 1); 27 | // it should return the previously set value 28 | uint256 returnVal = twTap.refreshTotalDeposited(); 29 | 30 | assertEq( 31 | twTap.lastTotalDeposited(), 32 | PARTICIPATE_AMOUNT, 33 | "twTap_refreshTotalDeposited::test_WhenRefreshCooldownIsNotMet: Invalid lastTotalDeposited" 34 | ); 35 | assertEq( 36 | twTap.lastTotalDepositRefresh(), 37 | block.timestamp, 38 | "twTap_refreshTotalDeposited::test_WhenRefreshCooldownIsNotMet: Invalid lastTotalDepositRefresh" 39 | ); 40 | } 41 | 42 | function test_WhenRefreshCooldownIsMet() external whenParamArrayIsSet { 43 | skip(twTap.refreshCooldown() + 1); 44 | 45 | // Setup previous value 46 | uint256 returnVal = twTap.refreshTotalDeposited(); 47 | assertEq( 48 | twTap.lastTotalDeposited(), 49 | PARTICIPATE_AMOUNT, 50 | "twTap_refreshTotalDeposited::test_WhenRefreshCooldownIsMet: Invalid lastTotalDeposited" 51 | ); 52 | assertEq( 53 | twTap.lastTotalDepositRefresh(), 54 | block.timestamp, 55 | "twTap_refreshTotalDeposited::test_WhenRefreshCooldownIsMet: Invalid lastTotalDepositRefresh" 56 | ); 57 | 58 | // Update values to new value 59 | skip(twTap.EPOCH_DURATION() / 2); // Arbitrary value to simulate time passing 60 | _participateUser(bobAddr); 61 | skip(twTap.refreshCooldown() + 1); 62 | returnVal = twTap.refreshTotalDeposited(); 63 | 64 | // it should update lastTotalDeposited with the newly fetch value 65 | assertEq( 66 | twTap.lastTotalDeposited(), 67 | PARTICIPATE_AMOUNT * 2, 68 | "twTap_refreshTotalDeposited::test_WhenRefreshCooldownIsMet: Invalid lastTotalDeposited" 69 | ); 70 | 71 | // it should update lastTotalDepositRefresh to block.timestamp 72 | assertEq( 73 | twTap.lastTotalDepositRefresh(), 74 | block.timestamp, 75 | "twTap_refreshTotalDeposited::test_WhenRefreshCooldownIsMet: Invalid lastTotalDepositRefresh" 76 | ); 77 | 78 | // it should return the new value of lastTotalDeposited 79 | assertEq( 80 | returnVal, 81 | PARTICIPATE_AMOUNT * 2, 82 | "twTap_refreshTotalDeposited::test_WhenRefreshCooldownIsMet: Invalid returnVal" 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /test/unit/options/twTap/twTap_refreshTotalDeposited.tree: -------------------------------------------------------------------------------- 1 | twTap_refreshTotalDeposited 2 | └── when param array is set 3 | ├── when refresh cooldown is not met 4 | │ └── it should return the previously set value 5 | └── when refresh cooldown is met 6 | ├── it should update lastTotalDeposited with the newly fetch value 7 | ├── it should update lastTotalDepositRefresh to block.timestamp 8 | └── it should return the new value of lastTotalDeposited -------------------------------------------------------------------------------- /test_hardhat/twTAP/fixtures.ts: -------------------------------------------------------------------------------- 1 | import { time } from '@nomicfoundation/hardhat-network-helpers'; 2 | import hre, { ethers } from 'hardhat'; 3 | import ERC20MockArtifact from 'tapioca-sdk/dist/artifacts/tapioca-mocks/ERC20Mock.json'; 4 | import { ERC20Mock__factory } from 'tapioca-sdk/dist/typechain/tapioca-mocks'; 5 | import { BN } from '../test.utils'; 6 | 7 | export const setupTwTAPFixture = async () => { 8 | const signer = (await hre.ethers.getSigners())[0]; 9 | const users = (await hre.ethers.getSigners()).splice(1); 10 | 11 | // Tap OFT 12 | const one = BN(1e18); 13 | const hundredMil = one.mul(100_000_000); 14 | const tapOFT = await ( 15 | await ethers.getContractFactory('ERC20Mock') 16 | ).deploy('TapOFT', 'TapOFT'); 17 | 18 | await tapOFT.mint(signer.address, hundredMil); 19 | 20 | // Mock tokens 21 | const mock0 = await ( 22 | (await ethers.getContractFactoryFromArtifact( 23 | ERC20MockArtifact, 24 | )) as ERC20Mock__factory 25 | ).deploy('Mock Zero', 'MOCK0', hundredMil, 18, signer.address); 26 | const mock1 = await ( 27 | (await ethers.getContractFactoryFromArtifact( 28 | ERC20MockArtifact, 29 | )) as ERC20Mock__factory 30 | ).deploy('Mock One', 'MOCK1', hundredMil, 18, signer.address); 31 | const mock2 = await ( 32 | (await ethers.getContractFactoryFromArtifact( 33 | ERC20MockArtifact, 34 | )) as ERC20Mock__factory 35 | ).deploy('Mock Two', 'MOCK2', hundredMil, 18, signer.address); 36 | 37 | // Mock token distribution 38 | const tokens = [mock0, mock1, mock2]; 39 | for (const tok of tokens) { 40 | await tok.freeMint(one.mul(1000)); 41 | for (const acc of users) { 42 | await tok.connect(acc).freeMint(one.mul(1000)); 43 | await time.increase(86400); 44 | } 45 | } 46 | 47 | const tapAmount = one.mul(1000); 48 | 49 | // TAP distribution. (TODO: Why is the delay necessary?) 50 | for (const acc of users) { 51 | await tapOFT.connect(acc).freeMint(tapAmount); 52 | await time.increase(86400); 53 | } 54 | 55 | // twtap 56 | const twtap = await ( 57 | await ethers.getContractFactory('TwTAP') 58 | ).deploy(tapOFT.address, signer.address); 59 | 60 | // Approvals and reward token setup 61 | for (const tok of tokens) { 62 | await twtap.addRewardToken(tok.address); 63 | } 64 | for (const acc of users) { 65 | await tapOFT.connect(acc).approve(twtap.address, tapAmount); 66 | } 67 | 68 | return { 69 | // signers 70 | signer, 71 | users, 72 | // vars 73 | tapOFT, 74 | twtap, 75 | tokens, 76 | }; 77 | }; 78 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "ts-node": { 3 | "swc": true 4 | }, 5 | "compilerOptions": { 6 | "target": "es2020", 7 | "module": "commonjs", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "outDir": "dist", 11 | "declaration": true, 12 | "resolveJsonModule": true, 13 | "skipLibCheck": true, 14 | "baseUrl": ".", 15 | "paths": { 16 | "@tapioca-sdk/*": ["gitmodule/tapioca-sdk/src/*"], 17 | "@typechain/*": ["gen/typechain/*"], 18 | "@tapioca-periph/config":["dep/tap-utils/tasks/deploy/DEPLOY_CONFIG.ts"], 19 | "@tapioca-bar/config":["dep/tapioca-bar/tasks/deploy/DEPLOY_CONFIG.ts"], 20 | "@tapiocaz/config":["dep/tapiocaz/tasks/deploy/DEPLOY_CONFIG.ts"], 21 | } 22 | }, 23 | "include": [ 24 | "./hardhat.config.ts", 25 | "./hardhat_scripts", 26 | "./test_hardhat", 27 | "./gen/typechain", 28 | "./tasks", 29 | "./deploy" 30 | ] 31 | } 32 | --------------------------------------------------------------------------------