@coti-io/coti-contracts 1.0.9 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/npm-publish.yml +18 -14
- package/README.md +3 -1
- package/contracts/disperse/coinByRatio/FixedRatioCoinDisperser.sol +452 -0
- package/contracts/disperse/coinByRatio/FixedRatioCoinDisperserLeftoverS1.sol +490 -0
- package/contracts/disperse/coinByRatio/FixedRatioCoinDisperserUnlimitedWindow.sol +432 -0
- package/contracts/disperse/disperseToken/MintDisperser.sol +120 -0
- package/contracts/disperse/disperseToken/TokenDisperser.sol +139 -0
- package/contracts/mocks/token/ERC20Mock.sol +19 -0
- package/contracts/mocks/token/PrivateERC20/EncryptedTokenReceiverMock.sol +18 -0
- package/contracts/mocks/token/PrivateERC20/PrivacyBridgeERC20Mock.sol +13 -0
- package/contracts/mocks/token/PrivateERC20/PrivateERC20AuditorSupplyMock.sol +44 -0
- package/contracts/mocks/token/PrivateERC20/PrivateERC20CappedMock.sol +23 -0
- package/contracts/mocks/token/PrivateERC20/PrivateERC20GtCallerMock.sol +29 -0
- package/contracts/mocks/token/PrivateERC20/PrivateERC20Mock.sol +9 -4
- package/contracts/mocks/token/PrivateERC20/PrivateERC20ReentrantReceiverMock.sol +39 -0
- package/contracts/mocks/token/PrivateERC20/PublicReentrantTokenReceiverMock.sol +29 -0
- package/contracts/mocks/token/PrivateERC20/PublicTokenReceiverBoolMock.sol +18 -0
- package/contracts/mocks/token/PrivateERC20/PublicTokenReceiverMock.sol +12 -0
- package/contracts/mocks/utils/mpc/Arithmetic128TestsContract.sol +123 -0
- package/contracts/mocks/utils/mpc/Arithmetic256TestsContract.sol +122 -0
- package/contracts/mocks/utils/mpc/Bitwise128TestsContract.sol +65 -0
- package/contracts/mocks/utils/mpc/Bitwise256TestsContract.sol +65 -0
- package/contracts/mocks/utils/mpc/CheckedArithmetic128WithOverflowBitTestsContract.sol +64 -0
- package/contracts/mocks/utils/mpc/CheckedArithmetic256WithOverflowBitTestsContract.sol +64 -0
- package/contracts/mocks/utils/mpc/Comparison128TestsContract.sol +98 -0
- package/contracts/mocks/utils/mpc/Comparison256TestsContract.sol +98 -0
- package/contracts/mocks/utils/mpc/MinMax128TestsContract.sol +44 -0
- package/contracts/mocks/utils/mpc/MinMax256TestsContract.sol +44 -0
- package/contracts/mocks/utils/mpc/MinimalImplementation.sol +55 -0
- package/contracts/mocks/utils/mpc/MinimalProxy.sol +27 -0
- package/contracts/mocks/utils/mpc/MpcOperations128TestContract.sol +267 -0
- package/contracts/mocks/utils/mpc/MpcOperationsTestContract.sol +334 -0
- package/contracts/mocks/utils/mpc/Mux128TestsContract.sol +24 -0
- package/contracts/mocks/utils/mpc/Mux256TestsContract.sol +24 -0
- package/contracts/mocks/utils/mpc/OnBoard128TestsContract.sol +93 -0
- package/contracts/mocks/utils/mpc/OnBoard256TestsContract.sol +116 -0
- package/contracts/mocks/utils/mpc/PrivacyImplementationV1.sol +157 -0
- package/contracts/mocks/utils/mpc/PrivacyImplementationV2.sol +133 -0
- package/contracts/mocks/utils/mpc/PrivacyProxy.sol +137 -0
- package/contracts/mocks/utils/mpc/Random128TestsContract.sol +32 -0
- package/contracts/mocks/utils/mpc/Random256TestsContract.sol +32 -0
- package/contracts/mocks/utils/mpc/Shift128TestsContract.sol +36 -0
- package/contracts/mocks/utils/mpc/Shift256TestsContract.sol +36 -0
- package/contracts/mocks/utils/mpc/Transfer128TestsContract.sol +29 -0
- package/contracts/mocks/utils/mpc/Transfer256TestsContract.sol +29 -0
- package/contracts/mocks/utils/mpc/TransferWithAllowance128TestsContract.sol +32 -0
- package/contracts/mocks/utils/mpc/TransferWithAllowance256TestsContract.sol +32 -0
- package/contracts/mocks/utils/mpc/ValidateCiphertext128TestsContract.sol +59 -0
- package/contracts/mocks/utils/mpc/ValidateCiphertext256TestsContract.sol +63 -0
- package/contracts/mocks/utils/mpc/ValidateCiphertextTestsContract.sol +99 -0
- package/contracts/mocks/wallet/PrivateERC20Wallet/PrivateERC20WalletMock.sol +7 -6
- package/contracts/node/CotiNodeRewards.sol +199 -0
- package/contracts/node/SoulboundNodeNFT.sol +519 -0
- package/contracts/privacyBridge/PrivacyBridge.sol +318 -0
- package/contracts/privacyBridge/PrivacyBridgeCotiNative.sol +268 -0
- package/contracts/privacyBridge/PrivacyBridgeERC20.sol +251 -0
- package/contracts/privacyBridge/PrivacyBridgeUSDCe.sol +16 -0
- package/contracts/privacyBridge/PrivacyBridgeUSDT.sol +17 -0
- package/contracts/privacyBridge/PrivacyBridgeWADA.sol +17 -0
- package/contracts/privacyBridge/PrivacyBridgeWBTC.sol +17 -0
- package/contracts/privacyBridge/PrivacyBridgeWETH.sol +17 -0
- package/contracts/privacyBridge/PrivacyBridgegCoti.sol +17 -0
- package/contracts/token/PrivateERC20/IPrivateERC20.sol +273 -40
- package/contracts/token/PrivateERC20/ITokenReceiver.sol +17 -0
- package/contracts/token/PrivateERC20/ITokenReceiverEncrypted.sol +20 -0
- package/contracts/token/PrivateERC20/PrivateERC20.sol +861 -152
- package/contracts/token/PrivateERC20/tokens/PrivateBridgedUSDC.sol +17 -0
- package/contracts/token/PrivateERC20/tokens/PrivateCOTI.sol +13 -0
- package/contracts/token/PrivateERC20/tokens/PrivateCOTITreasuryGovernanceToken.sol +17 -0
- package/contracts/token/PrivateERC20/tokens/PrivateTetherUSD.sol +17 -0
- package/contracts/token/PrivateERC20/tokens/PrivateWrappedADA.sol +17 -0
- package/contracts/token/PrivateERC20/tokens/PrivateWrappedBTC.sol +17 -0
- package/contracts/token/PrivateERC20/tokens/PrivateWrappedEther.sol +13 -0
- package/contracts/utils/mpc/MpcCore.sol +10891 -2449
- package/contracts/utils/mpc/MpcInterface.sol +7 -2
- package/hardhat/gasPriceBump.ts +60 -0
- package/hardhat.config.ts +60 -12
- package/package.json +21 -3
- package/scripts/deploySoulboundNodeNFT.ts +57 -0
- package/test/token/PrivateERC20/PrivacyBridge.fees.test.ts +327 -0
- package/test/token/PrivateERC20/PrivateERC20.test.ts +1109 -268
- package/test/utils/mpc/Bitwise128.test.ts +92 -0
- package/test/utils/mpc/Bitwise256.test.ts +101 -0
- package/test/utils/mpc/BuildInputText128.test.ts +398 -0
- package/test/utils/mpc/CheckedArithmetic128.test.ts +45 -0
- package/test/utils/mpc/CheckedArithmetic256.test.ts +45 -0
- package/test/utils/mpc/Comparison128.test.ts +48 -0
- package/test/utils/mpc/Comparison256.test.ts +48 -0
- package/test/utils/mpc/InvalidCiphertext.test.ts +179 -0
- package/test/utils/mpc/InvalidCiphertext128.test.ts +179 -0
- package/test/utils/mpc/InvalidCiphertext256.test.ts +201 -0
- package/test/utils/mpc/InvalidTransfer128.test.ts +166 -0
- package/test/utils/mpc/InvalidTransfer256.test.ts +158 -0
- package/test/utils/mpc/MinMax128.test.ts +44 -0
- package/test/utils/mpc/MinMax256.test.ts +44 -0
- package/test/utils/mpc/MinimalProxyDemo.test.ts +280 -0
- package/test/utils/mpc/MpcOperations.test.ts +589 -0
- package/test/utils/mpc/MpcOperations128.test.ts +632 -0
- package/test/utils/mpc/Mux128.test.ts +41 -0
- package/test/utils/mpc/Mux256.test.ts +41 -0
- package/test/utils/mpc/NegativeCases.test.ts +478 -0
- package/test/utils/mpc/NegativeCases128.test.ts +237 -0
- package/test/utils/mpc/NegativeCases256.test.ts +236 -0
- package/test/utils/mpc/OnBoard128.test.ts +90 -0
- package/test/utils/mpc/OnBoard256.test.ts +114 -0
- package/test/utils/mpc/Precompile128.test.ts +51 -0
- package/test/utils/mpc/Precompile256.test.ts +115 -0
- package/test/utils/mpc/ProxyValidation.test.ts +199 -0
- package/test/utils/mpc/Random128.test.ts +47 -0
- package/test/utils/mpc/Random256.test.ts +47 -0
- package/test/utils/mpc/Shift128.test.ts +41 -0
- package/test/utils/mpc/Shift256.test.ts +41 -0
- package/test/utils/mpc/Transfer128.test.ts +46 -0
- package/test/utils/mpc/Transfer256.test.ts +46 -0
- package/test/utils/mpc/TransferWithAllowance128.test.ts +48 -0
- package/test/utils/mpc/TransferWithAllowance256.test.ts +48 -0
- package/test/utils/mpc/UpgradeablePrivacyProxy.test.ts +307 -0
- package/test/utils/mpc/ValidateCiphertext.test.ts +221 -0
- package/test/utils/mpc/ValidateCiphertext256.test.ts +161 -0
- package/test/utils/mpc/ValidateCiphertext256Decryption.test.ts +383 -0
- package/test/utils/mpc/WalletEncryptionFailures.test.ts +494 -0
- package/test/utils/privateErc20Helpers.ts +97 -0
- package/typechain-types/@openzeppelin/contracts/access/Ownable.ts +153 -0
- package/typechain-types/@openzeppelin/contracts/access/index.ts +4 -0
- package/typechain-types/@openzeppelin/contracts/index.ts +2 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC20/IERC20.ts +262 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.ts +143 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC20/extensions/index.ts +4 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC20/index.ts +6 -0
- package/typechain-types/@openzeppelin/contracts/token/index.ts +2 -0
- package/typechain-types/contracts/disperse/coinByRatio/FixedRatioCoinDisperser.ts +679 -0
- package/typechain-types/contracts/disperse/coinByRatio/index.ts +4 -0
- package/typechain-types/contracts/disperse/disperseToken/MintDisperser.sol/IMintableERC20.ts +97 -0
- package/typechain-types/contracts/disperse/disperseToken/MintDisperser.sol/MintDisperser.ts +206 -0
- package/typechain-types/contracts/disperse/disperseToken/MintDisperser.sol/index.ts +5 -0
- package/typechain-types/contracts/disperse/disperseToken/TokenDisperser.ts +191 -0
- package/typechain-types/contracts/disperse/disperseToken/index.ts +6 -0
- package/typechain-types/contracts/disperse/index.ts +7 -0
- package/typechain-types/contracts/index.ts +2 -0
- package/typechain-types/contracts/mocks/token/PrivateERC20/PrivateERC20Mock.ts +77 -60
- package/typechain-types/contracts/mocks/utils/mpc/Arithmetic128BitTestsContract.ts +341 -0
- package/typechain-types/contracts/mocks/utils/mpc/Arithmetic128TestsContract.ts +311 -0
- package/typechain-types/contracts/mocks/utils/mpc/Arithmetic256BitTestsContract.ts +347 -0
- package/typechain-types/contracts/mocks/utils/mpc/Arithmetic256TestsContract.ts +311 -0
- package/typechain-types/contracts/mocks/utils/mpc/Bitwise128BitTestsContract.ts +186 -0
- package/typechain-types/contracts/mocks/utils/mpc/Bitwise128TestsContract.ts +179 -0
- package/typechain-types/contracts/mocks/utils/mpc/Bitwise256BitTestsContract.ts +186 -0
- package/typechain-types/contracts/mocks/utils/mpc/Bitwise256TestsContract.ts +179 -0
- package/typechain-types/contracts/mocks/utils/mpc/CheckedArithmetic128WithOverflowBitTestsContract.ts +206 -0
- package/typechain-types/contracts/mocks/utils/mpc/CheckedArithmetic256WithOverflowBitTestsContract.ts +206 -0
- package/typechain-types/contracts/mocks/utils/mpc/Comparison128BitTestsContract.ts +260 -0
- package/typechain-types/contracts/mocks/utils/mpc/Comparison128TestsContract.ts +278 -0
- package/typechain-types/contracts/mocks/utils/mpc/Comparison256BitTestsContract.ts +260 -0
- package/typechain-types/contracts/mocks/utils/mpc/Comparison256TestsContract.ts +278 -0
- package/typechain-types/contracts/mocks/utils/mpc/MinMax128TestsContract.ts +142 -0
- package/typechain-types/contracts/mocks/utils/mpc/MinMax256TestsContract.ts +142 -0
- package/typechain-types/contracts/mocks/utils/mpc/MinimalImplementation.ts +259 -0
- package/typechain-types/contracts/mocks/utils/mpc/MinimalProxy.ts +90 -0
- package/typechain-types/contracts/mocks/utils/mpc/Miscellaneous128BitTestsContract.ts +302 -0
- package/typechain-types/contracts/mocks/utils/mpc/Miscellaneous256BitTestsContract.ts +322 -0
- package/typechain-types/contracts/mocks/utils/mpc/MpcOperations128TestContract.ts +388 -0
- package/typechain-types/contracts/mocks/utils/mpc/MpcOperationsTestContract.ts +455 -0
- package/typechain-types/contracts/mocks/utils/mpc/Mux128TestsContract.ts +109 -0
- package/typechain-types/contracts/mocks/utils/mpc/Mux256TestsContract.ts +109 -0
- package/typechain-types/contracts/mocks/utils/mpc/OnBoard128TestsContract.ts +166 -0
- package/typechain-types/contracts/mocks/utils/mpc/OnBoard256TestsContract.ts +194 -0
- package/typechain-types/contracts/mocks/utils/mpc/PrivacyImplementationV1.ts +385 -0
- package/typechain-types/contracts/mocks/utils/mpc/PrivacyImplementationV2.ts +441 -0
- package/typechain-types/contracts/mocks/utils/mpc/PrivacyProxy.ts +201 -0
- package/typechain-types/contracts/mocks/utils/mpc/Random128TestsContract.ts +131 -0
- package/typechain-types/contracts/mocks/utils/mpc/Random256TestsContract.ts +131 -0
- package/typechain-types/contracts/mocks/utils/mpc/Shift128TestsContract.ts +142 -0
- package/typechain-types/contracts/mocks/utils/mpc/Shift256TestsContract.ts +142 -0
- package/typechain-types/contracts/mocks/utils/mpc/Transfer128TestsContract.ts +109 -0
- package/typechain-types/contracts/mocks/utils/mpc/Transfer256TestsContract.ts +109 -0
- package/typechain-types/contracts/mocks/utils/mpc/TransferWithAllowance128TestsContract.ts +128 -0
- package/typechain-types/contracts/mocks/utils/mpc/TransferWithAllowance256TestsContract.ts +128 -0
- package/typechain-types/contracts/mocks/utils/mpc/ValidateCiphertext128TestsContract.ts +198 -0
- package/typechain-types/contracts/mocks/utils/mpc/ValidateCiphertext256TestsContract.ts +182 -0
- package/typechain-types/contracts/mocks/utils/mpc/ValidateCiphertextTestsContract.ts +257 -0
- package/typechain-types/contracts/mocks/utils/mpc/index.ts +32 -0
- package/typechain-types/contracts/token/PrivateERC20/IPrivateERC20.ts +77 -60
- package/typechain-types/contracts/token/PrivateERC20/PrivateERC20.ts +77 -60
- package/typechain-types/contracts/utils/mpc/MpcInterface.sol/ExtendedOperations.ts +111 -10
- package/typechain-types/factories/@openzeppelin/contracts/access/Ownable__factory.ts +74 -0
- package/typechain-types/factories/@openzeppelin/contracts/access/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts/index.ts +1 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC20/IERC20__factory.ts +205 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit__factory.ts +100 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC20/extensions/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC20/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/index.ts +1 -0
- package/typechain-types/factories/contracts/disperse/coinByRatio/FixedRatioCoinDisperser__factory.ts +759 -0
- package/typechain-types/factories/contracts/disperse/coinByRatio/index.ts +4 -0
- package/typechain-types/factories/contracts/disperse/disperseToken/MintDisperser.sol/IMintableERC20__factory.ts +43 -0
- package/typechain-types/factories/contracts/disperse/disperseToken/MintDisperser.sol/MintDisperser__factory.ts +185 -0
- package/typechain-types/factories/contracts/disperse/disperseToken/MintDisperser.sol/index.ts +5 -0
- package/typechain-types/factories/contracts/disperse/disperseToken/TokenDisperser__factory.ts +198 -0
- package/typechain-types/factories/contracts/disperse/disperseToken/index.ts +5 -0
- package/typechain-types/factories/contracts/disperse/index.ts +5 -0
- package/typechain-types/factories/contracts/index.ts +1 -0
- package/typechain-types/factories/contracts/mocks/access/DataPrivacyFramework/DataPrivacyFrameworkMock__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PrivateERC20Mock__factory.ts +179 -47
- package/typechain-types/factories/contracts/mocks/utils/mpc/Arithmetic128BitTestsContract__factory.ts +349 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Arithmetic128TestsContract__factory.ts +330 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Arithmetic256BitTestsContract__factory.ts +364 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Arithmetic256TestsContract__factory.ts +330 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/ArithmeticTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/Bitwise128BitTestsContract__factory.ts +182 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Bitwise128TestsContract__factory.ts +184 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Bitwise256BitTestsContract__factory.ts +182 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Bitwise256TestsContract__factory.ts +184 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/BitwiseTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/CheckedArithmetic128WithOverflowBitTestsContract__factory.ts +203 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/CheckedArithmetic256WithOverflowBitTestsContract__factory.ts +203 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/CheckedArithmeticWIthOverflowBitTestsContract.sol/CheckedArithmeticWithOverflowBitTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison128BitTestsContract__factory.ts +255 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison128TestsContract__factory.ts +295 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison1TestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison256BitTestsContract__factory.ts +255 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison256TestsContract__factory.ts +295 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison2TestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/MinMax128TestsContract__factory.ts +147 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/MinMax256TestsContract__factory.ts +147 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/MinMaxTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/MinimalImplementation__factory.ts +263 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/MinimalProxy__factory.ts +104 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Miscellaneous128BitTestsContract__factory.ts +332 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Miscellaneous1TestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/Miscellaneous256BitTestsContract__factory.ts +380 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/MiscellaneousTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/MpcOperations128TestContract__factory.ts +723 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/MpcOperationsTestContract__factory.ts +1410 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Mux128TestsContract__factory.ts +115 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Mux256TestsContract__factory.ts +115 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/OffboardToUserKeyTestContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/OnBoard128TestsContract__factory.ts +175 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/OnBoard256TestsContract__factory.ts +205 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/PrivacyImplementationV1__factory.ts +521 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/PrivacyImplementationV2__factory.ts +648 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/PrivacyProxy__factory.ts +179 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Random128TestsContract__factory.ts +131 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Random256TestsContract__factory.ts +131 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Shift128TestsContract__factory.ts +147 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Shift256TestsContract__factory.ts +147 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/ShiftTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/StringTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/Transfer128TestsContract__factory.ts +135 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Transfer256TestsContract__factory.ts +135 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/TransferScalarTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/TransferTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance128TestsContract__factory.ts +154 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance256TestsContract__factory.ts +154 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance64_16TestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance64_32TestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance64_64TestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance64_8TestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowanceScalarTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowanceTestsContract__factory.ts +1 -1
- package/typechain-types/factories/contracts/mocks/utils/mpc/ValidateCiphertext128TestsContract__factory.ts +190 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/ValidateCiphertext256TestsContract__factory.ts +210 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/ValidateCiphertextTestsContract__factory.ts +260 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/index.ts +32 -0
- package/typechain-types/factories/contracts/mocks/wallet/PrivateERC20Wallet/PrivateERC20WalletMock__factory.ts +7 -7
- package/typechain-types/factories/contracts/token/PrivateERC20/IPrivateERC20__factory.ts +174 -42
- package/typechain-types/factories/contracts/token/PrivateERC20/PrivateERC20__factory.ts +174 -42
- package/typechain-types/factories/contracts/utils/mpc/MpcInterface.sol/ExtendedOperations__factory.ts +126 -0
- package/typechain-types/hardhat.d.ts +702 -0
- package/typechain-types/index.ts +78 -0
- package/contracts/mocks/utils/mpc/README.md +0 -486
- package/contracts/package.json +0 -11
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
|
|
5
|
+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
6
|
+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
7
|
+
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
|
8
|
+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @title FixedRatioCoinDisperserUnlimitedWindow
|
|
12
|
+
* @notice Redeem ERC20 "points" for native ETH payout pool
|
|
13
|
+
* - Fixed-index redemption set at finalize()
|
|
14
|
+
* - Pull-based withdrawals (DoS safe)
|
|
15
|
+
* - Optional push for EOAs only
|
|
16
|
+
* - Native ETH payouts
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
contract FixedRatioCoinDisperserUnlimitedWindow is ReentrancyGuard, Ownable {
|
|
20
|
+
using SafeERC20 for IERC20;
|
|
21
|
+
|
|
22
|
+
// --- Custom Errors ---
|
|
23
|
+
error TokenZeroAddress();
|
|
24
|
+
error OwnerZeroAddress();
|
|
25
|
+
error AlreadyFinalized();
|
|
26
|
+
error PoolZero();
|
|
27
|
+
error SupplyZero();
|
|
28
|
+
error NotFinalized();
|
|
29
|
+
error NoDust();
|
|
30
|
+
error ContractMustPull();
|
|
31
|
+
error NothingToWithdraw();
|
|
32
|
+
error ContractPaused();
|
|
33
|
+
error AmountZero();
|
|
34
|
+
error SnapshotZero();
|
|
35
|
+
error NoPointsLeft();
|
|
36
|
+
error OverCapacity();
|
|
37
|
+
error BalanceManipulation();
|
|
38
|
+
error PayoutZero();
|
|
39
|
+
error InvalidAddress();
|
|
40
|
+
error InsufficientEthBalance();
|
|
41
|
+
error EthTransferFailed();
|
|
42
|
+
|
|
43
|
+
// --- Events ---
|
|
44
|
+
event Funded(address indexed from, uint256 amount);
|
|
45
|
+
event Finalized(uint256 totalPayoutPool, uint256 totalRedeemablePoints, uint256 accPayoutPerPoint);
|
|
46
|
+
event Redeemed(address indexed user, uint256 pointsRequested, uint256 pointsReceived, uint256 payout, bool pushed);
|
|
47
|
+
event Paused(bool isPaused);
|
|
48
|
+
event DustWithdrawn(uint256 amount);
|
|
49
|
+
event Withdrawal(address indexed user, uint256 amount);
|
|
50
|
+
|
|
51
|
+
/// @notice Emitted when the payout index is updated via external source sync.
|
|
52
|
+
event AccPayoutPerPointUpdated(uint256 previousAccPayoutPerPoint, uint256 newAccPayoutPerPoint);
|
|
53
|
+
|
|
54
|
+
// --- Config ---
|
|
55
|
+
IERC20 public immutable POINTS_TOKEN;
|
|
56
|
+
|
|
57
|
+
// --- Lifecycle ---
|
|
58
|
+
bool public finalized;
|
|
59
|
+
bool public paused;
|
|
60
|
+
|
|
61
|
+
// --- Accounting ---
|
|
62
|
+
uint256 public totalPayoutPool; // ETH reserved for redemptions (snapshot at finalize)
|
|
63
|
+
uint256 public totalRedeemablePoints; // points supply snapshot at finalize
|
|
64
|
+
uint256 public accPayoutPerPoint; // index = totalPayoutPool * 1e18 / totalRedeemablePoints
|
|
65
|
+
uint256 public totalPointsRedeemed; // cumulative points locked
|
|
66
|
+
uint256 public totalPayoutSent; // cumulative ETH sent
|
|
67
|
+
|
|
68
|
+
// --- Pull ledger ---
|
|
69
|
+
mapping(address => uint256) public pendingWithdrawals;
|
|
70
|
+
uint256 public pendingTotal;
|
|
71
|
+
|
|
72
|
+
uint256 private constant ONE = 1e18;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @dev Constructor
|
|
76
|
+
* @param _pointsToken Address of the ERC20 points token that can be redeemed
|
|
77
|
+
* @param _owner Address that will have admin privileges (can pause, finalize, etc.)
|
|
78
|
+
*/
|
|
79
|
+
constructor(address _pointsToken, address _owner) {
|
|
80
|
+
if (_pointsToken == address(0)) revert TokenZeroAddress();
|
|
81
|
+
if (_owner == address(0)) revert OwnerZeroAddress();
|
|
82
|
+
|
|
83
|
+
POINTS_TOKEN = IERC20(_pointsToken);
|
|
84
|
+
_transferOwnership(_owner);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// --- Admin ---
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @dev Pause or unpause the redemption system
|
|
91
|
+
* @notice Only the owner can call this function
|
|
92
|
+
* @notice When paused, users cannot redeem points but can still withdraw pending amounts
|
|
93
|
+
*/
|
|
94
|
+
function setPaused(bool _paused) external onlyOwner {
|
|
95
|
+
paused = _paused;
|
|
96
|
+
emit Paused(_paused);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @dev Fund the contract with ETH for redemptions
|
|
101
|
+
* @notice Only the owner can call this function
|
|
102
|
+
* @notice The ETH sent will be used to pay out redemptions
|
|
103
|
+
* @notice Can be called multiple times to add more ETH
|
|
104
|
+
* @notice Cannot be called after finalization.
|
|
105
|
+
*/
|
|
106
|
+
function fundEth() external payable onlyOwner {
|
|
107
|
+
if (finalized) revert AlreadyFinalized();
|
|
108
|
+
if (msg.value == 0) revert AmountZero();
|
|
109
|
+
|
|
110
|
+
totalPayoutPool += msg.value;
|
|
111
|
+
emit Funded(msg.sender, msg.value);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @dev Move existing contract balance to the payout pool (pre-finalize only)
|
|
116
|
+
* @notice Only owner can call this function
|
|
117
|
+
* @notice Prevents double-counting by only adding (balance - totalPayoutPool) if positive
|
|
118
|
+
*/
|
|
119
|
+
function moveBalanceToPool() external onlyOwner {
|
|
120
|
+
if (finalized) revert AlreadyFinalized();
|
|
121
|
+
|
|
122
|
+
uint256 balance = address(this).balance;
|
|
123
|
+
if (balance == 0) revert PoolZero();
|
|
124
|
+
|
|
125
|
+
uint256 currentPool = totalPayoutPool;
|
|
126
|
+
if (balance > currentPool) {
|
|
127
|
+
uint256 difference = balance - currentPool;
|
|
128
|
+
totalPayoutPool += difference;
|
|
129
|
+
emit Funded(msg.sender, difference);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @dev Finalize the redemption system and calculate payout rates
|
|
135
|
+
* @notice Only the owner can call this function
|
|
136
|
+
* @notice Can only be called once
|
|
137
|
+
* @notice Snapshot the current ETH balance and points token supply
|
|
138
|
+
* @notice Calculate the payout rate per point (ETH per point)
|
|
139
|
+
* @notice After finalization, redemptions can begin (window no longer enforced)
|
|
140
|
+
*/
|
|
141
|
+
function finalize() external onlyOwner {
|
|
142
|
+
if (finalized) revert AlreadyFinalized();
|
|
143
|
+
|
|
144
|
+
uint256 pool = address(this).balance;
|
|
145
|
+
uint256 supply = POINTS_TOKEN.totalSupply();
|
|
146
|
+
if (pool == 0) revert PoolZero();
|
|
147
|
+
if (supply == 0) revert SupplyZero();
|
|
148
|
+
|
|
149
|
+
uint256 index = Math.mulDiv(pool, ONE, supply);
|
|
150
|
+
|
|
151
|
+
totalPayoutPool = pool;
|
|
152
|
+
totalRedeemablePoints = supply;
|
|
153
|
+
accPayoutPerPoint = index;
|
|
154
|
+
finalized = true;
|
|
155
|
+
|
|
156
|
+
emit Finalized(pool, supply, index);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// --- Owner utilities ---
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @dev Withdraw excess ETH that is not needed for redemptions
|
|
163
|
+
* @notice Only the owner can call this function
|
|
164
|
+
* @notice Can only be called after finalization and redemption window closes
|
|
165
|
+
* @notice Withdraws ETH in excess of what's needed for pending withdrawals
|
|
166
|
+
* @notice ETH is sent to the owner address
|
|
167
|
+
*
|
|
168
|
+
* @dev NOTE: Redemption window is no longer enforced; this can be called any time after finalization.
|
|
169
|
+
*/
|
|
170
|
+
function withdrawDust() external onlyOwner nonReentrant {
|
|
171
|
+
if (!finalized) revert NotFinalized();
|
|
172
|
+
// NOTE: redemption window no longer enforced
|
|
173
|
+
|
|
174
|
+
uint256 requiredReserve = pendingTotal;
|
|
175
|
+
uint256 bal = address(this).balance;
|
|
176
|
+
if (bal <= requiredReserve) revert NoDust();
|
|
177
|
+
|
|
178
|
+
uint256 amount = bal - requiredReserve;
|
|
179
|
+
(bool success,) = owner().call{value: amount}("");
|
|
180
|
+
if (!success) revert EthTransferFailed();
|
|
181
|
+
|
|
182
|
+
emit DustWithdrawn(amount);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// --- Redeem API ---
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @dev Redeem points for ETH using pull pattern (user must call withdraw later)
|
|
189
|
+
* @param amount Amount of points to redeem
|
|
190
|
+
* @notice User must have approved the contract to spend their points
|
|
191
|
+
* @notice ETH payout is added to user's pending withdrawals
|
|
192
|
+
* @notice User must call withdraw() later to receive the ETH
|
|
193
|
+
* @notice Can only be called when finalized and not paused (window no longer enforced)
|
|
194
|
+
*/
|
|
195
|
+
function redeemPull(uint256 amount) external nonReentrant {
|
|
196
|
+
(uint256 payout, uint256 received) = _redeemCore(msg.sender, amount);
|
|
197
|
+
pendingWithdrawals[msg.sender] += payout;
|
|
198
|
+
pendingTotal += payout;
|
|
199
|
+
|
|
200
|
+
emit Redeemed(msg.sender, amount, received, payout, false);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @dev Redeem points for ETH using push pattern (immediate ETH transfer)
|
|
205
|
+
* @param amount Amount of points to redeem
|
|
206
|
+
* @notice User must have approved the contract to spend their points
|
|
207
|
+
* @notice ETH is sent directly to the user's address
|
|
208
|
+
* @notice Only works for EOA (externally owned accounts), not contracts
|
|
209
|
+
* @notice Can only be called when finalized and not paused (window no longer enforced)
|
|
210
|
+
*/
|
|
211
|
+
function redeemPush(uint256 amount) external nonReentrant {
|
|
212
|
+
if (!_isEoa(msg.sender)) revert ContractMustPull();
|
|
213
|
+
|
|
214
|
+
(uint256 payout, uint256 received) = _redeemCore(msg.sender, amount);
|
|
215
|
+
|
|
216
|
+
(bool success,) = msg.sender.call{value: payout}("");
|
|
217
|
+
if (!success) revert EthTransferFailed();
|
|
218
|
+
|
|
219
|
+
emit Redeemed(msg.sender, amount, received, payout, true);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @dev Withdraw pending ETH from pull redemptions
|
|
224
|
+
* @notice Withdraws all pending ETH for the caller
|
|
225
|
+
* @notice ETH is sent directly to the caller's address
|
|
226
|
+
* @notice Can be called anytime after a pull redemption
|
|
227
|
+
* @notice Sets caller's pending balance to zero after withdrawal
|
|
228
|
+
*/
|
|
229
|
+
function withdraw() external nonReentrant {
|
|
230
|
+
uint256 amount = pendingWithdrawals[msg.sender];
|
|
231
|
+
if (amount == 0) revert NothingToWithdraw();
|
|
232
|
+
|
|
233
|
+
pendingWithdrawals[msg.sender] = 0;
|
|
234
|
+
pendingTotal -= amount;
|
|
235
|
+
|
|
236
|
+
(bool success,) = msg.sender.call{value: amount}("");
|
|
237
|
+
if (!success) revert EthTransferFailed();
|
|
238
|
+
|
|
239
|
+
emit Withdrawal(msg.sender, amount);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// --- Core math ---
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @dev Internal function that handles the core redemption logic
|
|
246
|
+
* @param user Address of the user redeeming points
|
|
247
|
+
* @param amount Amount of points to redeem
|
|
248
|
+
* @return payout Amount of ETH to be paid out
|
|
249
|
+
* @return received Actual amount of points received (transferred to contract)
|
|
250
|
+
* @notice Handles all validation, point transfer, and payout calculation
|
|
251
|
+
* @notice Points are transferred from user to contract and locked forever
|
|
252
|
+
* @notice Updates global accounting (totalPointsRedeemed, totalPayoutSent)
|
|
253
|
+
*/
|
|
254
|
+
function _redeemCore(address user, uint256 amount)
|
|
255
|
+
internal
|
|
256
|
+
returns (uint256 payout, uint256 received)
|
|
257
|
+
{
|
|
258
|
+
if (!finalized) revert NotFinalized();
|
|
259
|
+
if (paused) revert ContractPaused();
|
|
260
|
+
if (amount == 0) revert AmountZero();
|
|
261
|
+
|
|
262
|
+
uint256 trp = totalRedeemablePoints;
|
|
263
|
+
uint256 tpr = totalPointsRedeemed;
|
|
264
|
+
if (trp == 0) revert SnapshotZero();
|
|
265
|
+
|
|
266
|
+
uint256 remaining = trp - tpr;
|
|
267
|
+
if (remaining == 0) revert NoPointsLeft();
|
|
268
|
+
|
|
269
|
+
// Pull points token (requires allowance from user)
|
|
270
|
+
uint256 beforeBal = POINTS_TOKEN.balanceOf(address(this));
|
|
271
|
+
POINTS_TOKEN.safeTransferFrom(user, address(this), amount);
|
|
272
|
+
uint256 afterBal = POINTS_TOKEN.balanceOf(address(this));
|
|
273
|
+
received = afterBal - beforeBal;
|
|
274
|
+
|
|
275
|
+
if (received == 0) revert PayoutZero();
|
|
276
|
+
if (received > amount) revert BalanceManipulation();
|
|
277
|
+
if (received > remaining) revert OverCapacity();
|
|
278
|
+
|
|
279
|
+
payout = Math.mulDiv(received, accPayoutPerPoint, ONE);
|
|
280
|
+
|
|
281
|
+
// Cap payout by safe reserve / balance
|
|
282
|
+
uint256 reserve = _safeRemainingReserve();
|
|
283
|
+
if (payout > reserve) payout = reserve;
|
|
284
|
+
if (payout == 0) revert PayoutZero();
|
|
285
|
+
|
|
286
|
+
// Check if contract has enough ETH (defensive; reserve already caps by balance)
|
|
287
|
+
if (payout > address(this).balance) revert InsufficientEthBalance();
|
|
288
|
+
|
|
289
|
+
unchecked {
|
|
290
|
+
totalPointsRedeemed = tpr + received;
|
|
291
|
+
totalPayoutSent += payout;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// --- Views ---
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* @dev Check if redemptions are currently open
|
|
299
|
+
* @return True if redemptions are open (finalized and not paused)
|
|
300
|
+
*/
|
|
301
|
+
function isRedemptionOpen() public view returns (bool) {
|
|
302
|
+
return finalized && !paused;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* @dev Get the remaining ETH reserve available for redemptions
|
|
307
|
+
* @return Amount of ETH still available for redemptions
|
|
308
|
+
* @notice Returns 0 if not finalized or if all ETH has been paid out
|
|
309
|
+
*/
|
|
310
|
+
function remainingReserve() public view returns (uint256) {
|
|
311
|
+
if (!finalized) return 0;
|
|
312
|
+
if (totalPayoutSent >= totalPayoutPool) return 0;
|
|
313
|
+
return totalPayoutPool - totalPayoutSent;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* @dev Internal function to get the safe remaining reserve
|
|
318
|
+
* @return The minimum of theoretical reserve and actual ETH balance
|
|
319
|
+
* @notice Ensures we don't try to pay out more ETH than we actually have
|
|
320
|
+
*/
|
|
321
|
+
function _safeRemainingReserve() internal view returns (uint256) {
|
|
322
|
+
if (!finalized) return 0;
|
|
323
|
+
uint256 theoreticalReserve =
|
|
324
|
+
totalPayoutSent >= totalPayoutPool ? 0 : (totalPayoutPool - totalPayoutSent);
|
|
325
|
+
uint256 actualBalance = address(this).balance;
|
|
326
|
+
return theoreticalReserve > actualBalance ? actualBalance : theoreticalReserve;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* @dev Preview the ETH payout for a given amount of points
|
|
331
|
+
* @param amount Amount of points to redeem
|
|
332
|
+
* @return Expected ETH payout amount
|
|
333
|
+
* @notice This is an estimate and actual payout may be lower due to reserve limits
|
|
334
|
+
* @notice Returns 0 if not finalized, no points left, or amount exceeds remaining points
|
|
335
|
+
*/
|
|
336
|
+
function previewPayout(uint256 amount) external view returns (uint256) {
|
|
337
|
+
if (!finalized || amount == 0) return 0;
|
|
338
|
+
|
|
339
|
+
uint256 trp = totalRedeemablePoints;
|
|
340
|
+
if (trp == 0) return 0;
|
|
341
|
+
|
|
342
|
+
uint256 tpr = totalPointsRedeemed;
|
|
343
|
+
if (tpr >= trp) return 0;
|
|
344
|
+
|
|
345
|
+
uint256 remaining = trp - tpr;
|
|
346
|
+
if (amount > remaining) return 0;
|
|
347
|
+
|
|
348
|
+
uint256 est = Math.mulDiv(amount, accPayoutPerPoint, ONE);
|
|
349
|
+
uint256 reserve = remainingReserve();
|
|
350
|
+
return est > reserve ? reserve : est;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// --- Governance / Admin override ---
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* @dev Owner can directly update the payout rate per point.
|
|
357
|
+
* @param newAccPayoutPerPoint New payout index (ETH per point, scaled by 1e18)
|
|
358
|
+
* @notice Only callable after finalization.
|
|
359
|
+
* @notice Does NOT retroactively adjust past payouts; only affects future redemptions.
|
|
360
|
+
*/
|
|
361
|
+
function setAccPayoutPerPoint(uint256 newAccPayoutPerPoint) external onlyOwner {
|
|
362
|
+
if (!finalized) revert NotFinalized();
|
|
363
|
+
if (newAccPayoutPerPoint == 0) revert PayoutZero();
|
|
364
|
+
|
|
365
|
+
uint256 prev = accPayoutPerPoint;
|
|
366
|
+
accPayoutPerPoint = newAccPayoutPerPoint;
|
|
367
|
+
|
|
368
|
+
emit AccPayoutPerPointUpdated(prev, newAccPayoutPerPoint);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Rescue (window no longer enforced)
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* @dev Rescue ERC20 tokens sent to the contract after redemption window closes
|
|
375
|
+
* @param tokenAddr Address of the ERC20 token to rescue
|
|
376
|
+
* @param to Address to send the tokens to
|
|
377
|
+
* @param amount Amount of tokens to rescue
|
|
378
|
+
* @notice Only the owner can call this function
|
|
379
|
+
* @notice Can only be called after finalization and redemption window closes
|
|
380
|
+
* @notice Used to recover accidentally sent tokens
|
|
381
|
+
*
|
|
382
|
+
* @dev NOTE: Redemption window is no longer enforced; this can be called any time after finalization.
|
|
383
|
+
*/
|
|
384
|
+
function rescueTokens(address tokenAddr, address to, uint256 amount) external onlyOwner {
|
|
385
|
+
if (!finalized) revert NotFinalized();
|
|
386
|
+
if (to == address(0)) revert InvalidAddress();
|
|
387
|
+
if (amount == 0) revert AmountZero();
|
|
388
|
+
IERC20(tokenAddr).safeTransfer(to, amount);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* @dev Rescue ETH sent to the contract after redemption window closes
|
|
393
|
+
* @param to Address to send the ETH to
|
|
394
|
+
* @param amount Amount of ETH to rescue
|
|
395
|
+
* @notice Only the owner can call this function
|
|
396
|
+
* @notice Can only be called after finalization and redemption window closes
|
|
397
|
+
* @notice Used to recover accidentally sent ETH
|
|
398
|
+
*
|
|
399
|
+
* @dev NOTE: Redemption window is no longer enforced; this can be called any time after finalization.
|
|
400
|
+
*/
|
|
401
|
+
function rescueEth(address to, uint256 amount) external onlyOwner {
|
|
402
|
+
if (!finalized) revert NotFinalized();
|
|
403
|
+
if (to == address(0)) revert InvalidAddress();
|
|
404
|
+
if (amount == 0) revert AmountZero();
|
|
405
|
+
if (amount > address(this).balance) revert InsufficientEthBalance();
|
|
406
|
+
|
|
407
|
+
(bool success,) = to.call{value: amount}("");
|
|
408
|
+
if (!success) revert EthTransferFailed();
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// --- Utils ---
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* @dev Check if an address is an externally owned account (EOA)
|
|
415
|
+
* @param a Address to check
|
|
416
|
+
* @return True if the address is an EOA (no code), false if it's a contract
|
|
417
|
+
* @notice Used to determine if push redemptions are allowed
|
|
418
|
+
*/
|
|
419
|
+
function _isEoa(address a) internal view returns (bool) {
|
|
420
|
+
return a.code.length == 0;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* @dev Allow the contract to receive ETH from any sender.
|
|
425
|
+
* @notice This is triggered automatically when ETH is sent directly (no data).
|
|
426
|
+
* @notice The ETH is NOT automatically added to the redemption pool.
|
|
427
|
+
* @notice Use fundEth() or moveBalanceToPool() to add ETH to the pool.
|
|
428
|
+
*/
|
|
429
|
+
receive() external payable {
|
|
430
|
+
if (msg.value == 0) return; // ignore zero-value sends to save gas
|
|
431
|
+
}
|
|
432
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.20;
|
|
3
|
+
|
|
4
|
+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
5
|
+
|
|
6
|
+
interface IMintableERC20 {
|
|
7
|
+
function mint(address to, uint256 amount) external;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface IOwnable {
|
|
11
|
+
function transferOwnership(address newOwner) external;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @title MintDisperser
|
|
16
|
+
* @notice Owner-controlled utility contract for minting ERC20 tokens to multiple recipients in a single transaction
|
|
17
|
+
* @dev The target token must expose a mint(address,uint256) function and the
|
|
18
|
+
* MintDisperser contract must have permission to mint (e.g., MINTER_ROLE/owner).
|
|
19
|
+
* @dev Supports two distribution methods:
|
|
20
|
+
* - mintSameAmount: Mints the same amount to all recipients
|
|
21
|
+
* - mint: Mints different amounts to each recipient
|
|
22
|
+
*/
|
|
23
|
+
contract MintDisperser is Ownable {
|
|
24
|
+
/**
|
|
25
|
+
* @notice Initialize the MintDisperser contract
|
|
26
|
+
* @param initialOwner Address that will have owner privileges to execute minting operations
|
|
27
|
+
* @dev Sets the initial owner of the contract using OpenZeppelin's Ownable pattern
|
|
28
|
+
*/
|
|
29
|
+
constructor(address initialOwner) {
|
|
30
|
+
_transferOwnership(initialOwner);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @notice Mint the same amount of tokens to multiple recipients
|
|
35
|
+
* @param token Address of the ERC20 token contract that supports minting
|
|
36
|
+
* @param recipients Array of recipient addresses that will receive tokens
|
|
37
|
+
* @param amountPerRecipient Amount of tokens to mint to each recipient
|
|
38
|
+
* @dev Only the contract owner can call this function
|
|
39
|
+
* @dev Reverts if:
|
|
40
|
+
* - token is the zero address
|
|
41
|
+
* - amountPerRecipient is zero
|
|
42
|
+
* - recipients array is empty
|
|
43
|
+
* - any recipient address is the zero address
|
|
44
|
+
* @dev The token contract must allow this contract to mint tokens (typically by being the owner or having MINTER_ROLE)
|
|
45
|
+
* @dev All recipients receive the same amount of tokens
|
|
46
|
+
*/
|
|
47
|
+
function mintSameAmount(
|
|
48
|
+
address token,
|
|
49
|
+
address[] calldata recipients,
|
|
50
|
+
uint256 amountPerRecipient
|
|
51
|
+
) external onlyOwner {
|
|
52
|
+
require(token != address(0), "token=0");
|
|
53
|
+
require(amountPerRecipient > 0, "amount=0");
|
|
54
|
+
uint256 len = recipients.length;
|
|
55
|
+
require(len > 0, "no recipients");
|
|
56
|
+
|
|
57
|
+
for (uint256 i = 0; i < len; ++i) {
|
|
58
|
+
address to = recipients[i];
|
|
59
|
+
require(to != address(0), "recipient=0");
|
|
60
|
+
IMintableERC20(token).mint(to, amountPerRecipient);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @notice Mint different amounts of tokens to multiple recipients
|
|
66
|
+
* @param token Address of the ERC20 token contract that supports minting
|
|
67
|
+
* @param recipients Array of recipient addresses that will receive tokens
|
|
68
|
+
* @param amounts Array of token amounts to mint to each recipient (must match recipients array length)
|
|
69
|
+
* @dev Only the contract owner can call this function
|
|
70
|
+
* @dev Reverts if:
|
|
71
|
+
* - token is the zero address
|
|
72
|
+
* - recipients array is empty
|
|
73
|
+
* - recipients and amounts arrays have different lengths
|
|
74
|
+
* - any recipient address is the zero address
|
|
75
|
+
* - any amount is zero
|
|
76
|
+
* @dev The token contract must allow this contract to mint tokens (typically by being the owner or having MINTER_ROLE)
|
|
77
|
+
* @dev Each recipient receives the corresponding amount from the amounts array at the same index
|
|
78
|
+
*/
|
|
79
|
+
function mint(
|
|
80
|
+
address token,
|
|
81
|
+
address[] calldata recipients,
|
|
82
|
+
uint256[] calldata amounts
|
|
83
|
+
) external onlyOwner {
|
|
84
|
+
require(token != address(0), "token=0");
|
|
85
|
+
uint256 len = recipients.length;
|
|
86
|
+
require(len > 0, "no recipients");
|
|
87
|
+
require(len == amounts.length, "length mismatch");
|
|
88
|
+
|
|
89
|
+
for (uint256 i = 0; i < len; ++i) {
|
|
90
|
+
address to = recipients[i];
|
|
91
|
+
uint256 amt = amounts[i];
|
|
92
|
+
require(to != address(0), "recipient=0");
|
|
93
|
+
require(amt > 0, "amount=0");
|
|
94
|
+
IMintableERC20(token).mint(to, amt);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @notice Transfers ownership of an Ownable ERC20 token from this contract to a new owner
|
|
100
|
+
* @param token Address of the Ownable token contract whose ownership will be transferred
|
|
101
|
+
* @param newOwner Address that will become the new owner of the token contract
|
|
102
|
+
* @dev Only the contract owner can call this function
|
|
103
|
+
* @dev Reverts if:
|
|
104
|
+
* - token is the zero address
|
|
105
|
+
* - newOwner is the zero address
|
|
106
|
+
* - this contract is not the current owner of the token contract
|
|
107
|
+
* @dev This function is useful for transferring token ownership after the MintDisperser has been granted ownership
|
|
108
|
+
* to enable minting operations. After minting is complete, ownership can be transferred back or to another address.
|
|
109
|
+
* @dev The token contract must implement the IOwnable interface with a transferOwnership function
|
|
110
|
+
*/
|
|
111
|
+
function transferTokenOwnership(
|
|
112
|
+
address token,
|
|
113
|
+
address newOwner
|
|
114
|
+
) external onlyOwner {
|
|
115
|
+
require(token != address(0), "token=0");
|
|
116
|
+
require(newOwner != address(0), "newOwner=0");
|
|
117
|
+
|
|
118
|
+
IOwnable(token).transferOwnership(newOwner);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity 0.8.19;
|
|
4
|
+
|
|
5
|
+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
6
|
+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @title TokenDisperser
|
|
10
|
+
* @notice Owner-controlled utility contract for distributing ERC20 tokens to multiple recipients
|
|
11
|
+
* @dev Supports two distribution methods:
|
|
12
|
+
* - disperseFunds: Pulls tokens from a sender's balance (requires approval)
|
|
13
|
+
* - disperseFundsFromContract: Distributes from this contract's own token balance
|
|
14
|
+
* @dev Tracks distributions by ID to prevent duplicate payouts to same recipient
|
|
15
|
+
* @dev Uses OpenZeppelin's SafeERC20 for secure token transfers
|
|
16
|
+
*/
|
|
17
|
+
contract TokenDisperser {
|
|
18
|
+
using SafeERC20 for IERC20;
|
|
19
|
+
|
|
20
|
+
/// @notice Contract owner with permissions to execute distributions
|
|
21
|
+
address public immutable owner;
|
|
22
|
+
|
|
23
|
+
/// @notice ERC20 token that will be distributed
|
|
24
|
+
IERC20 public immutable token;
|
|
25
|
+
|
|
26
|
+
/// @notice Mapping: distributionId => recipient => amount received
|
|
27
|
+
/// @dev Used to prevent duplicate distributions to same recipient per distributionId
|
|
28
|
+
mapping(uint256 => mapping(address => uint256)) private _fundsReceived;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @notice Reverts if caller is not the owner
|
|
32
|
+
*/
|
|
33
|
+
modifier onlyOwner {
|
|
34
|
+
require(msg.sender == owner, "Caller is not owner");
|
|
35
|
+
_;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @notice Initialize the TokenDisperser contract
|
|
40
|
+
* @param token_ Address of the ERC20 token to distribute
|
|
41
|
+
* @dev Sets deployer as owner and stores the token address
|
|
42
|
+
*/
|
|
43
|
+
constructor(address token_) {
|
|
44
|
+
owner = msg.sender;
|
|
45
|
+
token = IERC20(token_);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @notice Query how much each recipient received in a distribution
|
|
50
|
+
* @param distributionId The distribution ID to query
|
|
51
|
+
* @param recipients Array of recipient addresses to check
|
|
52
|
+
* @return Array of amounts received (same order as recipients)
|
|
53
|
+
* @dev Returns 0 for addresses that haven't received funds in this distribution
|
|
54
|
+
*/
|
|
55
|
+
function fundsReceived(uint256 distributionId, address[] calldata recipients) external view returns (uint256[] memory) {
|
|
56
|
+
uint256[] memory fundsReceived_ = new uint256[](recipients.length);
|
|
57
|
+
|
|
58
|
+
for (uint256 i = 0; i < recipients.length; ++i) {
|
|
59
|
+
fundsReceived_[i] = _fundsReceived[distributionId][recipients[i]];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return fundsReceived_;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @notice Distribute tokens from a sender's balance to multiple recipients
|
|
67
|
+
* @param distributionId Unique ID for this distribution batch
|
|
68
|
+
* @param totalAmount Sum of all amounts (used for validation)
|
|
69
|
+
* @param sender Address that has tokens and approved this contract to spend them
|
|
70
|
+
* @param recipients Array of recipient addresses
|
|
71
|
+
* @param amounts Array of token amounts (must match recipients length)
|
|
72
|
+
* @dev Only owner can call this function
|
|
73
|
+
* @dev Requires sender to have approved this contract
|
|
74
|
+
* @dev Prevents duplicate distributions to same recipient within same distributionId
|
|
75
|
+
* @dev Reverts if amounts don't sum to totalAmount
|
|
76
|
+
* @dev Uses safeTransferFrom to pull tokens from sender
|
|
77
|
+
*/
|
|
78
|
+
function disperseFunds(
|
|
79
|
+
uint256 distributionId,
|
|
80
|
+
uint256 totalAmount,
|
|
81
|
+
address sender,
|
|
82
|
+
address[] calldata recipients,
|
|
83
|
+
uint256[] calldata amounts
|
|
84
|
+
)
|
|
85
|
+
external
|
|
86
|
+
onlyOwner
|
|
87
|
+
{
|
|
88
|
+
uint256 currentAmount = 0;
|
|
89
|
+
|
|
90
|
+
for (uint256 i = 0; i < recipients.length; ++i) {
|
|
91
|
+
require(_fundsReceived[distributionId][recipients[i]] == 0, "Duplicate recipient");
|
|
92
|
+
|
|
93
|
+
token.safeTransferFrom(sender, recipients[i], amounts[i]);
|
|
94
|
+
|
|
95
|
+
currentAmount += amounts[i];
|
|
96
|
+
|
|
97
|
+
_fundsReceived[distributionId][recipients[i]] = amounts[i];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
require(currentAmount == totalAmount, "Incorrect amount");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @notice Distribute tokens from this contract's own balance to multiple recipients
|
|
105
|
+
* @param distributionId Unique ID for this distribution batch
|
|
106
|
+
* @param totalAmount Sum of all amounts (used for validation)
|
|
107
|
+
* @param recipients Array of recipient addresses
|
|
108
|
+
* @param amounts Array of token amounts (must match recipients length)
|
|
109
|
+
* @dev Only owner can call this function
|
|
110
|
+
* @dev Requires contract to have sufficient token balance
|
|
111
|
+
* @dev Prevents duplicate distributions to same recipient within same distributionId
|
|
112
|
+
* @dev Reverts if amounts don't sum to totalAmount or contract lacks balance
|
|
113
|
+
* @dev Uses safeTransfer to send from contract's own balance
|
|
114
|
+
*/
|
|
115
|
+
function disperseFundsFromContract(
|
|
116
|
+
uint256 distributionId,
|
|
117
|
+
uint256 totalAmount,
|
|
118
|
+
address[] calldata recipients,
|
|
119
|
+
uint256[] calldata amounts
|
|
120
|
+
)
|
|
121
|
+
external
|
|
122
|
+
onlyOwner
|
|
123
|
+
{
|
|
124
|
+
uint256 currentAmount = 0;
|
|
125
|
+
|
|
126
|
+
for (uint256 i = 0; i < recipients.length; ++i) {
|
|
127
|
+
require(_fundsReceived[distributionId][recipients[i]] == 0, "Duplicate recipient");
|
|
128
|
+
|
|
129
|
+
// Transfer from this contract's own balance directly
|
|
130
|
+
token.safeTransfer(recipients[i], amounts[i]);
|
|
131
|
+
|
|
132
|
+
currentAmount += amounts[i];
|
|
133
|
+
|
|
134
|
+
_fundsReceived[distributionId][recipients[i]] = amounts[i];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
require(currentAmount == totalAmount, "Incorrect amount");
|
|
138
|
+
}
|
|
139
|
+
}
|