@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
|
@@ -2,19 +2,26 @@ import hre from "hardhat"
|
|
|
2
2
|
import { expect } from "chai"
|
|
3
3
|
|
|
4
4
|
import { setupAccounts } from "../../utils/accounts"
|
|
5
|
+
import {
|
|
6
|
+
IPRIVATE_ERC20_INTERFACE_ID,
|
|
7
|
+
mintPublic,
|
|
8
|
+
burnPublic,
|
|
9
|
+
txOpts,
|
|
10
|
+
encryptItUint256,
|
|
11
|
+
decryptCtUint256,
|
|
12
|
+
expectTxFails
|
|
13
|
+
} from "../../utils/privateErc20Helpers"
|
|
5
14
|
import { PrivateERC20Mock, PrivateERC20WalletMock } from "../../../typechain-types"
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
15
|
+
import { Wallet } from "@coti-io/coti-ethers"
|
|
16
|
+
import type { itUint256 } from "@coti-io/coti-sdk-typescript"
|
|
17
|
+
import { ZeroAddress } from "ethers"
|
|
9
18
|
|
|
10
19
|
async function deploy() {
|
|
11
20
|
const [owner, otherAccount] = await setupAccounts()
|
|
12
21
|
|
|
13
22
|
const tokenContract = await hre.ethers.getContractFactory("PrivateERC20Mock")
|
|
14
23
|
|
|
15
|
-
const token = await tokenContract
|
|
16
|
-
.connect(owner)
|
|
17
|
-
.deploy({ gasLimit: GAS_LIMIT })
|
|
24
|
+
const token = await tokenContract.connect(owner).deploy(txOpts)
|
|
18
25
|
|
|
19
26
|
const contract = await token.waitForDeployment()
|
|
20
27
|
|
|
@@ -42,118 +49,102 @@ describe("Private ERC20", function () {
|
|
|
42
49
|
})
|
|
43
50
|
|
|
44
51
|
describe("deploy", function () {
|
|
45
|
-
it(
|
|
46
|
-
await expect(await contract.name()).to.equal("PrivateERC20Mock")
|
|
52
|
+
it("has a name", async function () {
|
|
53
|
+
await expect(await contract.name()).to.equal("PrivateERC20Mock")
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it("has a symbol", async function () {
|
|
57
|
+
await expect(await contract.symbol()).to.equal("PE20M")
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it("has 6 decimals", async function () {
|
|
61
|
+
await expect(await contract.decimals()).to.equal(6n)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it("totalSupply view is zero (privacy stance)", async function () {
|
|
65
|
+
await expect(await contract.totalSupply()).to.equal(0n)
|
|
47
66
|
})
|
|
48
67
|
|
|
49
|
-
it(
|
|
50
|
-
await expect(await contract.
|
|
68
|
+
it("publicAmountsEnabled is true by default", async function () {
|
|
69
|
+
await expect(await contract.publicAmountsEnabled()).to.equal(true)
|
|
51
70
|
})
|
|
52
71
|
|
|
53
|
-
it(
|
|
54
|
-
await expect(await contract.
|
|
72
|
+
it("supports ERC-165 and IPrivateERC20", async function () {
|
|
73
|
+
await expect(await contract.supportsInterface("0x01ffc9a7")).to.equal(true)
|
|
74
|
+
await expect(await contract.supportsInterface(IPRIVATE_ERC20_INTERFACE_ID)).to.equal(true)
|
|
75
|
+
await expect(await contract.supportsInterface("0xffffffff")).to.equal(false)
|
|
55
76
|
})
|
|
56
77
|
})
|
|
57
78
|
|
|
58
79
|
describe("mint", function () {
|
|
59
80
|
const value = 5000n
|
|
60
81
|
|
|
61
|
-
describe("successful mint",
|
|
82
|
+
describe("successful mint", function () {
|
|
62
83
|
before("minting", async function () {
|
|
63
|
-
this.tx = await contract
|
|
64
|
-
.connect(owner)
|
|
65
|
-
.mint(owner.address, value, { gasLimit: GAS_LIMIT })
|
|
66
|
-
|
|
84
|
+
this.tx = await mintPublic(contract, owner, owner.address, value)
|
|
67
85
|
await this.tx.wait()
|
|
68
86
|
})
|
|
69
|
-
|
|
70
|
-
it(
|
|
87
|
+
|
|
88
|
+
it("does not increment totalSupply", async function () {
|
|
71
89
|
await expect(await contract.totalSupply()).to.equal(0n)
|
|
72
90
|
})
|
|
73
|
-
|
|
74
|
-
it(
|
|
91
|
+
|
|
92
|
+
it("increments recipient balance", async function () {
|
|
75
93
|
const ctBalance = await contract["balanceOf(address)"](owner.address)
|
|
76
|
-
|
|
77
|
-
const balance =
|
|
78
|
-
|
|
94
|
+
|
|
95
|
+
const balance = decryptCtUint256(owner, ctBalance)
|
|
96
|
+
|
|
79
97
|
await expect(balance).to.equal(value)
|
|
80
98
|
})
|
|
81
|
-
|
|
82
|
-
it(
|
|
99
|
+
|
|
100
|
+
it("emits Transfer event", async function () {
|
|
83
101
|
await expect(this.tx).to.emit(contract, "Transfer")
|
|
84
102
|
})
|
|
85
103
|
})
|
|
86
|
-
|
|
87
|
-
describe(
|
|
88
|
-
it(
|
|
89
|
-
await
|
|
90
|
-
contract
|
|
91
|
-
|
|
92
|
-
.mint(ZeroAddress, value)
|
|
93
|
-
)
|
|
94
|
-
.to.be.revertedWithCustomError(contract, "ERC20InvalidReceiver")
|
|
95
|
-
.withArgs(ZeroAddress)
|
|
104
|
+
|
|
105
|
+
describe("failed mint", function () {
|
|
106
|
+
it("rejects minting to the zero address", async function () {
|
|
107
|
+
await expectTxFails(
|
|
108
|
+
contract.connect(owner).getFunction("mint(address,uint256)")(ZeroAddress, value, txOpts)
|
|
109
|
+
)
|
|
96
110
|
})
|
|
97
|
-
|
|
98
|
-
// it('rejects overflow', async function () {
|
|
99
|
-
// const tx = await contract
|
|
100
|
-
// .connect(owner.wallet)
|
|
101
|
-
// .mint(owner.wallet.address, (BigInt(2) ** BigInt(64)) - BigInt(1), { gasLimit: GAS_LIMIT })
|
|
102
|
-
|
|
103
|
-
// await tx.wait()
|
|
104
|
-
|
|
105
|
-
// await expect(tx).to.be.reverted
|
|
106
|
-
// })
|
|
107
111
|
})
|
|
108
112
|
})
|
|
109
113
|
|
|
110
114
|
describe("burn", function () {
|
|
111
115
|
const value = 5000n
|
|
112
|
-
|
|
113
|
-
describe('failed burn', async function () {
|
|
114
|
-
it('rejects burning from the zero address', async function () {
|
|
115
|
-
await expect(
|
|
116
|
-
contract
|
|
117
|
-
.connect(owner)
|
|
118
|
-
.burn(ZeroAddress, value)
|
|
119
|
-
)
|
|
120
|
-
.to.be.revertedWithCustomError(contract, "ERC20InvalidSender")
|
|
121
|
-
.withArgs(ZeroAddress)
|
|
122
|
-
})
|
|
123
116
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const ctBalance = await contract["balanceOf(address)"](owner.address)
|
|
117
|
+
describe("failed burn", function () {
|
|
118
|
+
it("rejects burning from the zero address", async function () {
|
|
119
|
+
await expectTxFails(
|
|
120
|
+
contract.connect(owner).getFunction("burn(address,uint256)")(ZeroAddress, value, txOpts)
|
|
121
|
+
)
|
|
122
|
+
})
|
|
132
123
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
124
|
+
it("reverts when burning more than balance (no Transfer)", async function () {
|
|
125
|
+
await expectTxFails(
|
|
126
|
+
contract
|
|
127
|
+
.connect(owner)
|
|
128
|
+
.getFunction("burn(address,uint256)")(owner.address, value + 1n, txOpts)
|
|
129
|
+
)
|
|
136
130
|
})
|
|
137
131
|
})
|
|
138
132
|
|
|
139
|
-
describe(
|
|
133
|
+
describe("successful burn", function () {
|
|
140
134
|
before("burning", async function () {
|
|
141
|
-
this.tx = await contract
|
|
142
|
-
.connect(owner)
|
|
143
|
-
.burn(owner.address, value, { gasLimit: GAS_LIMIT })
|
|
144
|
-
|
|
135
|
+
this.tx = await burnPublic(contract, owner, owner.address, value)
|
|
145
136
|
await this.tx.wait()
|
|
146
137
|
})
|
|
147
138
|
|
|
148
|
-
it(
|
|
139
|
+
it("decrements the senders balance", async function () {
|
|
149
140
|
const ctBalance = await contract["balanceOf(address)"](owner.address)
|
|
150
141
|
|
|
151
|
-
const balance =
|
|
152
|
-
|
|
142
|
+
const balance = decryptCtUint256(owner, ctBalance)
|
|
143
|
+
|
|
153
144
|
await expect(balance).to.equal(0n)
|
|
154
145
|
})
|
|
155
146
|
|
|
156
|
-
it(
|
|
147
|
+
it("emits Transfer event", async function () {
|
|
157
148
|
await expect(this.tx).to.emit(contract, "Transfer")
|
|
158
149
|
})
|
|
159
150
|
})
|
|
@@ -163,76 +154,78 @@ describe("Private ERC20", function () {
|
|
|
163
154
|
const value = 10000n
|
|
164
155
|
|
|
165
156
|
before("minting", async function () {
|
|
166
|
-
this.tx = await contract
|
|
167
|
-
.connect(owner)
|
|
168
|
-
.mint(owner.address, value, { gasLimit: GAS_LIMIT })
|
|
169
|
-
|
|
157
|
+
this.tx = await mintPublic(contract, owner, owner.address, value)
|
|
170
158
|
await this.tx.wait()
|
|
171
159
|
})
|
|
172
160
|
|
|
173
|
-
describe("failed transfer",
|
|
174
|
-
it(
|
|
175
|
-
const itValue = await owner
|
|
176
|
-
|
|
161
|
+
describe("failed transfer", function () {
|
|
162
|
+
it("rejects transferring to the zero address", async function () {
|
|
163
|
+
const itValue = (await encryptItUint256(owner,
|
|
164
|
+
value,
|
|
165
|
+
contractAddress,
|
|
166
|
+
contract.interface.getFunction("transfer(address,((uint256,uint256),bytes))").selector
|
|
167
|
+
)) as itUint256
|
|
168
|
+
|
|
177
169
|
await expect(
|
|
178
170
|
contract
|
|
179
171
|
.connect(owner)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
)
|
|
172
|
+
.getFunction("transfer(address,((uint256,uint256),bytes))")(ZeroAddress, itValue)
|
|
173
|
+
)
|
|
183
174
|
.to.be.revertedWithCustomError(contract, "ERC20InvalidReceiver")
|
|
184
175
|
.withArgs(ZeroAddress)
|
|
185
176
|
})
|
|
186
177
|
|
|
187
|
-
it(
|
|
188
|
-
const itValue = await owner
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
.
|
|
192
|
-
|
|
193
|
-
(otherAccount.address, itValue, { gasLimit: GAS_LIMIT })
|
|
194
|
-
|
|
195
|
-
await tx.wait()
|
|
196
|
-
|
|
197
|
-
let ctBalance = await contract["balanceOf(address)"](owner.address)
|
|
198
|
-
|
|
199
|
-
let balance = await owner.decryptValue(ctBalance)
|
|
200
|
-
|
|
201
|
-
await expect(balance).to.equal(value)
|
|
202
|
-
|
|
203
|
-
ctBalance = await contract["balanceOf(address)"](otherAccount.address)
|
|
178
|
+
it("reverts when amount exceeds balance (no Transfer)", async function () {
|
|
179
|
+
const itValue = (await encryptItUint256(owner,
|
|
180
|
+
value + 1n,
|
|
181
|
+
contractAddress,
|
|
182
|
+
contract.interface.getFunction("transfer(address,((uint256,uint256),bytes))").selector
|
|
183
|
+
)) as itUint256
|
|
204
184
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
185
|
+
await expectTxFails(
|
|
186
|
+
contract
|
|
187
|
+
.connect(owner)
|
|
188
|
+
.getFunction("transfer(address,((uint256,uint256),bytes))")(
|
|
189
|
+
otherAccount.address,
|
|
190
|
+
itValue,
|
|
191
|
+
txOpts
|
|
192
|
+
)
|
|
193
|
+
)
|
|
208
194
|
})
|
|
209
195
|
})
|
|
210
196
|
|
|
211
|
-
describe("successful transfer",
|
|
197
|
+
describe("successful transfer", function () {
|
|
212
198
|
before("transferring", async function () {
|
|
213
|
-
const itValue = await owner
|
|
199
|
+
const itValue = (await encryptItUint256(owner,
|
|
200
|
+
value / 2n,
|
|
201
|
+
contractAddress,
|
|
202
|
+
contract.interface.getFunction("transfer(address,((uint256,uint256),bytes))").selector
|
|
203
|
+
)) as itUint256
|
|
214
204
|
|
|
215
205
|
const tx = await contract
|
|
216
206
|
.connect(owner)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
207
|
+
.getFunction("transfer(address,((uint256,uint256),bytes))")(
|
|
208
|
+
otherAccount.address,
|
|
209
|
+
itValue,
|
|
210
|
+
txOpts
|
|
211
|
+
)
|
|
212
|
+
|
|
220
213
|
await tx.wait()
|
|
221
214
|
})
|
|
222
215
|
|
|
223
|
-
it(
|
|
216
|
+
it("decrements the senders balance", async function () {
|
|
224
217
|
const ctBalance = await contract["balanceOf(address)"](owner.address)
|
|
225
218
|
|
|
226
|
-
const balance =
|
|
227
|
-
|
|
219
|
+
const balance = decryptCtUint256(owner, ctBalance)
|
|
220
|
+
|
|
228
221
|
await expect(balance).to.equal(value / 2n)
|
|
229
222
|
})
|
|
230
223
|
|
|
231
|
-
it(
|
|
224
|
+
it("increments the receivers balance", async function () {
|
|
232
225
|
const ctBalance = await contract["balanceOf(address)"](otherAccount.address)
|
|
233
226
|
|
|
234
|
-
const balance =
|
|
235
|
-
|
|
227
|
+
const balance = decryptCtUint256(otherAccount, ctBalance)
|
|
228
|
+
|
|
236
229
|
await expect(balance).to.equal(value / 2n)
|
|
237
230
|
})
|
|
238
231
|
})
|
|
@@ -241,135 +234,187 @@ describe("Private ERC20", function () {
|
|
|
241
234
|
describe("approve", function () {
|
|
242
235
|
const value = 5000n
|
|
243
236
|
|
|
244
|
-
describe("failed approval",
|
|
245
|
-
it(
|
|
246
|
-
const itValue = await owner
|
|
247
|
-
|
|
237
|
+
describe("failed approval", function () {
|
|
238
|
+
it("rejects when approving the zero address", async function () {
|
|
239
|
+
const itValue = (await encryptItUint256(owner,
|
|
240
|
+
value,
|
|
241
|
+
contractAddress,
|
|
242
|
+
contract.interface.getFunction("approve(address,((uint256,uint256),bytes))").selector
|
|
243
|
+
)) as itUint256
|
|
244
|
+
|
|
248
245
|
await expect(
|
|
249
246
|
contract
|
|
250
247
|
.connect(owner)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
)
|
|
248
|
+
.getFunction("approve(address,((uint256,uint256),bytes))")(ZeroAddress, itValue)
|
|
249
|
+
)
|
|
254
250
|
.to.be.revertedWithCustomError(contract, "ERC20InvalidSpender")
|
|
255
251
|
.withArgs(ZeroAddress)
|
|
256
252
|
})
|
|
257
253
|
})
|
|
258
254
|
|
|
259
|
-
describe("successful approval",
|
|
260
|
-
before(
|
|
261
|
-
const itValue = await owner
|
|
255
|
+
describe("successful approval", function () {
|
|
256
|
+
before("approving", async function () {
|
|
257
|
+
const itValue = (await encryptItUint256(owner,
|
|
258
|
+
value,
|
|
259
|
+
contractAddress,
|
|
260
|
+
contract.interface.getFunction("approve(address,((uint256,uint256),bytes))").selector
|
|
261
|
+
)) as itUint256
|
|
262
262
|
|
|
263
263
|
const tx = await contract
|
|
264
264
|
.connect(owner)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
265
|
+
.getFunction("approve(address,((uint256,uint256),bytes))")(otherAccount.address, itValue, txOpts)
|
|
266
|
+
|
|
268
267
|
await tx.wait()
|
|
269
268
|
})
|
|
270
269
|
|
|
271
|
-
it(
|
|
272
|
-
const ctAllowance = await contract
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
const allowance = await owner.decryptValue(ctAllowance[1])
|
|
270
|
+
it("stores allowance ciphertext for owner view", async function () {
|
|
271
|
+
const ctAllowance = await contract["allowance(address,address)"](owner.address, otherAccount.address)
|
|
272
|
+
|
|
273
|
+
const allowance = decryptCtUint256(owner, ctAllowance.ownerCiphertext)
|
|
277
274
|
|
|
278
275
|
await expect(allowance).to.equal(value)
|
|
279
276
|
})
|
|
280
277
|
|
|
281
|
-
it(
|
|
282
|
-
const ctAllowance = await contract
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const allowance = await otherAccount.decryptValue(ctAllowance[2])
|
|
278
|
+
it("stores allowance ciphertext for spender view", async function () {
|
|
279
|
+
const ctAllowance = await contract["allowance(address,address)"](owner.address, otherAccount.address)
|
|
280
|
+
|
|
281
|
+
const allowance = decryptCtUint256(otherAccount, ctAllowance.spenderCiphertext)
|
|
287
282
|
|
|
288
283
|
await expect(allowance).to.equal(value)
|
|
289
284
|
})
|
|
290
285
|
})
|
|
291
286
|
})
|
|
292
287
|
|
|
293
|
-
describe(
|
|
288
|
+
describe("transferFrom", function () {
|
|
294
289
|
const value = 3000n
|
|
295
290
|
|
|
296
|
-
describe(
|
|
297
|
-
it(
|
|
298
|
-
const itValue = await otherAccount
|
|
299
|
-
|
|
291
|
+
describe("failed transferFrom", function () {
|
|
292
|
+
it("rejects transferring to the zero address", async function () {
|
|
293
|
+
const itValue = (await encryptItUint256(otherAccount,
|
|
294
|
+
value,
|
|
295
|
+
contractAddress,
|
|
296
|
+
contract.interface.getFunction("transferFrom(address,address,((uint256,uint256),bytes))").selector
|
|
297
|
+
)) as itUint256
|
|
298
|
+
|
|
300
299
|
await expect(
|
|
301
300
|
contract
|
|
302
301
|
.connect(otherAccount)
|
|
303
|
-
|
|
304
|
-
(owner.address, ZeroAddress, itValue)
|
|
305
|
-
|
|
302
|
+
.getFunction("transferFrom(address,address,((uint256,uint256),bytes))")
|
|
303
|
+
.staticCall(owner.address, ZeroAddress, itValue)
|
|
304
|
+
)
|
|
306
305
|
.to.be.revertedWithCustomError(contract, "ERC20InvalidReceiver")
|
|
307
306
|
.withArgs(ZeroAddress)
|
|
308
307
|
})
|
|
309
308
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
309
|
+
it("rejects from zero address", async function () {
|
|
310
|
+
const itValue = (await encryptItUint256(otherAccount,
|
|
311
|
+
value,
|
|
312
|
+
contractAddress,
|
|
313
|
+
contract.interface.getFunction("transferFrom(address,address,((uint256,uint256),bytes))").selector
|
|
314
|
+
)) as itUint256
|
|
313
315
|
|
|
314
|
-
|
|
316
|
+
await expect(
|
|
317
|
+
contract
|
|
315
318
|
.connect(otherAccount)
|
|
316
|
-
|
|
317
|
-
(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
})
|
|
319
|
+
.getFunction("transferFrom(address,address,((uint256,uint256),bytes))")
|
|
320
|
+
.staticCall(ZeroAddress, otherAccount.address, itValue)
|
|
321
|
+
).to.be.revertedWithCustomError(contract, "ERC20InvalidSender")
|
|
322
|
+
})
|
|
321
323
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
+
it("reverts when allowance is insufficient", async function () {
|
|
325
|
+
const itValue = (await encryptItUint256(otherAccount,
|
|
326
|
+
999999n,
|
|
327
|
+
contractAddress,
|
|
328
|
+
contract.interface.getFunction("transferFrom(address,address,((uint256,uint256),bytes))").selector
|
|
329
|
+
)) as itUint256
|
|
324
330
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
331
|
+
await expectTxFails(
|
|
332
|
+
contract
|
|
333
|
+
.connect(otherAccount)
|
|
334
|
+
.getFunction("transferFrom(address,address,((uint256,uint256),bytes))")(
|
|
335
|
+
owner.address,
|
|
336
|
+
otherAccount.address,
|
|
337
|
+
itValue,
|
|
338
|
+
txOpts
|
|
339
|
+
)
|
|
340
|
+
)
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
it("reverts when amount exceeds balance (allowance OK)", async function () {
|
|
344
|
+
await contract
|
|
345
|
+
.connect(owner)
|
|
346
|
+
.getFunction("increaseAllowance(address,uint256)")(otherAccount.address, 5000n, txOpts)
|
|
347
|
+
.then((t) => t.wait())
|
|
329
348
|
|
|
330
|
-
|
|
331
|
-
|
|
349
|
+
const itValue = (await encryptItUint256(otherAccount,
|
|
350
|
+
6000n,
|
|
351
|
+
contractAddress,
|
|
352
|
+
contract.interface.getFunction("transferFrom(address,address,((uint256,uint256),bytes))").selector
|
|
353
|
+
)) as itUint256
|
|
332
354
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
355
|
+
await expectTxFails(
|
|
356
|
+
contract
|
|
357
|
+
.connect(otherAccount)
|
|
358
|
+
.getFunction("transferFrom(address,address,((uint256,uint256),bytes))")(
|
|
359
|
+
owner.address,
|
|
360
|
+
"0x0000000000000000000000000000000000000001",
|
|
361
|
+
itValue,
|
|
362
|
+
txOpts
|
|
363
|
+
)
|
|
364
|
+
)
|
|
337
365
|
})
|
|
338
366
|
})
|
|
339
367
|
|
|
340
|
-
describe(
|
|
341
|
-
before(
|
|
342
|
-
|
|
368
|
+
describe("successful transferFrom", function () {
|
|
369
|
+
before("transferring", async function () {
|
|
370
|
+
await contract
|
|
371
|
+
.connect(owner)
|
|
372
|
+
.getFunction("approve(address,uint256)")(otherAccount.address, 0n, txOpts)
|
|
373
|
+
.then((t) => t.wait())
|
|
374
|
+
await contract
|
|
375
|
+
.connect(owner)
|
|
376
|
+
.getFunction("approve(address,uint256)")(otherAccount.address, 5000n, txOpts)
|
|
377
|
+
.then((t) => t.wait())
|
|
378
|
+
|
|
379
|
+
const itValue = (await encryptItUint256(otherAccount,
|
|
380
|
+
value,
|
|
381
|
+
contractAddress,
|
|
382
|
+
contract.interface.getFunction("transferFrom(address,address,((uint256,uint256),bytes))").selector
|
|
383
|
+
)) as itUint256
|
|
343
384
|
|
|
344
385
|
const tx = await contract
|
|
345
386
|
.connect(otherAccount)
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
387
|
+
.getFunction("transferFrom(address,address,((uint256,uint256),bytes))")(
|
|
388
|
+
owner.address,
|
|
389
|
+
otherAccount.address,
|
|
390
|
+
itValue,
|
|
391
|
+
txOpts
|
|
392
|
+
)
|
|
393
|
+
|
|
349
394
|
await tx.wait()
|
|
350
395
|
})
|
|
351
396
|
|
|
352
|
-
it(
|
|
397
|
+
it("decrements the owners balance", async function () {
|
|
353
398
|
const ctBalance = await contract["balanceOf(address)"](owner.address)
|
|
354
399
|
|
|
355
|
-
const balance =
|
|
356
|
-
|
|
400
|
+
const balance = decryptCtUint256(owner, ctBalance)
|
|
401
|
+
|
|
357
402
|
await expect(balance).to.equal(2000n)
|
|
358
403
|
})
|
|
359
404
|
|
|
360
|
-
it(
|
|
405
|
+
it("increments the recipients balance", async function () {
|
|
361
406
|
const ctBalance = await contract["balanceOf(address)"](otherAccount.address)
|
|
362
407
|
|
|
363
|
-
const balance =
|
|
364
|
-
|
|
408
|
+
const balance = decryptCtUint256(otherAccount, ctBalance)
|
|
409
|
+
|
|
365
410
|
await expect(balance).to.equal(8000n)
|
|
366
411
|
})
|
|
367
412
|
|
|
368
|
-
it(
|
|
413
|
+
it("decrements the spenders allowance", async function () {
|
|
369
414
|
const ctAllowance = await contract["allowance(address,address)"](owner.address, otherAccount.address)
|
|
370
415
|
|
|
371
|
-
const allowance =
|
|
372
|
-
|
|
416
|
+
const allowance = decryptCtUint256(otherAccount, ctAllowance.spenderCiphertext)
|
|
417
|
+
|
|
373
418
|
await expect(allowance).to.equal(2000n)
|
|
374
419
|
})
|
|
375
420
|
})
|
|
@@ -383,164 +428,960 @@ describe("Private ERC20", function () {
|
|
|
383
428
|
before("deploying and funding wallet contract", async function () {
|
|
384
429
|
const walletContractFactory = await hre.ethers.getContractFactory("PrivateERC20WalletMock")
|
|
385
430
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
walletContract = await walletContract.waitForDeployment()
|
|
431
|
+
const w = await walletContractFactory.connect(owner).deploy(txOpts)
|
|
432
|
+
await w.waitForDeployment()
|
|
433
|
+
walletContract = w as unknown as PrivateERC20WalletMock
|
|
391
434
|
|
|
392
435
|
walletContractAddress = await walletContract.getAddress()
|
|
393
436
|
|
|
394
|
-
|
|
395
|
-
.connect(owner)
|
|
396
|
-
.mint(walletContractAddress, value, { gasLimit: GAS_LIMIT })
|
|
397
|
-
|
|
398
|
-
await this.tx.wait()
|
|
437
|
+
await mintPublic(contract, owner, walletContractAddress, value).then((t) => t.wait())
|
|
399
438
|
})
|
|
400
439
|
|
|
401
|
-
describe("setAccountEncryptionAddress",
|
|
440
|
+
describe("setAccountEncryptionAddress", function () {
|
|
402
441
|
before("setting account encryption address", async function () {
|
|
403
442
|
const tx = await walletContract
|
|
404
443
|
.connect(otherAccount)
|
|
405
|
-
.setAccountEncryptionAddress(contractAddress, otherAccount.address,
|
|
406
|
-
|
|
444
|
+
.setAccountEncryptionAddress(contractAddress, otherAccount.address, txOpts)
|
|
445
|
+
|
|
407
446
|
await tx.wait()
|
|
408
447
|
})
|
|
409
448
|
|
|
410
|
-
it("
|
|
449
|
+
it("updates accountEncryptionAddress mapping", async function () {
|
|
411
450
|
const accountEncryptionAddress = await contract.accountEncryptionAddress(walletContractAddress)
|
|
412
|
-
|
|
451
|
+
|
|
413
452
|
await expect(accountEncryptionAddress).to.equal(otherAccount.address)
|
|
414
453
|
})
|
|
415
454
|
|
|
416
|
-
it("
|
|
455
|
+
it("reencrypts balance for the new encryption address", async function () {
|
|
417
456
|
const ctBalance = await contract["balanceOf(address)"](walletContractAddress)
|
|
418
457
|
|
|
419
|
-
const balance =
|
|
458
|
+
const balance = decryptCtUint256(otherAccount, ctBalance)
|
|
420
459
|
|
|
421
460
|
await expect(balance).to.equal(value)
|
|
422
461
|
})
|
|
423
462
|
})
|
|
424
463
|
|
|
425
|
-
describe("transfer",
|
|
464
|
+
describe("transfer via wallet", function () {
|
|
465
|
+
let otherBalanceBeforeWalletTransfer = 0n
|
|
466
|
+
|
|
426
467
|
before("transferring", async function () {
|
|
468
|
+
const ctBefore = await contract["balanceOf(address)"](otherAccount.address)
|
|
469
|
+
otherBalanceBeforeWalletTransfer = decryptCtUint256(otherAccount, ctBefore)
|
|
470
|
+
|
|
427
471
|
const tx = await walletContract
|
|
428
472
|
.connect(otherAccount)
|
|
429
|
-
.transfer(contractAddress, otherAccount.address, value / 2n,
|
|
430
|
-
|
|
473
|
+
.transfer(contractAddress, otherAccount.address, value / 2n, txOpts)
|
|
474
|
+
|
|
431
475
|
await tx.wait()
|
|
432
476
|
})
|
|
433
477
|
|
|
434
|
-
it(
|
|
478
|
+
it("decrements the wallet balance", async function () {
|
|
435
479
|
const ctBalance = await contract["balanceOf(address)"](walletContractAddress)
|
|
436
480
|
|
|
437
|
-
const balance =
|
|
481
|
+
const balance = decryptCtUint256(otherAccount, ctBalance)
|
|
438
482
|
|
|
439
483
|
await expect(balance).to.equal(value / 2n)
|
|
440
484
|
})
|
|
441
485
|
|
|
442
|
-
it(
|
|
486
|
+
it("increments the receiver balance", async function () {
|
|
443
487
|
const ctBalance = await contract["balanceOf(address)"](otherAccount.address)
|
|
444
488
|
|
|
445
|
-
const balance =
|
|
489
|
+
const balance = decryptCtUint256(otherAccount, ctBalance)
|
|
446
490
|
|
|
447
|
-
await expect(balance).to.equal(
|
|
491
|
+
await expect(balance).to.equal(otherBalanceBeforeWalletTransfer + value / 2n)
|
|
448
492
|
})
|
|
449
493
|
})
|
|
450
494
|
|
|
451
|
-
describe("approve",
|
|
495
|
+
describe("approve via wallet", function () {
|
|
452
496
|
before("approving", async function () {
|
|
453
497
|
const tx = await walletContract
|
|
454
498
|
.connect(otherAccount)
|
|
455
|
-
.approve(contractAddress, owner.address, value / 2n,
|
|
456
|
-
|
|
499
|
+
.approve(contractAddress, owner.address, value / 2n, txOpts)
|
|
500
|
+
|
|
457
501
|
await tx.wait()
|
|
458
502
|
})
|
|
459
503
|
|
|
460
|
-
it("
|
|
504
|
+
it("sets allowance for wallet owner/spender pair", async function () {
|
|
461
505
|
const ctAllowance = await contract["allowance(address,address)"](walletContractAddress, owner.address)
|
|
462
506
|
|
|
463
|
-
const allowance =
|
|
507
|
+
const allowance = decryptCtUint256(otherAccount, ctAllowance.ownerCiphertext)
|
|
464
508
|
|
|
465
509
|
await expect(allowance).to.equal(value / 2n)
|
|
466
510
|
})
|
|
467
511
|
})
|
|
512
|
+
})
|
|
468
513
|
|
|
469
|
-
|
|
470
|
-
|
|
514
|
+
describe("maximum allowance", function () {
|
|
515
|
+
const value = 2n ** 256n - 1n
|
|
516
|
+
let ownerBalanceBeforeMaxTransfer = 0n
|
|
517
|
+
let maxAllowanceTransferFromReceipt: any
|
|
518
|
+
|
|
519
|
+
before("approve max and transferFrom", async function () {
|
|
520
|
+
let ct = await contract["balanceOf(address)"](owner.address)
|
|
521
|
+
ownerBalanceBeforeMaxTransfer = decryptCtUint256(owner, ct)
|
|
522
|
+
const need = 7000n
|
|
523
|
+
if (ownerBalanceBeforeMaxTransfer < need) {
|
|
524
|
+
await mintPublic(contract, owner, owner.address, need - ownerBalanceBeforeMaxTransfer).then((t) =>
|
|
525
|
+
t.wait()
|
|
526
|
+
)
|
|
527
|
+
ct = await contract["balanceOf(address)"](owner.address)
|
|
528
|
+
ownerBalanceBeforeMaxTransfer = decryptCtUint256(owner, ct)
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
await contract
|
|
532
|
+
.connect(owner)
|
|
533
|
+
.getFunction("approve(address,uint256)")(otherAccount.address, 0n, txOpts)
|
|
534
|
+
.then((t) => t.wait())
|
|
471
535
|
|
|
472
|
-
|
|
473
|
-
|
|
536
|
+
const itMax = (await encryptItUint256(owner,
|
|
537
|
+
value,
|
|
538
|
+
contractAddress,
|
|
539
|
+
contract.interface.getFunction("approve(address,((uint256,uint256),bytes))").selector
|
|
540
|
+
)) as itUint256
|
|
474
541
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
(walletContractAddress, itValue)
|
|
479
|
-
|
|
480
|
-
await tx.wait()
|
|
542
|
+
let tx = await contract
|
|
543
|
+
.connect(owner)
|
|
544
|
+
.getFunction("approve(address,((uint256,uint256),bytes))")(otherAccount.address, itMax, txOpts)
|
|
481
545
|
|
|
482
|
-
|
|
483
|
-
.connect(otherAccount)
|
|
484
|
-
.transferFrom(contractAddress, otherAccount.address, owner.address, value)
|
|
485
|
-
|
|
486
|
-
await tx.wait()
|
|
487
|
-
})
|
|
546
|
+
await tx.wait()
|
|
488
547
|
|
|
489
|
-
|
|
490
|
-
|
|
548
|
+
const itValue = (await encryptItUint256(otherAccount,
|
|
549
|
+
7000n,
|
|
550
|
+
contractAddress,
|
|
551
|
+
contract.interface.getFunction("transferFrom(address,address,((uint256,uint256),bytes))").selector
|
|
552
|
+
)) as itUint256
|
|
491
553
|
|
|
492
|
-
|
|
554
|
+
tx = await contract
|
|
555
|
+
.connect(otherAccount)
|
|
556
|
+
.getFunction("transferFrom(address,address,((uint256,uint256),bytes))")(
|
|
557
|
+
owner.address,
|
|
558
|
+
"0x0000000000000000000000000000000000000001",
|
|
559
|
+
itValue,
|
|
560
|
+
txOpts
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
maxAllowanceTransferFromReceipt = await tx.wait()
|
|
564
|
+
})
|
|
493
565
|
|
|
494
|
-
|
|
495
|
-
|
|
566
|
+
it("reduces owner balance but not unlimited allowance", async function () {
|
|
567
|
+
const ctBalance = await contract["balanceOf(address)"](owner.address)
|
|
496
568
|
|
|
497
|
-
|
|
498
|
-
const itBalance = await contract["balanceOf(address)"](owner.address)
|
|
569
|
+
const balance = decryptCtUint256(owner, ctBalance)
|
|
499
570
|
|
|
500
|
-
|
|
571
|
+
await expect(balance).to.equal(ownerBalanceBeforeMaxTransfer - 7000n)
|
|
572
|
+
})
|
|
501
573
|
|
|
502
|
-
|
|
503
|
-
|
|
574
|
+
it("keeps max allowance for spender", async function () {
|
|
575
|
+
const ctAllowance = await contract["allowance(address,address)"](owner.address, otherAccount.address)
|
|
576
|
+
|
|
577
|
+
const allowance = decryptCtUint256(owner, ctAllowance.ownerCiphertext)
|
|
578
|
+
|
|
579
|
+
await expect(allowance).to.equal(value)
|
|
580
|
+
})
|
|
581
|
+
|
|
582
|
+
it("does not emit Approval on spend when allowance is unlimited", async function () {
|
|
583
|
+
const approvalEv = contract.interface.getEvent("Approval")
|
|
584
|
+
const approvalTopic = approvalEv.topicHash
|
|
585
|
+
const hasApproval = maxAllowanceTransferFromReceipt.logs.some((l: any) => l.topics?.[0] === approvalTopic)
|
|
586
|
+
await expect(hasApproval).to.equal(false)
|
|
504
587
|
})
|
|
505
588
|
})
|
|
506
589
|
|
|
507
|
-
describe("
|
|
508
|
-
|
|
590
|
+
describe("supplyCap boundaries (capped token)", function () {
|
|
591
|
+
it("enforces cap for public and encrypted mint", async function () {
|
|
592
|
+
const [capOwner] = await setupAccounts()
|
|
593
|
+
const cappedFactory = await hre.ethers.getContractFactory("PrivateERC20CappedMock")
|
|
594
|
+
const capped = await cappedFactory.connect(capOwner).deploy(1000n, txOpts)
|
|
595
|
+
await capped.waitForDeployment()
|
|
596
|
+
const cappedAddr = await capped.getAddress()
|
|
597
|
+
|
|
598
|
+
// grant MINTER_ROLE for both mint overloads
|
|
599
|
+
const minterRole = await (capped as any).MINTER_ROLE()
|
|
600
|
+
await (await (capped as any).grantRole(minterRole, capOwner.address, txOpts)).wait()
|
|
601
|
+
|
|
602
|
+
// public mint within cap
|
|
603
|
+
await (await capped.connect(capOwner).getFunction("mint(address,uint256)")(capOwner.address, 1000n, txOpts)).wait()
|
|
604
|
+
// public mint above cap
|
|
605
|
+
await expectTxFails(
|
|
606
|
+
capped.connect(capOwner).getFunction("mint(address,uint256)")(capOwner.address, 1n, txOpts)
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
// encrypted mint within remaining (cap already full, so minting any more should fail)
|
|
610
|
+
const itOne = (await encryptItUint256(
|
|
611
|
+
capOwner,
|
|
612
|
+
1n,
|
|
613
|
+
cappedAddr,
|
|
614
|
+
(capped.interface.getFunction("mint(address,((uint256,uint256),bytes))") as any).selector
|
|
615
|
+
)) as itUint256
|
|
616
|
+
await expectTxFails(
|
|
617
|
+
capped.connect(capOwner).getFunction("mint(address,((uint256,uint256),bytes))")(capOwner.address, itOne, txOpts)
|
|
618
|
+
)
|
|
619
|
+
})
|
|
620
|
+
})
|
|
509
621
|
|
|
510
|
-
|
|
511
|
-
|
|
622
|
+
describe("increaseAllowance and decreaseAllowance", function () {
|
|
623
|
+
let localContract: PrivateERC20Mock
|
|
624
|
+
let localAddress: string
|
|
625
|
+
let localOwner: Wallet
|
|
626
|
+
let localOther: Wallet
|
|
627
|
+
|
|
628
|
+
before(async function () {
|
|
629
|
+
const deployment = await deploy()
|
|
630
|
+
localContract = deployment.contract
|
|
631
|
+
localAddress = deployment.contractAddress
|
|
632
|
+
localOwner = deployment.owner
|
|
633
|
+
localOther = deployment.otherAccount
|
|
634
|
+
await mintPublic(localContract, localOwner, localOwner.address, 100000n).then((t) => t.wait())
|
|
635
|
+
})
|
|
512
636
|
|
|
513
|
-
|
|
637
|
+
it("increases allowance from zero", async function () {
|
|
638
|
+
const add = 1234n
|
|
639
|
+
await localContract
|
|
640
|
+
.connect(localOwner)
|
|
641
|
+
.getFunction("increaseAllowance(address,uint256)")(localOther.address, add, txOpts)
|
|
642
|
+
.then((t) => t.wait())
|
|
643
|
+
const ctAllowance = await localContract["allowance(address,address)"](localOwner.address, localOther.address)
|
|
644
|
+
const allowance = decryptCtUint256(localOwner, ctAllowance.ownerCiphertext)
|
|
645
|
+
await expect(allowance).to.equal(add)
|
|
646
|
+
})
|
|
647
|
+
|
|
648
|
+
it("decreases allowance", async function () {
|
|
649
|
+
const sub = 234n
|
|
650
|
+
await localContract
|
|
651
|
+
.connect(localOwner)
|
|
652
|
+
.getFunction("decreaseAllowance(address,uint256)")(localOther.address, sub, txOpts)
|
|
653
|
+
.then((t) => t.wait())
|
|
654
|
+
const ctAllowance = await localContract["allowance(address,address)"](localOwner.address, localOther.address)
|
|
655
|
+
const allowance = decryptCtUint256(localOwner, ctAllowance.ownerCiphertext)
|
|
656
|
+
await expect(allowance).to.equal(1234n - 234n)
|
|
657
|
+
})
|
|
658
|
+
|
|
659
|
+
it("reverts decrease when allowance is insufficient", async function () {
|
|
660
|
+
await expectTxFails(
|
|
661
|
+
localContract
|
|
662
|
+
.connect(localOwner)
|
|
663
|
+
.getFunction("decreaseAllowance(address,uint256)")(localOther.address, 100000n, txOpts)
|
|
664
|
+
)
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
it("reverts increaseAllowance when addition overflows uint256", async function () {
|
|
668
|
+
const max = 2n ** 256n - 1n
|
|
669
|
+
await localContract
|
|
670
|
+
.connect(localOwner)
|
|
671
|
+
.getFunction("approve(address,uint256)")(localOther.address, 0n, txOpts)
|
|
672
|
+
.then((t) => t.wait())
|
|
673
|
+
|
|
674
|
+
const itMax = (await encryptItUint256(localOwner,
|
|
675
|
+
max,
|
|
676
|
+
localAddress,
|
|
677
|
+
localContract.interface.getFunction("approve(address,((uint256,uint256),bytes))").selector
|
|
678
|
+
)) as itUint256
|
|
679
|
+
|
|
680
|
+
await localContract
|
|
681
|
+
.connect(localOwner)
|
|
682
|
+
.getFunction("approve(address,((uint256,uint256),bytes))")(localOther.address, itMax, txOpts)
|
|
683
|
+
.then((t) => t.wait())
|
|
684
|
+
|
|
685
|
+
await expectTxFails(
|
|
686
|
+
localContract
|
|
687
|
+
.connect(localOwner)
|
|
688
|
+
.getFunction("increaseAllowance(address,uint256)")(localOther.address, 1n, txOpts)
|
|
689
|
+
)
|
|
690
|
+
})
|
|
691
|
+
})
|
|
692
|
+
|
|
693
|
+
describe("publicAmountsDisabled", function () {
|
|
694
|
+
let c: PrivateERC20Mock
|
|
695
|
+
let o: Wallet
|
|
696
|
+
|
|
697
|
+
before(async function () {
|
|
698
|
+
const d = await deploy()
|
|
699
|
+
c = d.contract
|
|
700
|
+
o = d.owner
|
|
701
|
+
await mintPublic(c, o, o.address, 1000n).then((t) => t.wait())
|
|
702
|
+
await c.connect(o).setPublicAmountsEnabled(false).then((t) => t.wait())
|
|
703
|
+
})
|
|
704
|
+
|
|
705
|
+
it("reverts public transfer", async function () {
|
|
706
|
+
await expect(
|
|
707
|
+
c.connect(o).getFunction("transfer(address,uint256)").staticCall(otherAccount.address, 1n)
|
|
708
|
+
).to.be.revertedWithCustomError(c, "PublicAmountsDisabled")
|
|
709
|
+
})
|
|
710
|
+
|
|
711
|
+
it("reverts public approve/increase/decrease/transferFrom/burn/transferAndCall", async function () {
|
|
712
|
+
await expect(
|
|
713
|
+
c.connect(o).getFunction("approve(address,uint256)").staticCall(otherAccount.address, 1n)
|
|
714
|
+
).to.be.revertedWithCustomError(c, "PublicAmountsDisabled")
|
|
715
|
+
|
|
716
|
+
await expect(
|
|
717
|
+
c.connect(o).getFunction("increaseAllowance(address,uint256)").staticCall(otherAccount.address, 1n)
|
|
718
|
+
).to.be.revertedWithCustomError(c, "PublicAmountsDisabled")
|
|
719
|
+
|
|
720
|
+
await expect(
|
|
721
|
+
c.connect(o).getFunction("decreaseAllowance(address,uint256)").staticCall(otherAccount.address, 1n)
|
|
722
|
+
).to.be.revertedWithCustomError(c, "PublicAmountsDisabled")
|
|
723
|
+
|
|
724
|
+
await expect(
|
|
725
|
+
c.connect(o)
|
|
726
|
+
.getFunction("transferFrom(address,address,uint256)")
|
|
727
|
+
.staticCall(o.address, otherAccount.address, 1n)
|
|
728
|
+
).to.be.revertedWithCustomError(c, "PublicAmountsDisabled")
|
|
729
|
+
|
|
730
|
+
await expect(
|
|
731
|
+
c.connect(o).getFunction("burn(uint256)").staticCall(1n)
|
|
732
|
+
).to.be.revertedWithCustomError(c, "PublicAmountsDisabled")
|
|
733
|
+
|
|
734
|
+
// transferAndCall(public) also blocked
|
|
735
|
+
const recvFactory = await hre.ethers.getContractFactory("PublicTokenReceiverMock")
|
|
736
|
+
const recv = await recvFactory.connect(o).deploy(txOpts)
|
|
737
|
+
await recv.waitForDeployment()
|
|
738
|
+
await expect(
|
|
739
|
+
c.connect(o)
|
|
740
|
+
.getFunction("transferAndCall(address,uint256,bytes)")
|
|
741
|
+
.staticCall(await recv.getAddress(), 1n, "0x")
|
|
742
|
+
).to.be.revertedWithCustomError(c, "PublicAmountsDisabled")
|
|
743
|
+
})
|
|
744
|
+
|
|
745
|
+
after(async function () {
|
|
746
|
+
await c.connect(o).setPublicAmountsEnabled(true).then((t) => t.wait())
|
|
747
|
+
})
|
|
748
|
+
})
|
|
749
|
+
|
|
750
|
+
describe("transferAndCall reentrancy (encrypted)", function () {
|
|
751
|
+
it("prevents receiver callback re-entering token", async function () {
|
|
752
|
+
const d = await deploy()
|
|
753
|
+
const t = d.contract
|
|
754
|
+
const tAddr = d.contractAddress
|
|
755
|
+
const o = d.owner
|
|
756
|
+
const other = d.otherAccount
|
|
757
|
+
|
|
758
|
+
// fund owner
|
|
759
|
+
await mintPublic(t, o, o.address, 1000n).then((x) => x.wait())
|
|
760
|
+
|
|
761
|
+
const receiverFactory = await hre.ethers.getContractFactory("PrivateERC20ReentrantReceiverMock")
|
|
762
|
+
const receiver = await receiverFactory.connect(o).deploy(txOpts)
|
|
763
|
+
await receiver.waitForDeployment()
|
|
764
|
+
const receiverAddr = await receiver.getAddress()
|
|
765
|
+
|
|
766
|
+
// configure callback to attempt re-entry into approve(uint256)
|
|
767
|
+
const reenterData = t.interface.encodeFunctionData("approve(address,uint256)", [other.address, 1n])
|
|
768
|
+
await (await (receiver as any).configure(tAddr, true, reenterData, txOpts)).wait()
|
|
769
|
+
|
|
770
|
+
const itAmount = (await encryptItUint256(
|
|
771
|
+
o,
|
|
772
|
+
1n,
|
|
773
|
+
tAddr,
|
|
774
|
+
t.interface.getFunction("transferAndCall(address,((uint256,uint256),bytes),bytes)").selector
|
|
775
|
+
)) as itUint256
|
|
776
|
+
|
|
777
|
+
await expectTxFails(
|
|
778
|
+
t.connect(o)
|
|
779
|
+
.getFunction("transferAndCall(address,((uint256,uint256),bytes),bytes)")(receiverAddr, itAmount, "0x", txOpts)
|
|
780
|
+
)
|
|
781
|
+
})
|
|
782
|
+
})
|
|
783
|
+
|
|
784
|
+
describe("more edge cases (fresh deploy)", function () {
|
|
785
|
+
let c: PrivateERC20Mock
|
|
786
|
+
let addr: string
|
|
787
|
+
let o: Wallet
|
|
788
|
+
let other: Wallet
|
|
789
|
+
|
|
790
|
+
before(async function () {
|
|
791
|
+
const d = await deploy()
|
|
792
|
+
c = d.contract
|
|
793
|
+
addr = d.contractAddress
|
|
794
|
+
o = d.owner
|
|
795
|
+
other = d.otherAccount
|
|
796
|
+
await mintPublic(c, o, o.address, 1000n).then((t) => t.wait())
|
|
797
|
+
})
|
|
798
|
+
|
|
799
|
+
it("public transfer exact balance moves all tokens", async function () {
|
|
800
|
+
const amount = 1000n
|
|
801
|
+
await (await c.connect(o).getFunction("transfer(address,uint256)")(other.address, amount, txOpts)).wait()
|
|
802
|
+
await expect(decryptCtUint256(o, await c["balanceOf(address)"](o.address))).to.equal(0n)
|
|
803
|
+
await expect(decryptCtUint256(other, await c["balanceOf(address)"](other.address))).to.equal(amount)
|
|
804
|
+
})
|
|
805
|
+
|
|
806
|
+
it("public transferFrom exact allowance reduces allowance to zero", async function () {
|
|
807
|
+
// reset: mint back to owner
|
|
808
|
+
await mintPublic(c, o, o.address, 500n).then((t) => t.wait())
|
|
809
|
+
await (await c.connect(o).getFunction("approve(address,uint256)")(other.address, 123n, txOpts)).wait()
|
|
810
|
+
|
|
811
|
+
await (await c.connect(other).getFunction("transferFrom(address,address,uint256)")(o.address, other.address, 123n, txOpts)).wait()
|
|
812
|
+
|
|
813
|
+
const a = await c["allowance(address,address)"](o.address, other.address)
|
|
814
|
+
await expect(decryptCtUint256(other, a.spenderCiphertext)).to.equal(0n)
|
|
815
|
+
})
|
|
816
|
+
|
|
817
|
+
it("public approve is unsafe when current allowance non-zero", async function () {
|
|
818
|
+
await (await c.connect(o).getFunction("approve(address,uint256)")(other.address, 10n, txOpts)).wait()
|
|
819
|
+
await expectTxFails(c.connect(o).getFunction("approve(address,uint256)")(other.address, 11n, txOpts))
|
|
820
|
+
})
|
|
821
|
+
|
|
822
|
+
it("public transferFrom with from==to reverts (self-transfer)", async function () {
|
|
823
|
+
// clear any prior allowance set by earlier tests in this block
|
|
824
|
+
await (await c.connect(o).getFunction("approve(address,uint256)")(other.address, 0n, txOpts)).wait()
|
|
825
|
+
await (await c.connect(o).getFunction("approve(address,uint256)")(other.address, 1n, txOpts)).wait()
|
|
826
|
+
await expectTxFails(
|
|
827
|
+
c.connect(other).getFunction("transferFrom(address,address,uint256)")(o.address, o.address, 1n, txOpts)
|
|
828
|
+
)
|
|
829
|
+
})
|
|
830
|
+
|
|
831
|
+
it("encrypted approve(0) is NOT a safe reset when current allowance non-zero", async function () {
|
|
832
|
+
// set non-zero allowance first
|
|
833
|
+
await (await c.connect(o).getFunction("approve(address,uint256)")(other.address, 0n, txOpts)).wait()
|
|
834
|
+
await (await c.connect(o).getFunction("approve(address,uint256)")(other.address, 55n, txOpts)).wait()
|
|
835
|
+
|
|
836
|
+
const itZero = (await encryptItUint256(
|
|
837
|
+
o,
|
|
838
|
+
0n,
|
|
839
|
+
addr,
|
|
840
|
+
c.interface.getFunction("approve(address,((uint256,uint256),bytes))").selector
|
|
841
|
+
)) as itUint256
|
|
842
|
+
|
|
843
|
+
// Contract treats "new allowance is zero" via MPC equality; depending on MPC encoding,
|
|
844
|
+
// an encrypted-zero may not compare equal to public zero, so this may still hit ERC20UnsafeApprove.
|
|
845
|
+
await expectTxFails(
|
|
846
|
+
c.connect(o)
|
|
847
|
+
.getFunction("approve(address,((uint256,uint256),bytes))")(other.address, itZero, txOpts)
|
|
848
|
+
)
|
|
849
|
+
})
|
|
850
|
+
|
|
851
|
+
it("transferAndCall(public) checks receiver must be contract (before PublicAmountsDisabled)", async function () {
|
|
852
|
+
await (await c.connect(o).setPublicAmountsEnabled(false).then((t) => t.wait()))
|
|
853
|
+
// EOA receiver => should hit TransferAndCallRequiresContract first
|
|
854
|
+
await expect(
|
|
855
|
+
c.connect(o).getFunction("transferAndCall(address,uint256,bytes)").staticCall(other.address, 1n, "0x")
|
|
856
|
+
).to.be.revertedWithCustomError(c, "TransferAndCallRequiresContract")
|
|
857
|
+
})
|
|
858
|
+
|
|
859
|
+
it("accountEncryptionAddress(0) and allowance(address,bool) with zero address revert", async function () {
|
|
860
|
+
await expect(c.accountEncryptionAddress(ZeroAddress)).to.be.revertedWithCustomError(c, "ERC20InvalidReceiver")
|
|
861
|
+
await expect(
|
|
862
|
+
c.connect(o).getFunction("allowance(address,bool)").staticCall(ZeroAddress, true)
|
|
863
|
+
).to.be.revertedWithCustomError(c, "ERC20InvalidReceiver")
|
|
864
|
+
})
|
|
865
|
+
})
|
|
866
|
+
|
|
867
|
+
describe("transferAndCall reentrancy (public)", function () {
|
|
868
|
+
it("prevents receiver callback re-entering token", async function () {
|
|
869
|
+
const d = await deploy()
|
|
870
|
+
const t = d.contract
|
|
871
|
+
const tAddr = d.contractAddress
|
|
872
|
+
const o = d.owner
|
|
873
|
+
const other = d.otherAccount
|
|
874
|
+
|
|
875
|
+
await mintPublic(t, o, o.address, 1000n).then((x) => x.wait())
|
|
876
|
+
|
|
877
|
+
const recvFactory = await hre.ethers.getContractFactory("PublicReentrantTokenReceiverMock")
|
|
878
|
+
const recv = await recvFactory.connect(o).deploy(txOpts)
|
|
879
|
+
await recv.waitForDeployment()
|
|
880
|
+
const recvAddr = await recv.getAddress()
|
|
881
|
+
|
|
882
|
+
// ensure public ops enabled for this test
|
|
883
|
+
await (await t.connect(o).setPublicAmountsEnabled(true).then((x) => x.wait()))
|
|
884
|
+
|
|
885
|
+
const reenterData = t.interface.encodeFunctionData("approve(address,uint256)", [other.address, 1n])
|
|
886
|
+
await (await (recv as any).configure(tAddr, true, reenterData, txOpts)).wait()
|
|
887
|
+
|
|
888
|
+
await expectTxFails(
|
|
889
|
+
t.connect(o).getFunction("transferAndCall(address,uint256,bytes)")(recvAddr, 1n, "0x", txOpts)
|
|
890
|
+
)
|
|
891
|
+
})
|
|
892
|
+
})
|
|
893
|
+
|
|
894
|
+
describe("missing branches: GT overloads + transferAndCall success/failure", function () {
|
|
895
|
+
it("covers transferAndCall(public) success and callback-false failure", async function () {
|
|
896
|
+
const d = await deploy()
|
|
897
|
+
const t = d.contract
|
|
898
|
+
const o = d.owner
|
|
899
|
+
|
|
900
|
+
await mintPublic(t, o, o.address, 10n).then((x) => x.wait())
|
|
901
|
+
|
|
902
|
+
const okRecvF = await hre.ethers.getContractFactory("PublicTokenReceiverBoolMock")
|
|
903
|
+
const okRecv = await okRecvF.connect(o).deploy(true, txOpts)
|
|
904
|
+
await okRecv.waitForDeployment()
|
|
905
|
+
|
|
906
|
+
const badRecv = await okRecvF.connect(o).deploy(false, txOpts)
|
|
907
|
+
await badRecv.waitForDeployment()
|
|
908
|
+
|
|
909
|
+
await (await t.connect(o).getFunction("transferAndCall(address,uint256,bytes)")(await okRecv.getAddress(), 1n, "0x", txOpts)).wait()
|
|
910
|
+
await expectTxFails(
|
|
911
|
+
t.connect(o).getFunction("transferAndCall(address,uint256,bytes)")(await badRecv.getAddress(), 1n, "0x", txOpts)
|
|
912
|
+
)
|
|
913
|
+
})
|
|
914
|
+
|
|
915
|
+
it("covers transferAndCall(encrypted) success and callback-false failure", async function () {
|
|
916
|
+
const d = await deploy()
|
|
917
|
+
const t = d.contract
|
|
918
|
+
const tAddr = d.contractAddress
|
|
919
|
+
const o = d.owner
|
|
920
|
+
|
|
921
|
+
await mintPublic(t, o, o.address, 10n).then((x) => x.wait())
|
|
922
|
+
|
|
923
|
+
const recvF = await hre.ethers.getContractFactory("EncryptedTokenReceiverMock")
|
|
924
|
+
const okRecv = await recvF.connect(o).deploy(true, txOpts)
|
|
925
|
+
await okRecv.waitForDeployment()
|
|
926
|
+
const badRecv = await recvF.connect(o).deploy(false, txOpts)
|
|
927
|
+
await badRecv.waitForDeployment()
|
|
928
|
+
|
|
929
|
+
const itAmt = (await encryptItUint256(
|
|
930
|
+
o,
|
|
931
|
+
1n,
|
|
932
|
+
tAddr,
|
|
933
|
+
t.interface.getFunction("transferAndCall(address,((uint256,uint256),bytes),bytes)").selector
|
|
934
|
+
)) as itUint256
|
|
935
|
+
|
|
936
|
+
await (await t.connect(o).getFunction("transferAndCall(address,((uint256,uint256),bytes),bytes)")(await okRecv.getAddress(), itAmt, "0x", txOpts)).wait()
|
|
937
|
+
await expectTxFails(
|
|
938
|
+
t.connect(o).getFunction("transferAndCall(address,((uint256,uint256),bytes),bytes)")(await badRecv.getAddress(), itAmt, "0x", txOpts)
|
|
939
|
+
)
|
|
940
|
+
})
|
|
941
|
+
|
|
942
|
+
it("covers GT entrypoints via helper contract", async function () {
|
|
943
|
+
const d = await deploy()
|
|
944
|
+
const t = d.contract
|
|
945
|
+
const tAddr = d.contractAddress
|
|
946
|
+
const o = d.owner
|
|
947
|
+
const other = d.otherAccount
|
|
948
|
+
|
|
949
|
+
await mintPublic(t, o, o.address, 1000n).then((x) => x.wait())
|
|
950
|
+
|
|
951
|
+
const callerF = await hre.ethers.getContractFactory("PrivateERC20GtCallerMock")
|
|
952
|
+
const caller = await callerF.connect(o).deploy(txOpts)
|
|
953
|
+
await caller.waitForDeployment()
|
|
954
|
+
const callerAddr = await caller.getAddress()
|
|
955
|
+
|
|
956
|
+
// fund caller so it can burnGt and transferGT as msg.sender
|
|
957
|
+
await (await t.connect(o).getFunction("transfer(address,uint256)")(callerAddr, 10n, txOpts)).wait()
|
|
958
|
+
|
|
959
|
+
// transferGT from caller to other
|
|
960
|
+
await (await (caller as any).transferGT(tAddr, other.address, 1n, txOpts)).wait()
|
|
961
|
+
await expect(decryptCtUint256(other, await t["balanceOf(address)"](other.address))).to.be.greaterThan(0n)
|
|
962
|
+
|
|
963
|
+
// approveGT from caller (owner=caller) to itself (spender=caller), then transferFromGT (spender=caller)
|
|
964
|
+
await (await (caller as any).approveGT(tAddr, callerAddr, 5n, txOpts)).wait()
|
|
965
|
+
await (await (caller as any).transferFromGT(tAddr, callerAddr, other.address, 2n, txOpts)).wait()
|
|
966
|
+
|
|
967
|
+
// burnGt from caller
|
|
968
|
+
await (await (caller as any).burnGt(tAddr, 1n, txOpts)).wait()
|
|
969
|
+
})
|
|
970
|
+
})
|
|
971
|
+
|
|
972
|
+
describe("reencryptAllowance event", function () {
|
|
973
|
+
it("emits AllowanceReencrypted", async function () {
|
|
974
|
+
await contract
|
|
514
975
|
.connect(owner)
|
|
515
|
-
|
|
516
|
-
(
|
|
517
|
-
|
|
518
|
-
await tx.wait()
|
|
976
|
+
.getFunction("approve(address,uint256)")(otherAccount.address, 0n, txOpts)
|
|
977
|
+
.then((t) => t.wait())
|
|
519
978
|
|
|
520
|
-
|
|
979
|
+
const it42 = (await encryptItUint256(owner,
|
|
980
|
+
42n,
|
|
981
|
+
contractAddress,
|
|
982
|
+
contract.interface.getFunction("approve(address,((uint256,uint256),bytes))").selector
|
|
983
|
+
)) as itUint256
|
|
521
984
|
|
|
522
|
-
|
|
523
|
-
.connect(
|
|
524
|
-
|
|
525
|
-
(
|
|
526
|
-
|
|
527
|
-
await
|
|
985
|
+
await contract
|
|
986
|
+
.connect(owner)
|
|
987
|
+
.getFunction("approve(address,((uint256,uint256),bytes))")(otherAccount.address, it42, txOpts)
|
|
988
|
+
.then((t) => t.wait())
|
|
989
|
+
|
|
990
|
+
const txResp = await contract.connect(owner).reencryptAllowance(otherAccount.address, false, txOpts)
|
|
991
|
+
const receipt = await txResp.wait()
|
|
992
|
+
expect(receipt).to.not.be.null
|
|
993
|
+
expect(receipt!.status).to.equal(1)
|
|
994
|
+
const ev = contract.interface.getEvent("AllowanceReencrypted")
|
|
995
|
+
expect(receipt!.logs.some((l) => l.topics[0] === ev.topicHash)).to.equal(true)
|
|
528
996
|
})
|
|
997
|
+
})
|
|
529
998
|
|
|
530
|
-
|
|
531
|
-
|
|
999
|
+
describe("encrypted edge cases (fresh deploy)", function () {
|
|
1000
|
+
let c: PrivateERC20Mock
|
|
1001
|
+
let addr: string
|
|
1002
|
+
let o: Wallet
|
|
1003
|
+
let other: Wallet
|
|
532
1004
|
|
|
533
|
-
|
|
1005
|
+
before(async function () {
|
|
1006
|
+
const d = await deploy()
|
|
1007
|
+
c = d.contract
|
|
1008
|
+
addr = d.contractAddress
|
|
1009
|
+
o = d.owner
|
|
1010
|
+
other = d.otherAccount
|
|
534
1011
|
|
|
535
|
-
await
|
|
1012
|
+
await mintPublic(c, o, o.address, 1000n).then((t) => t.wait())
|
|
536
1013
|
})
|
|
537
1014
|
|
|
538
|
-
it("
|
|
539
|
-
const
|
|
1015
|
+
it("transfer encrypted 0n keeps balances unchanged", async function () {
|
|
1016
|
+
const ctFromBefore = await c["balanceOf(address)"](o.address)
|
|
1017
|
+
const ctToBefore = await c["balanceOf(address)"](other.address)
|
|
540
1018
|
|
|
541
|
-
const
|
|
1019
|
+
const fromBefore = decryptCtUint256(o, ctFromBefore)
|
|
1020
|
+
const toBefore = decryptCtUint256(other, ctToBefore)
|
|
542
1021
|
|
|
543
|
-
await
|
|
1022
|
+
const itZero = (await encryptItUint256(
|
|
1023
|
+
o,
|
|
1024
|
+
0n,
|
|
1025
|
+
addr,
|
|
1026
|
+
c.interface.getFunction("transfer(address,((uint256,uint256),bytes))").selector
|
|
1027
|
+
)) as itUint256
|
|
1028
|
+
|
|
1029
|
+
await (
|
|
1030
|
+
await c
|
|
1031
|
+
.connect(o)
|
|
1032
|
+
.getFunction("transfer(address,((uint256,uint256),bytes))")(other.address, itZero, txOpts)
|
|
1033
|
+
).wait()
|
|
1034
|
+
|
|
1035
|
+
const ctFromAfter = await c["balanceOf(address)"](o.address)
|
|
1036
|
+
const ctToAfter = await c["balanceOf(address)"](other.address)
|
|
1037
|
+
|
|
1038
|
+
const fromAfter = decryptCtUint256(o, ctFromAfter)
|
|
1039
|
+
const toAfter = decryptCtUint256(other, ctToAfter)
|
|
1040
|
+
|
|
1041
|
+
await expect(fromAfter).to.equal(fromBefore)
|
|
1042
|
+
await expect(toAfter).to.equal(toBefore)
|
|
1043
|
+
})
|
|
1044
|
+
|
|
1045
|
+
it("transfer encrypted exact balance moves all tokens", async function () {
|
|
1046
|
+
const value = 1000n
|
|
1047
|
+
|
|
1048
|
+
const itValue = (await encryptItUint256(
|
|
1049
|
+
o,
|
|
1050
|
+
value,
|
|
1051
|
+
addr,
|
|
1052
|
+
c.interface.getFunction("transfer(address,((uint256,uint256),bytes))").selector
|
|
1053
|
+
)) as itUint256
|
|
1054
|
+
|
|
1055
|
+
await (
|
|
1056
|
+
await c
|
|
1057
|
+
.connect(o)
|
|
1058
|
+
.getFunction("transfer(address,((uint256,uint256),bytes))")(other.address, itValue, txOpts)
|
|
1059
|
+
).wait()
|
|
1060
|
+
|
|
1061
|
+
const ctFrom = await c["balanceOf(address)"](o.address)
|
|
1062
|
+
const ctTo = await c["balanceOf(address)"](other.address)
|
|
1063
|
+
|
|
1064
|
+
await expect(decryptCtUint256(o, ctFrom)).to.equal(0n)
|
|
1065
|
+
await expect(decryptCtUint256(other, ctTo)).to.equal(value)
|
|
1066
|
+
})
|
|
1067
|
+
|
|
1068
|
+
it("approve encrypted 0 then transferFrom encrypted 0 does not change state", async function () {
|
|
1069
|
+
// reset: mint back for this test sequence
|
|
1070
|
+
// (this block runs after the previous test, which zeroed o's balance)
|
|
1071
|
+
await mintPublic(c, o, o.address, 1000n).then((t) => t.wait())
|
|
1072
|
+
await mintPublic(c, o, other.address, 0n).then((t) => t.wait())
|
|
1073
|
+
|
|
1074
|
+
const zero = 0n
|
|
1075
|
+
const itZeroApprove = (await encryptItUint256(
|
|
1076
|
+
o,
|
|
1077
|
+
zero,
|
|
1078
|
+
addr,
|
|
1079
|
+
c.interface.getFunction("approve(address,((uint256,uint256),bytes))").selector
|
|
1080
|
+
)) as itUint256
|
|
1081
|
+
|
|
1082
|
+
await (
|
|
1083
|
+
await c
|
|
1084
|
+
.connect(o)
|
|
1085
|
+
.getFunction("approve(address,((uint256,uint256),bytes))")(other.address, itZeroApprove, txOpts)
|
|
1086
|
+
).wait()
|
|
1087
|
+
|
|
1088
|
+
const itZeroTransferFrom = (await encryptItUint256(
|
|
1089
|
+
other,
|
|
1090
|
+
zero,
|
|
1091
|
+
addr,
|
|
1092
|
+
c.interface.getFunction("transferFrom(address,address,((uint256,uint256),bytes))").selector
|
|
1093
|
+
)) as itUint256
|
|
1094
|
+
|
|
1095
|
+
const fromBefore = decryptCtUint256(o, await c["balanceOf(address)"](o.address))
|
|
1096
|
+
const toBefore = decryptCtUint256(other, await c["balanceOf(address)"](other.address))
|
|
1097
|
+
|
|
1098
|
+
await (
|
|
1099
|
+
await c
|
|
1100
|
+
.connect(other)
|
|
1101
|
+
.getFunction("transferFrom(address,address,((uint256,uint256),bytes))")(
|
|
1102
|
+
o.address,
|
|
1103
|
+
other.address,
|
|
1104
|
+
itZeroTransferFrom,
|
|
1105
|
+
txOpts
|
|
1106
|
+
)
|
|
1107
|
+
).wait()
|
|
1108
|
+
|
|
1109
|
+
const fromAfter = decryptCtUint256(o, await c["balanceOf(address)"](o.address))
|
|
1110
|
+
const toAfter = decryptCtUint256(other, await c["balanceOf(address)"](other.address))
|
|
1111
|
+
|
|
1112
|
+
await expect(fromAfter).to.equal(fromBefore)
|
|
1113
|
+
await expect(toAfter).to.equal(toBefore)
|
|
1114
|
+
|
|
1115
|
+
const ctAllowance = await c["allowance(address,address)"](o.address, other.address)
|
|
1116
|
+
const allowanceSpenderView = decryptCtUint256(other, ctAllowance.spenderCiphertext)
|
|
1117
|
+
await expect(allowanceSpenderView).to.equal(0n)
|
|
1118
|
+
})
|
|
1119
|
+
|
|
1120
|
+
it("transferFrom encrypted exact allowance reduces allowance to zero", async function () {
|
|
1121
|
+
// reset: mint back and set a known allowance
|
|
1122
|
+
await mintPublic(c, o, o.address, 1000n).then((t) => t.wait())
|
|
1123
|
+
|
|
1124
|
+
const allow = 250n
|
|
1125
|
+
await (
|
|
1126
|
+
await c
|
|
1127
|
+
.connect(o)
|
|
1128
|
+
.getFunction("approve(address,uint256)")(other.address, allow, txOpts)
|
|
1129
|
+
).wait()
|
|
1130
|
+
|
|
1131
|
+
const itAllow = (await encryptItUint256(
|
|
1132
|
+
other,
|
|
1133
|
+
allow,
|
|
1134
|
+
addr,
|
|
1135
|
+
c.interface.getFunction("transferFrom(address,address,((uint256,uint256),bytes))").selector
|
|
1136
|
+
)) as itUint256
|
|
1137
|
+
|
|
1138
|
+
await (
|
|
1139
|
+
await c
|
|
1140
|
+
.connect(other)
|
|
1141
|
+
.getFunction("transferFrom(address,address,((uint256,uint256),bytes))")(
|
|
1142
|
+
o.address,
|
|
1143
|
+
other.address,
|
|
1144
|
+
itAllow,
|
|
1145
|
+
txOpts
|
|
1146
|
+
)
|
|
1147
|
+
).wait()
|
|
1148
|
+
|
|
1149
|
+
const ctFrom = await c["balanceOf(address)"](o.address)
|
|
1150
|
+
const ctTo = await c["balanceOf(address)"](other.address)
|
|
1151
|
+
|
|
1152
|
+
// owner was >= 250 due to minting above; exact expected amounts depend on prior tests
|
|
1153
|
+
await expect(decryptCtUint256(other, ctTo)).to.be.greaterThan(0n)
|
|
1154
|
+
|
|
1155
|
+
const ctAllowance = await c["allowance(address,address)"](o.address, other.address)
|
|
1156
|
+
const allowanceSpenderView = decryptCtUint256(other, ctAllowance.spenderCiphertext)
|
|
1157
|
+
await expect(allowanceSpenderView).to.equal(0n)
|
|
1158
|
+
})
|
|
1159
|
+
|
|
1160
|
+
it("increaseAllowance encrypted 0n is a no-op", async function () {
|
|
1161
|
+
// Ensure allowance starts from 0 by approving 0 publicly.
|
|
1162
|
+
await (
|
|
1163
|
+
await c.connect(o).getFunction("approve(address,uint256)")(other.address, 0n, txOpts)
|
|
1164
|
+
).wait()
|
|
1165
|
+
|
|
1166
|
+
const itZero = (await encryptItUint256(
|
|
1167
|
+
o,
|
|
1168
|
+
0n,
|
|
1169
|
+
addr,
|
|
1170
|
+
c.interface.getFunction("increaseAllowance(address,((uint256,uint256),bytes))").selector
|
|
1171
|
+
)) as itUint256
|
|
1172
|
+
|
|
1173
|
+
await (
|
|
1174
|
+
await c
|
|
1175
|
+
.connect(o)
|
|
1176
|
+
.getFunction("increaseAllowance(address,((uint256,uint256),bytes))")(other.address, itZero, txOpts)
|
|
1177
|
+
).wait()
|
|
1178
|
+
|
|
1179
|
+
const ctAllowance = await c["allowance(address,address)"](o.address, other.address)
|
|
1180
|
+
const allowanceOwnerView = decryptCtUint256(o, ctAllowance.ownerCiphertext)
|
|
1181
|
+
await expect(allowanceOwnerView).to.equal(0n)
|
|
1182
|
+
})
|
|
1183
|
+
|
|
1184
|
+
it("decreaseAllowance encrypted exact current allowance reduces to zero", async function () {
|
|
1185
|
+
const current = 123n
|
|
1186
|
+
await (
|
|
1187
|
+
await c
|
|
1188
|
+
.connect(o)
|
|
1189
|
+
.getFunction("approve(address,uint256)")(other.address, current, txOpts)
|
|
1190
|
+
).wait()
|
|
1191
|
+
|
|
1192
|
+
const itSub = (await encryptItUint256(
|
|
1193
|
+
o,
|
|
1194
|
+
current,
|
|
1195
|
+
addr,
|
|
1196
|
+
c.interface.getFunction("decreaseAllowance(address,((uint256,uint256),bytes))").selector
|
|
1197
|
+
)) as itUint256
|
|
1198
|
+
|
|
1199
|
+
await (
|
|
1200
|
+
await c
|
|
1201
|
+
.connect(o)
|
|
1202
|
+
.getFunction("decreaseAllowance(address,((uint256,uint256),bytes))")(other.address, itSub, txOpts)
|
|
1203
|
+
).wait()
|
|
1204
|
+
|
|
1205
|
+
const ctAllowance = await c["allowance(address,address)"](o.address, other.address)
|
|
1206
|
+
const allowanceOwnerView = decryptCtUint256(o, ctAllowance.ownerCiphertext)
|
|
1207
|
+
await expect(allowanceOwnerView).to.equal(0n)
|
|
1208
|
+
})
|
|
1209
|
+
|
|
1210
|
+
it("encrypted mint/burn accept 0n and reject malformed itUint256", async function () {
|
|
1211
|
+
const fromBefore = decryptCtUint256(o, await c["balanceOf(address)"](o.address))
|
|
1212
|
+
|
|
1213
|
+
// PrivateERC20Mock only bypasses MINTER_ROLE for the public mint overload.
|
|
1214
|
+
// The encrypted mint overload still requires MINTER_ROLE, so grant it here.
|
|
1215
|
+
await (
|
|
1216
|
+
await c.connect(o).grantRole(await c.MINTER_ROLE(), o.address)
|
|
1217
|
+
).wait()
|
|
1218
|
+
|
|
1219
|
+
const itZeroMint = (await encryptItUint256(
|
|
1220
|
+
o,
|
|
1221
|
+
0n,
|
|
1222
|
+
addr,
|
|
1223
|
+
c.interface.getFunction("mint(address,((uint256,uint256),bytes))").selector
|
|
1224
|
+
)) as itUint256
|
|
1225
|
+
|
|
1226
|
+
await (
|
|
1227
|
+
await c
|
|
1228
|
+
.connect(o)
|
|
1229
|
+
.getFunction("mint(address,((uint256,uint256),bytes))")(o.address, itZeroMint, txOpts)
|
|
1230
|
+
).wait()
|
|
1231
|
+
|
|
1232
|
+
const itZeroBurn = (await encryptItUint256(
|
|
1233
|
+
o,
|
|
1234
|
+
0n,
|
|
1235
|
+
addr,
|
|
1236
|
+
c.interface.getFunction("burn(((uint256,uint256),bytes))").selector
|
|
1237
|
+
)) as itUint256
|
|
1238
|
+
|
|
1239
|
+
await (
|
|
1240
|
+
await c
|
|
1241
|
+
.connect(o)
|
|
1242
|
+
.getFunction("burn(((uint256,uint256),bytes))")(itZeroBurn, txOpts)
|
|
1243
|
+
).wait()
|
|
1244
|
+
|
|
1245
|
+
const fromAfter = decryptCtUint256(o, await c["balanceOf(address)"](o.address))
|
|
1246
|
+
await expect(fromAfter).to.equal(fromBefore)
|
|
1247
|
+
|
|
1248
|
+
const goodMint = (await encryptItUint256(
|
|
1249
|
+
o,
|
|
1250
|
+
1n,
|
|
1251
|
+
addr,
|
|
1252
|
+
c.interface.getFunction("mint(address,((uint256,uint256),bytes))").selector
|
|
1253
|
+
)) as itUint256
|
|
1254
|
+
|
|
1255
|
+
const badSig: itUint256 = {
|
|
1256
|
+
ciphertext: goodMint.ciphertext,
|
|
1257
|
+
signature: new Uint8Array()
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
await expectTxFails(
|
|
1261
|
+
c.connect(o)
|
|
1262
|
+
.getFunction("mint(address,((uint256,uint256),bytes))")(o.address, badSig, txOpts)
|
|
1263
|
+
)
|
|
1264
|
+
})
|
|
1265
|
+
|
|
1266
|
+
it("encrypted operations still work when publicAmountsEnabled=false", async function () {
|
|
1267
|
+
await (
|
|
1268
|
+
await c.connect(o).setPublicAmountsEnabled(false, txOpts)
|
|
1269
|
+
).wait()
|
|
1270
|
+
|
|
1271
|
+
const value = 10n
|
|
1272
|
+
const itValue = (await encryptItUint256(
|
|
1273
|
+
o,
|
|
1274
|
+
value,
|
|
1275
|
+
addr,
|
|
1276
|
+
c.interface.getFunction("transfer(address,((uint256,uint256),bytes))").selector
|
|
1277
|
+
)) as itUint256
|
|
1278
|
+
|
|
1279
|
+
const fromBefore = decryptCtUint256(o, await c["balanceOf(address)"](o.address))
|
|
1280
|
+
const toBefore = decryptCtUint256(other, await c["balanceOf(address)"](other.address))
|
|
1281
|
+
|
|
1282
|
+
await (
|
|
1283
|
+
await c
|
|
1284
|
+
.connect(o)
|
|
1285
|
+
.getFunction("transfer(address,((uint256,uint256),bytes))")(other.address, itValue, txOpts)
|
|
1286
|
+
).wait()
|
|
1287
|
+
|
|
1288
|
+
const fromAfter = decryptCtUint256(o, await c["balanceOf(address)"](o.address))
|
|
1289
|
+
const toAfter = decryptCtUint256(other, await c["balanceOf(address)"](other.address))
|
|
1290
|
+
|
|
1291
|
+
await expect(fromAfter).to.equal(fromBefore - value)
|
|
1292
|
+
await expect(toAfter).to.equal(toBefore + value)
|
|
1293
|
+
})
|
|
1294
|
+
|
|
1295
|
+
it("rejects malformed itUint256: bad signature and swapped ciphertext limbs", async function () {
|
|
1296
|
+
const good = (await encryptItUint256(
|
|
1297
|
+
o,
|
|
1298
|
+
1n,
|
|
1299
|
+
addr,
|
|
1300
|
+
c.interface.getFunction("transfer(address,((uint256,uint256),bytes))").selector
|
|
1301
|
+
)) as itUint256
|
|
1302
|
+
|
|
1303
|
+
const badSig: itUint256 = {
|
|
1304
|
+
ciphertext: good.ciphertext,
|
|
1305
|
+
signature: new Uint8Array()
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
const swapped: itUint256 = {
|
|
1309
|
+
ciphertext: {
|
|
1310
|
+
ciphertextHigh: good.ciphertext.ciphertextLow,
|
|
1311
|
+
ciphertextLow: good.ciphertext.ciphertextHigh
|
|
1312
|
+
},
|
|
1313
|
+
signature: good.signature
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
await expectTxFails(
|
|
1317
|
+
c.connect(o)
|
|
1318
|
+
.getFunction("transfer(address,((uint256,uint256),bytes))")(other.address, badSig, txOpts)
|
|
1319
|
+
)
|
|
1320
|
+
|
|
1321
|
+
await expectTxFails(
|
|
1322
|
+
c.connect(o)
|
|
1323
|
+
.getFunction("transfer(address,((uint256,uint256),bytes))")(other.address, swapped, txOpts)
|
|
1324
|
+
)
|
|
1325
|
+
})
|
|
1326
|
+
})
|
|
1327
|
+
|
|
1328
|
+
describe("isolated deploy: self-transfer and unsafe approve", function () {
|
|
1329
|
+
let iso: PrivateERC20Mock
|
|
1330
|
+
let isoAddr: string
|
|
1331
|
+
let o: Wallet
|
|
1332
|
+
let other: Wallet
|
|
1333
|
+
|
|
1334
|
+
before(async function () {
|
|
1335
|
+
const d = await deploy()
|
|
1336
|
+
iso = d.contract
|
|
1337
|
+
isoAddr = d.contractAddress
|
|
1338
|
+
o = d.owner
|
|
1339
|
+
other = d.otherAccount
|
|
1340
|
+
await mintPublic(iso, o, o.address, 1000n).then((t) => t.wait())
|
|
1341
|
+
})
|
|
1342
|
+
|
|
1343
|
+
it("reverts self-transfer", async function () {
|
|
1344
|
+
const itValue = (await encryptItUint256(o,
|
|
1345
|
+
1n,
|
|
1346
|
+
isoAddr,
|
|
1347
|
+
iso.interface.getFunction("transfer(address,((uint256,uint256),bytes))").selector
|
|
1348
|
+
)) as itUint256
|
|
1349
|
+
|
|
1350
|
+
await expectTxFails(
|
|
1351
|
+
iso.connect(o).getFunction("transfer(address,((uint256,uint256),bytes))")(o.address, itValue, txOpts)
|
|
1352
|
+
)
|
|
1353
|
+
})
|
|
1354
|
+
|
|
1355
|
+
it("reverts unsafe approve then clears with approve zero", async function () {
|
|
1356
|
+
const a1 = (await encryptItUint256(o,
|
|
1357
|
+
100n,
|
|
1358
|
+
isoAddr,
|
|
1359
|
+
iso.interface.getFunction("approve(address,((uint256,uint256),bytes))").selector
|
|
1360
|
+
)) as itUint256
|
|
1361
|
+
await iso
|
|
1362
|
+
.connect(o)
|
|
1363
|
+
.getFunction("approve(address,((uint256,uint256),bytes))")(other.address, a1, txOpts)
|
|
1364
|
+
.then((t) => t.wait())
|
|
1365
|
+
|
|
1366
|
+
const a2 = (await encryptItUint256(o,
|
|
1367
|
+
200n,
|
|
1368
|
+
isoAddr,
|
|
1369
|
+
iso.interface.getFunction("approve(address,((uint256,uint256),bytes))").selector
|
|
1370
|
+
)) as itUint256
|
|
1371
|
+
|
|
1372
|
+
await expectTxFails(
|
|
1373
|
+
iso.connect(o).getFunction("approve(address,((uint256,uint256),bytes))")(other.address, a2, txOpts)
|
|
1374
|
+
)
|
|
1375
|
+
|
|
1376
|
+
const z = (await encryptItUint256(o,
|
|
1377
|
+
0n,
|
|
1378
|
+
isoAddr,
|
|
1379
|
+
iso.interface.getFunction("approve(address,((uint256,uint256),bytes))").selector
|
|
1380
|
+
)) as itUint256
|
|
1381
|
+
await iso
|
|
1382
|
+
.connect(o)
|
|
1383
|
+
.getFunction("approve(address,((uint256,uint256),bytes))")(other.address, z, txOpts)
|
|
1384
|
+
.then((t) => t.wait())
|
|
544
1385
|
})
|
|
545
1386
|
})
|
|
546
1387
|
})
|