@coti-io/coti-contracts 1.2.0 → 1.3.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.
Files changed (267) hide show
  1. package/.github/workflows/npm-publish.yml +1 -1
  2. package/contracts/messaging/PrivateMessaging.sol +456 -0
  3. package/contracts/mocks/messaging/PrivateMessagingHarness.sol +54 -0
  4. package/contracts/mocks/oracle/CotiPriceConsumerMock.sol +31 -0
  5. package/contracts/mocks/token/ERC20DecimalsMock.sol +21 -0
  6. package/contracts/mocks/token/PrivateERC20/PrivacyBridgeERC20Mock.sol +8 -3
  7. package/contracts/node/SoulboundNodeNFT.sol +22 -22
  8. package/contracts/oracle/CotiPriceConsumer.sol +103 -0
  9. package/contracts/oracle/ICotiPriceConsumer.sol +15 -0
  10. package/contracts/oracle/IStdReference.sol +26 -0
  11. package/contracts/privacyBridge/PrivacyBridge.sol +373 -91
  12. package/contracts/privacyBridge/PrivacyBridgeCotiNative.sol +209 -161
  13. package/contracts/privacyBridge/PrivacyBridgeERC20.sol +241 -159
  14. package/contracts/privacyBridge/PrivacyBridgeUSDCe.sol +7 -1
  15. package/contracts/privacyBridge/PrivacyBridgeUSDT.sol +7 -1
  16. package/contracts/privacyBridge/PrivacyBridgeWADA.sol +7 -1
  17. package/contracts/privacyBridge/PrivacyBridgeWBTC.sol +7 -1
  18. package/contracts/privacyBridge/PrivacyBridgeWETH.sol +7 -1
  19. package/contracts/privacyBridge/PrivacyBridgegCoti.sol +7 -1
  20. package/hardhat.config.ts +5 -2
  21. package/package.json +2 -2
  22. package/scripts/add-bridge-operators.cjs +87 -0
  23. package/scripts/deploy-coti-price-consumer-mainnet.cjs +49 -0
  24. package/scripts/deployCotiNodeRewards.ts +51 -0
  25. package/scripts/redeploy-private-and-bridges.cjs +201 -0
  26. package/scripts/set-bridge-limits-mainnet.cjs +177 -0
  27. package/scripts/verify-mainnet-private-bridges.cjs +289 -0
  28. package/sonar-project.properties +11 -0
  29. package/test/messaging/PrivateMessaging.test.ts +158 -0
  30. package/test/privacyBridge/UnifiedPrivacyBridges.test.cjs +1663 -0
  31. package/test/token/PrivateERC20/PrivacyBridge.fees.test.ts +162 -239
  32. package/typechain-types/@openzeppelin/contracts/access/AccessControl.ts +324 -0
  33. package/typechain-types/@openzeppelin/contracts/access/AccessControlEnumerable.ts +361 -0
  34. package/typechain-types/@openzeppelin/contracts/access/IAccessControl.ts +292 -0
  35. package/typechain-types/@openzeppelin/contracts/access/IAccessControlEnumerable.ts +329 -0
  36. package/typechain-types/@openzeppelin/contracts/access/index.ts +4 -0
  37. package/typechain-types/@openzeppelin/contracts/index.ts +2 -0
  38. package/typechain-types/@openzeppelin/contracts/security/Pausable.ts +150 -0
  39. package/typechain-types/@openzeppelin/contracts/security/index.ts +4 -0
  40. package/typechain-types/@openzeppelin/contracts/token/ERC20/ERC20.ts +330 -0
  41. package/typechain-types/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.ts +286 -0
  42. package/typechain-types/@openzeppelin/contracts/token/ERC20/extensions/index.ts +1 -0
  43. package/typechain-types/@openzeppelin/contracts/token/ERC20/index.ts +1 -0
  44. package/typechain-types/@openzeppelin/contracts/token/ERC721/ERC721.ts +420 -0
  45. package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.ts +420 -0
  46. package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/index.ts +4 -0
  47. package/typechain-types/@openzeppelin/contracts/token/ERC721/index.ts +3 -0
  48. package/typechain-types/contracts/disperse/coinByRatio/FixedRatioCoinDisperserLeftoverS1.ts +735 -0
  49. package/typechain-types/contracts/disperse/coinByRatio/FixedRatioCoinDisperserUnlimitedWindow.ts +734 -0
  50. package/typechain-types/contracts/disperse/coinByRatio/index.ts +2 -0
  51. package/typechain-types/contracts/disperse/disperseToken/MintDisperser.sol/IOwnable.ts +95 -0
  52. package/typechain-types/contracts/disperse/disperseToken/MintDisperser.sol/MintDisperser.ts +22 -0
  53. package/typechain-types/contracts/disperse/disperseToken/MintDisperser.sol/index.ts +1 -0
  54. package/typechain-types/contracts/index.ts +8 -0
  55. package/typechain-types/contracts/messaging/PrivateMessaging.ts +871 -0
  56. package/typechain-types/contracts/messaging/index.ts +4 -0
  57. package/typechain-types/contracts/mocks/index.ts +4 -0
  58. package/typechain-types/contracts/mocks/messaging/PrivateMessagingHarness.ts +951 -0
  59. package/typechain-types/contracts/mocks/messaging/index.ts +4 -0
  60. package/typechain-types/contracts/mocks/oracle/CotiPriceConsumerMock.ts +163 -0
  61. package/typechain-types/contracts/mocks/oracle/index.ts +4 -0
  62. package/typechain-types/contracts/mocks/token/ERC20DecimalsMock.ts +349 -0
  63. package/typechain-types/contracts/mocks/token/ERC20Mock.ts +368 -0
  64. package/typechain-types/contracts/mocks/token/PrivateERC20/EncryptedTokenReceiverMock.ts +108 -0
  65. package/typechain-types/contracts/mocks/token/PrivateERC20/PrivacyBridgeERC20Mock.ts +1892 -0
  66. package/typechain-types/contracts/mocks/token/PrivateERC20/PrivateERC20AuditorSupplyMock.ts +1296 -0
  67. package/typechain-types/contracts/mocks/token/PrivateERC20/PrivateERC20CappedMock.ts +1270 -0
  68. package/typechain-types/contracts/mocks/{utils/mpc/Bitwise128BitTestsContract.ts → token/PrivateERC20/PrivateERC20GtCallerMock.ts} +47 -67
  69. package/typechain-types/contracts/mocks/token/PrivateERC20/PrivateERC20Mock.ts +757 -25
  70. package/typechain-types/contracts/mocks/token/PrivateERC20/PrivateERC20ReentrantReceiverMock.sol/IPrivateERC20TransferAndCallEncrypted.ts +102 -0
  71. package/typechain-types/contracts/mocks/token/PrivateERC20/PrivateERC20ReentrantReceiverMock.sol/PrivateERC20ReentrantReceiverMock.ts +154 -0
  72. package/typechain-types/contracts/mocks/token/PrivateERC20/PrivateERC20ReentrantReceiverMock.sol/index.ts +5 -0
  73. package/typechain-types/contracts/mocks/token/PrivateERC20/PublicReentrantTokenReceiverMock.ts +155 -0
  74. package/typechain-types/contracts/mocks/token/PrivateERC20/PublicTokenReceiverBoolMock.ts +107 -0
  75. package/typechain-types/contracts/mocks/token/PrivateERC20/PublicTokenReceiverMock.ts +100 -0
  76. package/typechain-types/contracts/mocks/token/PrivateERC20/index.ts +10 -0
  77. package/typechain-types/contracts/mocks/token/index.ts +2 -0
  78. package/typechain-types/contracts/mocks/wallet/PrivateERC20Wallet/PrivateERC20WalletMock.ts +6 -6
  79. package/typechain-types/contracts/node/CotiNodeRewards.ts +566 -0
  80. package/typechain-types/contracts/node/SoulboundNodeNFT.sol/IERC5192.ts +123 -0
  81. package/typechain-types/contracts/node/SoulboundNodeNFT.sol/SoulboundNodeNFT.ts +975 -0
  82. package/typechain-types/contracts/node/SoulboundNodeNFT.sol/index.ts +5 -0
  83. package/typechain-types/contracts/node/index.ts +6 -0
  84. package/typechain-types/contracts/oracle/CotiPriceConsumer.ts +256 -0
  85. package/typechain-types/contracts/oracle/ICotiPriceConsumer.ts +119 -0
  86. package/typechain-types/contracts/oracle/IStdReference.ts +136 -0
  87. package/typechain-types/contracts/oracle/index.ts +6 -0
  88. package/typechain-types/contracts/privacyBridge/PrivacyBridge.ts +1628 -0
  89. package/typechain-types/contracts/privacyBridge/PrivacyBridgeCotiNative.ts +1870 -0
  90. package/typechain-types/contracts/privacyBridge/PrivacyBridgeERC20.sol/IHasDecimals.ts +84 -0
  91. package/typechain-types/contracts/privacyBridge/PrivacyBridgeERC20.sol/PrivacyBridgeERC20.ts +1892 -0
  92. package/typechain-types/contracts/privacyBridge/PrivacyBridgeERC20.sol/index.ts +5 -0
  93. package/typechain-types/contracts/privacyBridge/PrivacyBridgeUSDCe.ts +1892 -0
  94. package/typechain-types/contracts/privacyBridge/PrivacyBridgeUSDT.ts +1892 -0
  95. package/typechain-types/contracts/privacyBridge/PrivacyBridgeWADA.ts +1892 -0
  96. package/typechain-types/contracts/privacyBridge/PrivacyBridgeWBTC.ts +1892 -0
  97. package/typechain-types/contracts/privacyBridge/PrivacyBridgeWETH.ts +1892 -0
  98. package/typechain-types/contracts/privacyBridge/PrivacyBridgegCoti.ts +1892 -0
  99. package/typechain-types/contracts/privacyBridge/index.ts +13 -0
  100. package/typechain-types/contracts/token/PrivateERC20/IPrivateERC20.ts +439 -19
  101. package/typechain-types/contracts/token/PrivateERC20/ITokenReceiver.ts +100 -0
  102. package/typechain-types/contracts/token/PrivateERC20/ITokenReceiverEncrypted.ts +99 -0
  103. package/typechain-types/contracts/token/PrivateERC20/PrivateERC20.ts +763 -15
  104. package/typechain-types/contracts/token/PrivateERC20/index.ts +4 -0
  105. package/typechain-types/contracts/token/PrivateERC20/tokens/PrivateBridgedUSDC.ts +1270 -0
  106. package/typechain-types/contracts/token/PrivateERC20/tokens/PrivateCOTI.ts +1270 -0
  107. package/typechain-types/contracts/token/PrivateERC20/tokens/PrivateCOTITreasuryGovernanceToken.ts +1270 -0
  108. package/typechain-types/contracts/token/PrivateERC20/tokens/PrivateTetherUSD.ts +1270 -0
  109. package/typechain-types/contracts/token/PrivateERC20/tokens/PrivateWrappedADA.ts +1270 -0
  110. package/typechain-types/contracts/token/PrivateERC20/tokens/PrivateWrappedBTC.ts +1270 -0
  111. package/typechain-types/contracts/token/PrivateERC20/tokens/PrivateWrappedEther.ts +1270 -0
  112. package/typechain-types/contracts/token/PrivateERC20/tokens/index.ts +10 -0
  113. package/typechain-types/factories/@openzeppelin/contracts/access/AccessControlEnumerable__factory.ts +276 -0
  114. package/typechain-types/factories/@openzeppelin/contracts/access/AccessControl__factory.ts +229 -0
  115. package/typechain-types/factories/@openzeppelin/contracts/access/IAccessControlEnumerable__factory.ts +244 -0
  116. package/typechain-types/factories/@openzeppelin/contracts/access/IAccessControl__factory.ts +197 -0
  117. package/typechain-types/factories/@openzeppelin/contracts/access/index.ts +4 -0
  118. package/typechain-types/factories/@openzeppelin/contracts/index.ts +1 -0
  119. package/typechain-types/factories/@openzeppelin/contracts/security/Pausable__factory.ts +61 -0
  120. package/typechain-types/factories/@openzeppelin/contracts/security/index.ts +4 -0
  121. package/typechain-types/factories/@openzeppelin/contracts/token/ERC20/ERC20__factory.ts +356 -0
  122. package/typechain-types/factories/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata__factory.ts +247 -0
  123. package/typechain-types/factories/@openzeppelin/contracts/token/ERC20/extensions/index.ts +1 -0
  124. package/typechain-types/factories/@openzeppelin/contracts/token/ERC20/index.ts +1 -0
  125. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/ERC721__factory.ts +416 -0
  126. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata__factory.ts +355 -0
  127. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/index.ts +4 -0
  128. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/index.ts +2 -0
  129. package/typechain-types/factories/contracts/disperse/coinByRatio/FixedRatioCoinDisperserLeftoverS1__factory.ts +791 -0
  130. package/typechain-types/factories/contracts/disperse/coinByRatio/FixedRatioCoinDisperserUnlimitedWindow__factory.ts +711 -0
  131. package/typechain-types/factories/contracts/disperse/coinByRatio/FixedRatioCoinDisperser__factory.ts +1 -1
  132. package/typechain-types/factories/contracts/disperse/coinByRatio/index.ts +2 -0
  133. package/typechain-types/factories/contracts/disperse/disperseToken/MintDisperser.sol/IOwnable__factory.ts +35 -0
  134. package/typechain-types/factories/contracts/disperse/disperseToken/MintDisperser.sol/MintDisperser__factory.ts +19 -1
  135. package/typechain-types/factories/contracts/disperse/disperseToken/MintDisperser.sol/index.ts +1 -0
  136. package/typechain-types/factories/contracts/disperse/disperseToken/TokenDisperser__factory.ts +1 -1
  137. package/typechain-types/factories/contracts/index.ts +4 -0
  138. package/typechain-types/factories/contracts/messaging/PrivateMessaging__factory.ts +1035 -0
  139. package/typechain-types/factories/contracts/messaging/index.ts +4 -0
  140. package/typechain-types/factories/contracts/mocks/access/DataPrivacyFramework/DataPrivacyFrameworkMock__factory.ts +1 -1
  141. package/typechain-types/factories/contracts/mocks/index.ts +2 -0
  142. package/typechain-types/factories/contracts/mocks/messaging/PrivateMessagingHarness__factory.ts +1161 -0
  143. package/typechain-types/factories/contracts/mocks/messaging/index.ts +4 -0
  144. package/typechain-types/factories/contracts/mocks/oracle/CotiPriceConsumerMock__factory.ts +159 -0
  145. package/typechain-types/factories/contracts/mocks/oracle/index.ts +4 -0
  146. package/typechain-types/factories/contracts/mocks/token/ERC20DecimalsMock__factory.ts +394 -0
  147. package/typechain-types/factories/contracts/mocks/token/ERC20Mock__factory.ts +392 -0
  148. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/EncryptedTokenReceiverMock__factory.ts +125 -0
  149. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PrivacyBridgeERC20Mock__factory.ts +1797 -0
  150. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PrivateERC20AuditorSupplyMock__factory.ts +1514 -0
  151. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PrivateERC20CappedMock__factory.ts +1466 -0
  152. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PrivateERC20GtCallerMock__factory.ts +165 -0
  153. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PrivateERC20Mock__factory.ts +771 -55
  154. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PrivateERC20ReentrantReceiverMock.sol/IPrivateERC20TransferAndCallEncrypted__factory.ts +54 -0
  155. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PrivateERC20ReentrantReceiverMock.sol/PrivateERC20ReentrantReceiverMock__factory.ts +159 -0
  156. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PrivateERC20ReentrantReceiverMock.sol/index.ts +5 -0
  157. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PublicReentrantTokenReceiverMock__factory.ts +164 -0
  158. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PublicTokenReceiverBoolMock__factory.ts +130 -0
  159. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/PublicTokenReceiverMock__factory.ts +102 -0
  160. package/typechain-types/factories/contracts/mocks/token/PrivateERC20/index.ts +9 -0
  161. package/typechain-types/factories/contracts/mocks/token/PrivateERC721/PrivateERC721URIStorageMock__factory.ts +1 -1
  162. package/typechain-types/factories/contracts/mocks/token/index.ts +2 -0
  163. package/typechain-types/factories/contracts/mocks/utils/mpc/Arithmetic128TestsContract__factory.ts +1 -1
  164. package/typechain-types/factories/contracts/mocks/utils/mpc/Arithmetic256TestsContract__factory.ts +1 -1
  165. package/typechain-types/factories/contracts/mocks/utils/mpc/ArithmeticTestsContract__factory.ts +1 -1
  166. package/typechain-types/factories/contracts/mocks/utils/mpc/Bitwise128TestsContract__factory.ts +1 -1
  167. package/typechain-types/factories/contracts/mocks/utils/mpc/Bitwise256TestsContract__factory.ts +1 -1
  168. package/typechain-types/factories/contracts/mocks/utils/mpc/BitwiseTestsContract__factory.ts +1 -1
  169. package/typechain-types/factories/contracts/mocks/utils/mpc/CheckedArithmetic128WithOverflowBitTestsContract__factory.ts +1 -1
  170. package/typechain-types/factories/contracts/mocks/utils/mpc/CheckedArithmetic256WithOverflowBitTestsContract__factory.ts +1 -1
  171. package/typechain-types/factories/contracts/mocks/utils/mpc/CheckedArithmeticWIthOverflowBitTestsContract.sol/CheckedArithmeticWithOverflowBitTestsContract__factory.ts +1 -1
  172. package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison128TestsContract__factory.ts +1 -1
  173. package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison1TestsContract__factory.ts +1 -1
  174. package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison256TestsContract__factory.ts +1 -1
  175. package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison2TestsContract__factory.ts +1 -1
  176. package/typechain-types/factories/contracts/mocks/utils/mpc/MinMax128TestsContract__factory.ts +1 -1
  177. package/typechain-types/factories/contracts/mocks/utils/mpc/MinMax256TestsContract__factory.ts +1 -1
  178. package/typechain-types/factories/contracts/mocks/utils/mpc/MinMaxTestsContract__factory.ts +1 -1
  179. package/typechain-types/factories/contracts/mocks/utils/mpc/MinimalImplementation__factory.ts +1 -1
  180. package/typechain-types/factories/contracts/mocks/utils/mpc/MinimalProxy__factory.ts +1 -1
  181. package/typechain-types/factories/contracts/mocks/utils/mpc/Miscellaneous1TestsContract__factory.ts +1 -1
  182. package/typechain-types/factories/contracts/mocks/utils/mpc/MiscellaneousTestsContract__factory.ts +1 -1
  183. package/typechain-types/factories/contracts/mocks/utils/mpc/MpcOperations128TestContract__factory.ts +1 -1
  184. package/typechain-types/factories/contracts/mocks/utils/mpc/MpcOperationsTestContract__factory.ts +1 -1
  185. package/typechain-types/factories/contracts/mocks/utils/mpc/Mux128TestsContract__factory.ts +1 -1
  186. package/typechain-types/factories/contracts/mocks/utils/mpc/Mux256TestsContract__factory.ts +1 -1
  187. package/typechain-types/factories/contracts/mocks/utils/mpc/OffboardToUserKeyTestContract__factory.ts +1 -1
  188. package/typechain-types/factories/contracts/mocks/utils/mpc/OnBoard128TestsContract__factory.ts +1 -1
  189. package/typechain-types/factories/contracts/mocks/utils/mpc/OnBoard256TestsContract__factory.ts +1 -1
  190. package/typechain-types/factories/contracts/mocks/utils/mpc/PrivacyImplementationV1__factory.ts +1 -1
  191. package/typechain-types/factories/contracts/mocks/utils/mpc/PrivacyImplementationV2__factory.ts +1 -1
  192. package/typechain-types/factories/contracts/mocks/utils/mpc/PrivacyProxy__factory.ts +1 -1
  193. package/typechain-types/factories/contracts/mocks/utils/mpc/Random128TestsContract__factory.ts +1 -1
  194. package/typechain-types/factories/contracts/mocks/utils/mpc/Random256TestsContract__factory.ts +1 -1
  195. package/typechain-types/factories/contracts/mocks/utils/mpc/Shift128TestsContract__factory.ts +1 -1
  196. package/typechain-types/factories/contracts/mocks/utils/mpc/Shift256TestsContract__factory.ts +1 -1
  197. package/typechain-types/factories/contracts/mocks/utils/mpc/ShiftTestsContract__factory.ts +1 -1
  198. package/typechain-types/factories/contracts/mocks/utils/mpc/StringTestsContract__factory.ts +1 -1
  199. package/typechain-types/factories/contracts/mocks/utils/mpc/Transfer128TestsContract__factory.ts +1 -1
  200. package/typechain-types/factories/contracts/mocks/utils/mpc/Transfer256TestsContract__factory.ts +1 -1
  201. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferScalarTestsContract__factory.ts +1 -1
  202. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferTestsContract__factory.ts +1 -1
  203. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance128TestsContract__factory.ts +1 -1
  204. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance256TestsContract__factory.ts +1 -1
  205. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance64_16TestsContract__factory.ts +1 -1
  206. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance64_32TestsContract__factory.ts +1 -1
  207. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance64_64TestsContract__factory.ts +1 -1
  208. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowance64_8TestsContract__factory.ts +1 -1
  209. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowanceScalarTestsContract__factory.ts +1 -1
  210. package/typechain-types/factories/contracts/mocks/utils/mpc/TransferWithAllowanceTestsContract__factory.ts +1 -1
  211. package/typechain-types/factories/contracts/mocks/utils/mpc/ValidateCiphertext128TestsContract__factory.ts +1 -1
  212. package/typechain-types/factories/contracts/mocks/utils/mpc/ValidateCiphertext256TestsContract__factory.ts +1 -1
  213. package/typechain-types/factories/contracts/mocks/utils/mpc/ValidateCiphertextTestsContract__factory.ts +1 -1
  214. package/typechain-types/factories/contracts/mocks/wallet/PrivateERC20Wallet/PrivateERC20WalletMock__factory.ts +4 -22
  215. package/typechain-types/factories/contracts/node/CotiNodeRewards__factory.ts +549 -0
  216. package/typechain-types/factories/contracts/node/SoulboundNodeNFT.sol/IERC5192__factory.ts +54 -0
  217. package/typechain-types/factories/contracts/node/SoulboundNodeNFT.sol/SoulboundNodeNFT__factory.ts +947 -0
  218. package/typechain-types/factories/contracts/node/SoulboundNodeNFT.sol/index.ts +5 -0
  219. package/typechain-types/factories/contracts/node/index.ts +5 -0
  220. package/typechain-types/factories/contracts/onboard/AccountOnboard__factory.ts +1 -1
  221. package/typechain-types/factories/contracts/oracle/CotiPriceConsumer__factory.ts +295 -0
  222. package/typechain-types/factories/contracts/oracle/ICotiPriceConsumer__factory.ts +73 -0
  223. package/typechain-types/factories/contracts/oracle/IStdReference__factory.ts +107 -0
  224. package/typechain-types/factories/contracts/oracle/index.ts +6 -0
  225. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridgeCotiNative__factory.ts +1676 -0
  226. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridgeERC20.sol/IHasDecimals__factory.ts +38 -0
  227. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridgeERC20.sol/PrivacyBridgeERC20__factory.ts +1678 -0
  228. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridgeERC20.sol/index.ts +5 -0
  229. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridgeUSDCe__factory.ts +1782 -0
  230. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridgeUSDT__factory.ts +1782 -0
  231. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridgeWADA__factory.ts +1782 -0
  232. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridgeWBTC__factory.ts +1782 -0
  233. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridgeWETH__factory.ts +1782 -0
  234. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridge__factory.ts +1367 -0
  235. package/typechain-types/factories/contracts/privacyBridge/PrivacyBridgegCoti__factory.ts +1782 -0
  236. package/typechain-types/factories/contracts/privacyBridge/index.ts +12 -0
  237. package/typechain-types/factories/contracts/token/PrivateERC20/IPrivateERC20__factory.ts +481 -35
  238. package/typechain-types/factories/contracts/token/PrivateERC20/ITokenReceiverEncrypted__factory.ts +53 -0
  239. package/typechain-types/factories/contracts/token/PrivateERC20/ITokenReceiver__factory.ts +54 -0
  240. package/typechain-types/factories/contracts/token/PrivateERC20/PrivateERC20__factory.ts +793 -59
  241. package/typechain-types/factories/contracts/token/PrivateERC20/index.ts +3 -0
  242. package/typechain-types/factories/contracts/token/PrivateERC20/tokens/PrivateBridgedUSDC__factory.ts +1445 -0
  243. package/typechain-types/factories/contracts/token/PrivateERC20/tokens/PrivateCOTITreasuryGovernanceToken__factory.ts +1451 -0
  244. package/typechain-types/factories/contracts/token/PrivateERC20/tokens/PrivateCOTI__factory.ts +1442 -0
  245. package/typechain-types/factories/contracts/token/PrivateERC20/tokens/PrivateTetherUSD__factory.ts +1445 -0
  246. package/typechain-types/factories/contracts/token/PrivateERC20/tokens/PrivateWrappedADA__factory.ts +1445 -0
  247. package/typechain-types/factories/contracts/token/PrivateERC20/tokens/PrivateWrappedBTC__factory.ts +1445 -0
  248. package/typechain-types/factories/contracts/token/PrivateERC20/tokens/PrivateWrappedEther__factory.ts +1451 -0
  249. package/typechain-types/factories/contracts/token/PrivateERC20/tokens/index.ts +10 -0
  250. package/typechain-types/factories/contracts/utils/mpc/MpcCore__factory.ts +1 -1
  251. package/typechain-types/hardhat.d.ts +953 -17
  252. package/typechain-types/index.ts +104 -0
  253. package/typechain-types/contracts/mocks/utils/mpc/Arithmetic128BitTestsContract.ts +0 -341
  254. package/typechain-types/contracts/mocks/utils/mpc/Arithmetic256BitTestsContract.ts +0 -347
  255. package/typechain-types/contracts/mocks/utils/mpc/Bitwise256BitTestsContract.ts +0 -186
  256. package/typechain-types/contracts/mocks/utils/mpc/Comparison128BitTestsContract.ts +0 -260
  257. package/typechain-types/contracts/mocks/utils/mpc/Comparison256BitTestsContract.ts +0 -260
  258. package/typechain-types/contracts/mocks/utils/mpc/Miscellaneous128BitTestsContract.ts +0 -302
  259. package/typechain-types/contracts/mocks/utils/mpc/Miscellaneous256BitTestsContract.ts +0 -322
  260. package/typechain-types/factories/contracts/mocks/utils/mpc/Arithmetic128BitTestsContract__factory.ts +0 -349
  261. package/typechain-types/factories/contracts/mocks/utils/mpc/Arithmetic256BitTestsContract__factory.ts +0 -364
  262. package/typechain-types/factories/contracts/mocks/utils/mpc/Bitwise128BitTestsContract__factory.ts +0 -182
  263. package/typechain-types/factories/contracts/mocks/utils/mpc/Bitwise256BitTestsContract__factory.ts +0 -182
  264. package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison128BitTestsContract__factory.ts +0 -255
  265. package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison256BitTestsContract__factory.ts +0 -255
  266. package/typechain-types/factories/contracts/mocks/utils/mpc/Miscellaneous128BitTestsContract__factory.ts +0 -332
  267. package/typechain-types/factories/contracts/mocks/utils/mpc/Miscellaneous256BitTestsContract__factory.ts +0 -380
@@ -4,24 +4,60 @@ pragma solidity ^0.8.19;
4
4
  import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
5
5
  import "@openzeppelin/contracts/security/Pausable.sol";
6
6
  import "@openzeppelin/contracts/access/Ownable.sol";
7
- import "@openzeppelin/contracts/access/AccessControl.sol";
8
- import "@openzeppelin/contracts/utils/math/Math.sol";
7
+ import "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
8
+ import "../oracle/ICotiPriceConsumer.sol";
9
9
 
10
10
  /**
11
11
  * @title PrivacyBridge
12
12
  * @notice Base contract for Privacy Bridge contracts containing common logic
13
13
  * @dev Trust assumptions: (1) MPC precompile at expected address is correct and non-malicious.
14
14
  * (2) Private token implementation is trusted and only authorized minters can mint.
15
- * (3) Owner operations (limits, fees, pause, withdraw fees, rescue) are centralized; consider timelock/multisig for sensitive actions.
16
- * (4) Any new derived bridge must override withdrawFees to perform the actual transfer; base implementation reverts.
15
+ * (3) Pause and rescue (governance-critical): The owner can {pause}. While paused, derived bridges expose
16
+ * owner-only rescue entry points ({PrivacyBridgeCotiNative.rescueNative}, {PrivacyBridgeERC20.rescueERC20})
17
+ * that send value to {rescueRecipient}. Those calls can transfer the contract's entire relevant balance,
18
+ * including liquidity that backs user obligations (full TVL migration). That is the intended emergency
19
+ * response after a bug or to retire a deployment; it is not enforced user-by-user on-chain. Treat
20
+ * owner key compromise after pause as catastrophic TVL loss to {rescueRecipient}. Mitigations are
21
+ * operational: multisig or timelock on ownership, strict {rescueRecipient} policy, monitoring of
22
+ * {Paused} and rescue events, and separation of duties where possible.
23
+ * (4) Oracle prices are trusted; {maxOracleAge} bounds staleness of `lastUpdated` (owner cannot set it to zero;
24
+ * use a large value only if a very lenient window is intended). Does not remove oracle trust.
25
+ * (5) {totalUserLiability} is bridge bookkeeping for transparency: it tracks net user obligations from mint/burn
26
+ * paths in this contract only. It helps depositors/observers reason about exposure; it is not a
27
+ * cryptographic proof of MPC/private-token balances and can diverge if the token layer misbehaves.
28
+ * **Docs / integrators:** Compare this counter to collateral still held by *this* contract (ERC20:
29
+ * {PrivacyBridgeERC20.token} balance; native: {address(this).balance}) for a liquidity snapshot. After
30
+ * {rescueERC20}/{rescueNative}, collateral may sit at {rescueRecipient} while this counter is unchanged—
31
+ * economic claims on outstanding private supply are not extinguished by rescue; do not treat the counter
32
+ * as “assets on hand” post-migration. Forced native (e.g. `selfdestruct`) increases balance but **never**
33
+ * mints private tokens and does **not** increase {totalUserLiability} (no user deposit path).
34
+ * (6) For COTI-operated deployments, residual trust in MPC/private-token behavior beyond (2) and (5), and in oracle
35
+ * *market* correctness beyond (4), is an accepted operational assumption; the on-chain mitigations above
36
+ * are the intended scope for those concerns in this module.
37
+ * (7) **Centralized control:** A single `Ownable` owner and any `OPERATOR_ROLE` grantees can configure pause,
38
+ * oracle rotation, deposit/withdraw limits, blacklist, and fee *parameters* (floors/caps/percentages) exposed
39
+ * in this module. **Fee and rescue destinations are fixed at deployment**—there are no setters for
40
+ * {feeRecipient} or {rescueRecipient}, so a compromised owner **cannot** redirect rescue or fee sweep
41
+ * addresses to an attacker (trade-off: a wrong address at deploy or a reverting recipient must be handled
42
+ * operationally / via migration). {transferOwnership} enumerates and revokes all role members, which can
43
+ * become gas-heavy with many operators; that cost is accepted. The contracts are not upgradeable via
44
+ * delegatecall within this package. Operational mitigations are off-chain: multisig or timelock on
45
+ * ownership, least-privilege operators, and monitoring.
46
+ * (8) **Oracle binding:** {_validateOracleTimestamps} requires exact equality to the user-supplied Band row
47
+ * timestamps so the fee quote cannot change between estimate and execution without a revert. With a
48
+ * typical ~30 minute feed cadence (plus {maxOracleAge} buffer), users have ample time to sign and submit
49
+ * the same row; relaxing this binding is intentionally rejected to avoid showing one price and settling
50
+ * at another.
17
51
  */
18
- abstract contract PrivacyBridge is ReentrancyGuard, Pausable, Ownable, AccessControl {
52
+ abstract contract PrivacyBridge is ReentrancyGuard, Pausable, Ownable, AccessControlEnumerable {
19
53
  bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
20
54
 
21
55
  event OperatorAdded(address indexed account, address indexed by);
22
56
  event OperatorRemoved(address indexed account, address indexed by);
23
57
  event DepositEnabledUpdated(bool enabled, address indexed by);
24
- event NativeCotiFeeUpdated(uint256 fee, address indexed by);
58
+ event DynamicFeeUpdated(string feeType, uint256 fixedFee, uint256 percentageBps, uint256 maxFee);
59
+ event PriceOracleUpdated(address indexed oldOracle, address indexed newOracle);
60
+ event MaxOracleAgeUpdated(uint256 maxOracleAge, address indexed by);
25
61
 
26
62
  /// @notice Maximum amount that can be deposited in a single transaction
27
63
  uint256 public maxDepositAmount;
@@ -35,19 +71,29 @@ abstract contract PrivacyBridge is ReentrancyGuard, Pausable, Ownable, AccessCon
35
71
  /// @notice Minimum amount required for a withdrawal
36
72
  uint256 public minWithdrawAmount;
37
73
 
38
- /// @notice Deposit fee in basis points (1 bp = 0.0001%, 1,000,000 = 100%)
39
- uint256 public depositFeeBasisPoints;
40
-
41
- /// @notice Withdrawal fee in basis points (1 bp = 0.0001%, 1,000,000 = 100%)
42
- uint256 public withdrawFeeBasisPoints;
43
-
44
- /// @notice Accumulated fees collected by the bridge (in bridged asset units)
45
- uint256 public accumulatedFees;
46
-
47
- /// @notice Accumulated native COTI fees (used only by ERC20 bridges for per-operation native fee; not used by native bridge)
74
+ /// @notice Booked native COTI fees not yet swept: both {PrivacyBridgeCotiNative} (deposit/withdraw fees)
75
+ /// and ERC20 bridges (per-operation dynamic native fee via {_collectDynamicNativeFee}) credit this counter.
76
+ /// Native bridge: {PrivacyBridgeCotiNative.withdrawFees}; ERC20 deployments: {withdrawCotiFees}.
48
77
  uint256 public accumulatedCotiFees;
49
78
 
50
- /// @notice Fee divisor (1,000,000)
79
+ /// @notice On-chain aggregate of bridge-issued user obligations from deposit/withdraw mint and burn paths
80
+ /// (native: net private minted; native withdraw: private burned; ERC20: public received in / amount out).
81
+ /// Intended for transparency so depositors and tooling can read how much liability the bridge tracks
82
+ /// in its own accounting. This does not attest to MPC correctness or encrypted token balances.
83
+ /// @dev Same scope as contract-level @dev (5): updates only follow explicit mint/burn paths; unsolicited native
84
+ /// (e.g. `selfdestruct`) does **not** increase this value and does not mint private tokens. If the private
85
+ /// token or MPC layer misreports or mis-mints, this counter can diverge from economic reality. Do not
86
+ /// treat it as a solvency proof or substitute for off-chain audits of the private ledger. Emergency
87
+ /// {rescueERC20}/{rescueNative} moves collateral out but does **not** change this counter—obligations
88
+ /// implied by outstanding private supply may then exceed assets held here until migration elsewhere.
89
+ /// **Integrators:** compare to on-contract collateral (see contract @dev (5)).
90
+ uint256 public totalUserLiability;
91
+
92
+ /// @notice Fee divisor (1,000,000). Fee math uses {Math.mulDiv} (OpenZeppelin): integer division **rounds down**
93
+ /// (toward zero) at each step, so on-chain fees are at most a few wei **lower** than an idealized
94
+ /// floating-point quote—bias slightly favors users, not the fee recipient.
95
+ /// @dev Pathological `amount` × oracle rate products can still overflow `uint256` and revert—operators should
96
+ /// set deposit/withdraw limits accordingly.
51
97
  uint256 public constant FEE_DIVISOR = 1000000;
52
98
 
53
99
  /// @notice Maximum fee allowed (10% = 100,000 units)
@@ -56,8 +102,46 @@ abstract contract PrivacyBridge is ReentrancyGuard, Pausable, Ownable, AccessCon
56
102
  /// @notice Flag to enable/disable deposits
57
103
  bool public isDepositEnabled = true;
58
104
 
59
- /// @notice Fee in native COTI for bridge operations
60
- uint256 public nativeCotiFee;
105
+ // Privacy Bridge defines default Fees
106
+ // those fees can be overwritten using
107
+ // setDepositDynamicFee available for OPERATORS and ADMIN
108
+
109
+ /// @notice Deposit fee floor in COTI wei
110
+ uint256 public depositFixedFee = 10 ether;
111
+
112
+ /// @notice Deposit percentage (500/1,000,000 = 0.05%)
113
+ uint256 public depositPercentageBps = 500;
114
+
115
+ /// @notice Deposit fee cap in COTI wei
116
+ uint256 public depositMaxFee = 3000 ether;
117
+
118
+ /// @notice Withdraw fee floor in COTI wei
119
+ uint256 public withdrawFixedFee = 3 ether;
120
+
121
+ /// @notice Withdraw percentage (250/1,000,000 = 0.025%)
122
+ uint256 public withdrawPercentageBps = 250;
123
+
124
+ /// @notice Withdraw fee cap in COTI wei
125
+ uint256 public withdrawMaxFee = 1500 ether;
126
+
127
+ // --- END OF DEFAULT FEES
128
+
129
+ /// @notice CotiPriceConsumer contract address (non-zero at construction; owner may {setPriceOracle} to rotate)
130
+ address public priceOracle;
131
+
132
+ /// @notice Default max oracle age: nominal ~30 minute feed cadence plus a 5 minute buffer so slightly delayed
133
+ /// updates or inclusion lag do not spuriously revert with {OraclePriceStale}.
134
+ uint256 public constant DEFAULT_MAX_ORACLE_AGE = 30 minutes + 5 minutes;
135
+
136
+ /// @notice Maximum allowed `block.timestamp - oracle lastUpdated` (seconds). Initialized to {DEFAULT_MAX_ORACLE_AGE};
137
+ /// owner may increase the window (e.g. for long test runs) but {setMaxOracleAge} rejects zero.
138
+ uint256 public maxOracleAge;
139
+
140
+ /// @notice Address where collected fees are sent (fixed at deploy; no setter—see contract @dev (7))
141
+ address public feeRecipient;
142
+
143
+ /// @notice Address where rescued funds are sent (fixed at deploy; no setter—see contract @dev (7))
144
+ address public rescueRecipient;
61
145
 
62
146
  error AmountZero();
63
147
  error InsufficientEthBalance();
@@ -66,6 +150,26 @@ abstract contract PrivacyBridge is ReentrancyGuard, Pausable, Ownable, AccessCon
66
150
  error DepositDisabled();
67
151
  error InsufficientCotiFee();
68
152
  error BridgePaused();
153
+ error OracleTimestampMismatch(uint256 expected, uint256 actual);
154
+ error PriceOracleNotSet();
155
+ error InvalidOraclePrice();
156
+ error OraclePriceStale(uint256 oracleLastUpdated, uint256 blockTimestamp, uint256 maxOracleAge);
157
+ error OracleLastUpdatedInFuture(uint256 lastUpdated);
158
+ error OracleMaxAgeZeroDisallowed();
159
+ error FeeRecipientNotSet();
160
+ error AddressBlacklisted(address account);
161
+
162
+ /// @notice Addresses blocked from depositing or withdrawing
163
+ mapping(address => bool) public blacklisted;
164
+
165
+ /// @notice Per-user native COTI credited when an ERC20 bridge excess refund could not be pushed to `msg.sender` (e.g. smart contract wallets).
166
+ /// @dev Indexed by the same address that called `deposit`/`withdraw`. Pull via {claimRefundableNativeExcess}; listen for {NativeRefundExcessPushFailed}.
167
+ mapping(address => uint256) public refundableNativeExcess;
168
+
169
+ event Blacklisted(address indexed account, address indexed by);
170
+ event UnBlacklisted(address indexed account, address indexed by);
171
+ event NativeRefundExcessPushFailed(address indexed user, uint256 amount);
172
+ event RefundableNativeExcessClaimed(address indexed user, uint256 amount);
69
173
 
70
174
  // Limits errors
71
175
  error InvalidLimitConfiguration();
@@ -74,8 +178,8 @@ abstract contract PrivacyBridge is ReentrancyGuard, Pausable, Ownable, AccessCon
74
178
  error WithdrawBelowMinimum();
75
179
  error WithdrawExceedsMaximum();
76
180
  error InvalidFee();
181
+ error InvalidFeeConfiguration();
77
182
  error InsufficientAccumulatedFees();
78
- error WithdrawFeesMustBeOverridden();
79
183
 
80
184
  /// @notice Emitted when a user deposits tokens
81
185
  /// @param user Address of the user
@@ -97,17 +201,28 @@ abstract contract PrivacyBridge is ReentrancyGuard, Pausable, Ownable, AccessCon
97
201
  uint256 maxWithdraw
98
202
  );
99
203
 
100
- /// @notice Emitted when fees are updated
101
- event FeeUpdated(string feeType, uint256 newFeeBasisPoints);
102
-
103
204
  /// @notice Emitted when accumulated fees are withdrawn
104
205
  event FeesWithdrawn(address indexed to, uint256 amount);
105
206
 
106
- constructor() Ownable() {
207
+ /**
208
+ * @param _feeRecipient Non-zero recipient for swept native fees (immutable for contract lifetime—no setter)
209
+ * @param _rescueRecipient Non-zero recipient for emergency rescue paths (immutable for contract lifetime—no setter)
210
+ * @param _priceOracle Non-zero {ICotiPriceConsumer} used for dynamic fees (owner may later {setPriceOracle})
211
+ */
212
+ constructor(address _feeRecipient, address _rescueRecipient, address _priceOracle) Ownable() {
213
+ if (_feeRecipient == address(0)) revert InvalidAddress();
214
+ if (_rescueRecipient == address(0)) revert InvalidAddress();
215
+ if (_priceOracle == address(0)) revert InvalidAddress();
107
216
  maxDepositAmount = type(uint256).max;
108
217
  maxWithdrawAmount = type(uint256).max;
109
218
  minDepositAmount = 1;
110
219
  minWithdrawAmount = 1;
220
+ feeRecipient = _feeRecipient;
221
+ rescueRecipient = _rescueRecipient;
222
+ priceOracle = _priceOracle;
223
+ maxOracleAge = DEFAULT_MAX_ORACLE_AGE;
224
+
225
+ emit PriceOracleUpdated(address(0), _priceOracle);
111
226
 
112
227
  _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
113
228
  _grantRole(OPERATOR_ROLE, msg.sender);
@@ -135,22 +250,86 @@ abstract contract PrivacyBridge is ReentrancyGuard, Pausable, Ownable, AccessCon
135
250
  }
136
251
 
137
252
  /**
138
- * @dev Overrides Ownable's transferOwnership to automatically grant roles to new owner
253
+ * @notice Transfers `Ownable` ownership and resets `AccessControl` admins/operators in one step.
254
+ * @dev **Handover semantics:** Every address with `OPERATOR_ROLE` and every address with `DEFAULT_ADMIN_ROLE`
255
+ * (including the current owner) is revoked before `Ownable` transfers to `newOwner`, who then receives
256
+ * both `DEFAULT_ADMIN_ROLE` and `OPERATOR_ROLE`. Any prior operator-only keys lose privilege immediately;
257
+ * plan key ceremonies and off-chain runbooks so no service relies on a revoked operator after transfer.
258
+ * This prevents stale operators from coexisting with a new owner (hidden privileged actors).
139
259
  */
140
260
  function transferOwnership(address newOwner) public override onlyOwner {
141
261
  if (newOwner == address(0)) revert InvalidAddress();
142
- address oldOwner = owner();
262
+
263
+ // Revoke all existing operators before transferring
264
+ uint256 operatorCount = getRoleMemberCount(OPERATOR_ROLE);
265
+ for (uint256 i = operatorCount; i > 0; i--) {
266
+ address op = getRoleMember(OPERATOR_ROLE, i - 1);
267
+ _revokeRole(OPERATOR_ROLE, op);
268
+ }
269
+
270
+ // Revoke all existing admins
271
+ uint256 adminCount = getRoleMemberCount(DEFAULT_ADMIN_ROLE);
272
+ for (uint256 i = adminCount; i > 0; i--) {
273
+ address admin = getRoleMember(DEFAULT_ADMIN_ROLE, i - 1);
274
+ _revokeRole(DEFAULT_ADMIN_ROLE, admin);
275
+ }
276
+
143
277
  super.transferOwnership(newOwner);
144
278
  _grantRole(DEFAULT_ADMIN_ROLE, newOwner);
145
279
  _grantRole(OPERATOR_ROLE, newOwner);
146
- _revokeRole(DEFAULT_ADMIN_ROLE, oldOwner);
147
- _revokeRole(OPERATOR_ROLE, oldOwner);
280
+ }
281
+
282
+ /**
283
+ * @dev **Intentionally disabled** (reverts with a fixed message). `renounceOwnership` would leave `AccessControl`
284
+ * roles and admins in place while clearing `Ownable.owner`, producing ambiguous governance (`onlyOwner`
285
+ * vs `onlyRole`). Use {transferOwnership} to a burn/multisig address if governance must be vacated, after
286
+ * revoking roles through the normal owner-controlled flows this contract expects.
287
+ */
288
+ function renounceOwnership() public override onlyOwner {
289
+ revert("renounceOwnership disabled");
290
+ }
291
+
292
+ /**
293
+ * @notice Add an address to the blacklist, preventing deposits and withdrawals.
294
+ * @param account The address to blacklist
295
+ * @dev Only the owner can call this function.
296
+ */
297
+ function addToBlacklist(address account) external onlyOwner {
298
+ if (account == address(0)) revert InvalidAddress();
299
+ blacklisted[account] = true;
300
+ emit Blacklisted(account, msg.sender);
301
+ }
302
+
303
+ /**
304
+ * @notice Remove an address from the blacklist.
305
+ * @param account The address to remove
306
+ * @dev Only the owner can call this function.
307
+ */
308
+ function removeFromBlacklist(address account) external onlyOwner {
309
+ if (account == address(0)) revert InvalidAddress();
310
+ blacklisted[account] = false;
311
+ emit UnBlacklisted(account, msg.sender);
312
+ }
313
+
314
+ /**
315
+ * @dev Reverts if the caller is blacklisted. Applies to deposit, withdraw, and {claimRefundableNativeExcess}.
316
+ * Blacklisted addresses are intentionally **not** exempted on claim: policy treats them as abusive;
317
+ * credited {refundableNativeExcess} for that address remains until the owner removes the listing or
318
+ * another agreed process applies.
319
+ */
320
+ modifier notBlacklisted() {
321
+ if (blacklisted[msg.sender]) revert AddressBlacklisted(msg.sender);
322
+ _;
148
323
  }
149
324
 
150
325
  /**
151
326
  * @notice Update deposit and withdrawal limits
152
327
  * @dev Ensures min values are less than or equal to max values.
153
328
  * Setting _maxDeposit or _maxWithdraw to 0 effectively disables deposits or withdrawals.
329
+ * Note: cross-parameter coherence (e.g. minDeposit after fee >= minWithdraw) cannot be
330
+ * validated on-chain because fees are dynamic and depend on the oracle price at transaction
331
+ * time, not at the time limits are set. The operator is responsible for ensuring that the
332
+ * smallest valid deposit mints at least the smallest valid withdrawal amount.
154
333
  * @param _minDeposit New minimum deposit amount
155
334
  * @param _maxDeposit New maximum deposit amount
156
335
  * @param _minWithdraw New minimum withdrawal amount
@@ -178,8 +357,10 @@ abstract contract PrivacyBridge is ReentrancyGuard, Pausable, Ownable, AccessCon
178
357
  }
179
358
 
180
359
  /**
181
- * @notice Pause the bridge, preventing deposits and withdrawals
182
- * @dev Only the owner can call this function
360
+ * @notice Emergency stop — pause the bridge, preventing all deposits and withdrawals.
361
+ * @dev Only the owner can call this function. Pausing also gates rescue paths on derived contracts: once
362
+ * paused, the owner can move TVL via rescue (see contract @dev (3)). Use pause only with operational
363
+ * awareness of that combined authority.
183
364
  */
184
365
  function pause() external onlyOwner {
185
366
  _pause();
@@ -214,105 +395,206 @@ abstract contract PrivacyBridge is ReentrancyGuard, Pausable, Ownable, AccessCon
214
395
  }
215
396
 
216
397
  /**
217
- * @notice Set the deposit fee
218
- * @param _feeBasisPoints New deposit fee in fee units (max 100,000 = 10%)
398
+ * @notice Toggle deposit functionality
399
+ * @param _enabled True to enable, false to disable
219
400
  * @dev Only the operator can call this function
220
401
  */
221
- function setDepositFee(uint256 _feeBasisPoints) external onlyOperator {
222
- if (_feeBasisPoints > MAX_FEE_UNITS) revert InvalidFee();
223
- depositFeeBasisPoints = _feeBasisPoints;
224
- emit FeeUpdated("deposit", _feeBasisPoints);
402
+ function setIsDepositEnabled(bool _enabled) external onlyOperator {
403
+ isDepositEnabled = _enabled;
404
+ emit DepositEnabledUpdated(_enabled, msg.sender);
405
+ }
406
+
407
+ function _requirePriceOracle() internal view {
408
+ if (priceOracle == address(0)) revert PriceOracleNotSet();
409
+ }
410
+
411
+ function _requirePositiveOracleRate(uint256 rate) internal pure {
412
+ if (rate == 0) revert InvalidOraclePrice();
225
413
  }
226
414
 
227
415
  /**
228
- * @notice Set the withdrawal fee
229
- * @param _feeBasisPoints New withdrawal fee in fee units (max 100,000 = 10%)
230
- * @dev Only the operator can call this function
416
+ * @dev Credits `user` when the ERC20 bridge’s push-refund of native excess after fee collection returns false
417
+ * (common with smart contract accounts / AA wallets that reject unsolicited ETH, or `receive`/`fallback`
418
+ * reverts). Funds remain on the bridge until {claimRefundableNativeExcess}. UIs should watch
419
+ * {NativeRefundExcessPushFailed} and prompt the same `user` to claim; the amount is not in
420
+ * {accumulatedCotiFees} and cannot be swept as protocol fees.
231
421
  */
232
- function setWithdrawFee(uint256 _feeBasisPoints) external onlyOperator {
233
- if (_feeBasisPoints > MAX_FEE_UNITS) revert InvalidFee();
234
- withdrawFeeBasisPoints = _feeBasisPoints;
235
- emit FeeUpdated("withdraw", _feeBasisPoints);
422
+ function _creditRefundableNativeExcess(address user, uint256 amount) internal {
423
+ refundableNativeExcess[user] += amount;
424
+ emit NativeRefundExcessPushFailed(user, amount);
236
425
  }
237
426
 
238
427
  /**
239
- * @notice Toggle deposit functionality
240
- * @param _enabled True to enable, false to disable
241
- * @dev Only the operator can call this function
428
+ * @notice Pull native COTI previously credited when the ERC20 bridge could not push the fee excess to you.
429
+ * @dev Same push pattern as the original refund: `msg.sender.call{value: amount}`. If your wallet still
430
+ * rejects ETH, the call reverts with {EthTransferFailed} and your credit is restored so you can try
431
+ * again from an address that accepts native transfers (the protocol does not support forwarding to a
432
+ * third-party payout address). Not gated by {whenPaused}; {notBlacklisted} applies ({AddressBlacklisted})—
433
+ * blacklisted callers cannot pull credits by design (see {notBlacklisted}).
242
434
  */
243
- function setIsDepositEnabled(bool _enabled) external onlyOperator {
244
- isDepositEnabled = _enabled;
245
- emit DepositEnabledUpdated(_enabled, msg.sender);
435
+ function claimRefundableNativeExcess() external nonReentrant notBlacklisted {
436
+ uint256 amount = refundableNativeExcess[msg.sender];
437
+ if (amount == 0) revert AmountZero();
438
+ refundableNativeExcess[msg.sender] = 0;
439
+ if (address(this).balance < amount) revert InsufficientEthBalance();
440
+ (bool success, ) = msg.sender.call{value: amount}("");
441
+ if (!success) {
442
+ refundableNativeExcess[msg.sender] = amount;
443
+ revert EthTransferFailed();
444
+ }
445
+ emit RefundableNativeExcessClaimed(msg.sender, amount);
246
446
  }
247
447
 
248
448
  /**
249
- * @notice Set the native COTI fee
250
- * @param _fee Amount in native tokens (wei-equivalent)
251
- * @dev Used by ERC20 bridges: they require msg.value >= this value and refund excess to the caller (best-effort). Only the operator can call this function.
449
+ * @notice Reject oracle rows that are too old vs `block.timestamp` per {maxOracleAge}.
450
+ * @dev {maxOracleAge} is always non-zero in normal configuration ({setMaxOracleAge} forbids zero).
252
451
  */
253
- function setNativeCotiFee(uint256 _fee) external onlyOperator {
254
- nativeCotiFee = _fee;
255
- emit NativeCotiFeeUpdated(_fee, msg.sender);
452
+ function _requireOracleFreshness(uint256 lastUpdated) internal view {
453
+ uint256 maxAge = maxOracleAge;
454
+ if (lastUpdated > block.timestamp) revert OracleLastUpdatedInFuture(lastUpdated);
455
+ uint256 nowTs = block.timestamp;
456
+ if (nowTs - lastUpdated > maxAge) revert OraclePriceStale(lastUpdated, nowTs, maxAge);
256
457
  }
257
458
 
258
459
  /**
259
- * @notice Deposit preflight checks (for derived contracts)
260
- * @dev Enforces pause state, deposit toggle, and amount limits.
460
+ * @notice Validate oracle timestamps for both COTI and a bridged token.
461
+ * @dev Strict equality: on-chain `lastUpdated` for COTI and for `tokenSymbol` must exactly equal the
462
+ * `expected*` values supplied by the client. That binds execution to the same Band row the user
463
+ * saw when calling the estimate view; if the feed publishes a newer row before inclusion, the check
464
+ * reverts with {OracleTimestampMismatch} so price cannot change under the user without a visible revert.
465
+ * This strict binding is **intentional** (no relaxation): with a typical ~30 minute oracle cadence and
466
+ * {maxOracleAge} buffer, users have a long window to sign and broadcast the same row; we avoid any path
467
+ * where the UI shows one Band row and execution silently uses a newer price.
468
+ * Failures are timing/race issues (mempool delay vs oracle refresh cadence), not third-party griefing.
469
+ * Integrators: call estimate immediately before building the tx; pass returned timestamps unchanged into
470
+ * deposit/withdraw; on mismatch, re-estimate and resubmit; avoid submit across a refresh boundary (COTI UI
471
+ * blocks ~10s before a scheduled tick—mirror that); simulate right before broadcast. {_requireOracleFreshness}
472
+ * still enforces {maxOracleAge} on the matched row.
473
+ * @param expectedCotiTimestamp COTI `lastUpdated` from the user's latest estimate (must equal on-chain).
474
+ * @param expectedTokenTimestamp Token `lastUpdated` from the user's latest estimate (must equal on-chain).
475
+ * @param tokenSymbol The Band oracle symbol for the bridged token (native bridge uses `"COTI"` for both).
261
476
  */
262
- function _preflightDeposit(uint256 amount) internal view {
263
- if (paused()) revert BridgePaused();
264
- if (!isDepositEnabled) revert DepositDisabled();
265
- _checkDepositLimits(amount);
477
+ function _validateOracleTimestamps(
478
+ uint256 expectedCotiTimestamp,
479
+ uint256 expectedTokenTimestamp,
480
+ string memory tokenSymbol
481
+ ) internal view {
482
+ _requirePriceOracle();
483
+ (, uint256 cotiLastUpdated,) = ICotiPriceConsumer(priceOracle).getPriceWithMeta("COTI");
484
+ if (cotiLastUpdated != expectedCotiTimestamp) revert OracleTimestampMismatch(expectedCotiTimestamp, cotiLastUpdated);
485
+ _requireOracleFreshness(cotiLastUpdated);
486
+ (, uint256 tokenLastUpdated,) = ICotiPriceConsumer(priceOracle).getPriceWithMeta(tokenSymbol);
487
+ if (tokenLastUpdated != expectedTokenTimestamp) revert OracleTimestampMismatch(expectedTokenTimestamp, tokenLastUpdated);
488
+ _requireOracleFreshness(tokenLastUpdated);
266
489
  }
267
490
 
268
-
269
491
  /**
270
- * @notice Calculate fee amount based on the input amount and fee basis points
271
- * @param amount The amount to calculate fee for
272
- * @param feeBasisPoints Fee in basis points (100 bp = 1%)
273
- * @return The fee amount
492
+ * @notice Calculate the dynamic fee using the floor/cap formula
493
+ * @param percentageFeeCoti The percentage-based fee component in COTI
494
+ * @param fixedFee The minimum fee floor in COTI
495
+ * @param maxFee The maximum fee cap in COTI
496
+ * @return The computed fee: min(max(fixedFee, percentageFeeCoti), maxFee)
274
497
  */
275
- function _calculateFeeAmount(
276
- uint256 amount,
277
- uint256 feeBasisPoints
498
+ function _calculateDynamicFee(
499
+ uint256 percentageFeeCoti,
500
+ uint256 fixedFee,
501
+ uint256 maxFee
278
502
  ) internal pure returns (uint256) {
279
- if (feeBasisPoints == 0) return 0;
280
- return Math.mulDiv(amount, feeBasisPoints, FEE_DIVISOR);
503
+ uint256 fee = percentageFeeCoti > fixedFee ? percentageFeeCoti : fixedFee;
504
+ return fee > maxFee ? maxFee : fee;
281
505
  }
282
506
 
283
507
  /**
284
- * @notice Withdraw accumulated fees
285
- * @param to Address to send the fees to
286
- * @param amount Amount of fees to withdraw
287
- * @dev Only the operator can call this function. Must be overridden in derived contracts
288
- * to perform the actual token/native transfer; base implementation reverts.
508
+ * @notice Estimate functions are declared in derived contracts (Native and ERC20 bridges)
509
+ * with different return signatures:
510
+ * - Native: returns (fee, lastUpdated, blockTimestamp)
511
+ * - ERC20: returns (fee, cotiLastUpdated, tokenLastUpdated, blockTimestamp)
289
512
  */
290
- function withdrawFees(
291
- address to,
292
- uint256 amount
293
- ) external virtual onlyOperator {
294
- if (to == address(0)) revert InvalidAddress();
295
- if (amount == 0) revert AmountZero();
296
- if (amount > accumulatedFees) revert InsufficientAccumulatedFees();
297
- revert WithdrawFeesMustBeOverridden();
513
+
514
+ /**
515
+ * @notice Set the deposit dynamic fee parameters
516
+ * @param _fixedFee New deposit fee floor in COTI wei
517
+ * @param _percentageBps New deposit percentage (max MAX_FEE_UNITS = 10%)
518
+ * @param _maxFee New deposit fee cap in COTI wei
519
+ * @dev Only the operator can call this function
520
+ */
521
+ function setDepositDynamicFee(
522
+ uint256 _fixedFee,
523
+ uint256 _percentageBps,
524
+ uint256 _maxFee
525
+ ) external onlyOperator {
526
+ if (_maxFee == 0) revert InvalidFeeConfiguration();
527
+ if (_fixedFee > _maxFee) revert InvalidFeeConfiguration();
528
+ if (_percentageBps > MAX_FEE_UNITS) revert InvalidFee();
529
+ depositFixedFee = _fixedFee;
530
+ depositPercentageBps = _percentageBps;
531
+ depositMaxFee = _maxFee;
532
+ emit DynamicFeeUpdated("deposit", _fixedFee, _percentageBps, _maxFee);
533
+ }
534
+
535
+ /**
536
+ * @notice Set the withdraw dynamic fee parameters
537
+ * @param _fixedFee New withdraw fee floor in COTI wei
538
+ * @param _percentageBps New withdraw percentage (max MAX_FEE_UNITS = 10%)
539
+ * @param _maxFee New withdraw fee cap in COTI wei
540
+ * @dev Only the operator can call this function
541
+ */
542
+ function setWithdrawDynamicFee(
543
+ uint256 _fixedFee,
544
+ uint256 _percentageBps,
545
+ uint256 _maxFee
546
+ ) external onlyOperator {
547
+ if (_maxFee == 0) revert InvalidFeeConfiguration();
548
+ if (_fixedFee > _maxFee) revert InvalidFeeConfiguration();
549
+ if (_percentageBps > MAX_FEE_UNITS) revert InvalidFee();
550
+ withdrawFixedFee = _fixedFee;
551
+ withdrawPercentageBps = _percentageBps;
552
+ withdrawMaxFee = _maxFee;
553
+ emit DynamicFeeUpdated("withdraw", _fixedFee, _percentageBps, _maxFee);
554
+ }
555
+
556
+ /**
557
+ * @notice Set the price oracle address
558
+ * @param _oracle Address of the CotiPriceConsumer contract
559
+ * @dev Only the owner can call this function
560
+ */
561
+ function setPriceOracle(address _oracle) external onlyOwner {
562
+ if (_oracle == address(0)) revert InvalidAddress();
563
+ address oldOracle = priceOracle;
564
+ priceOracle = _oracle;
565
+ emit PriceOracleUpdated(oldOracle, _oracle);
566
+ }
567
+
568
+ /**
569
+ * @notice Set the maximum allowed age of oracle `lastUpdated` (seconds) relative to `block.timestamp`.
570
+ * @param _maxOracleAge Must be non-zero. Default after deploy is {DEFAULT_MAX_ORACLE_AGE} (30 min cadence + 5 min buffer).
571
+ * @dev Zero is rejected so production cannot accidentally turn off staleness bounds; for very lenient test
572
+ * environments use a large finite value instead.
573
+ */
574
+ function setMaxOracleAge(uint256 _maxOracleAge) external onlyOwner {
575
+ if (_maxOracleAge == 0) revert OracleMaxAgeZeroDisallowed();
576
+ maxOracleAge = _maxOracleAge;
577
+ emit MaxOracleAgeUpdated(_maxOracleAge, msg.sender);
298
578
  }
299
579
 
580
+ event CotiFeesWithdrawn(address indexed feeRecipient, uint256 amount);
581
+
300
582
  /**
301
- * @notice Withdraw accumulated native COTI fees
302
- * @param to Address to send the native COTI fees to
583
+ * @notice Withdraw accumulated native COTI fees to the predefined feeRecipient
303
584
  * @param amount Amount of native COTI fees to withdraw
304
- * @dev Only the operator can call this function. Derived ERC20 bridges use this inherited implementation to withdraw
305
- * accumulated native COTI fees; native bridge does not use this (accumulatedCotiFees remains 0).
585
+ * @dev Only the owner can call this function.
306
586
  */
307
- function withdrawCotiFees(address to, uint256 amount) external onlyOperator nonReentrant {
308
- if (to == address(0)) revert InvalidAddress();
587
+ function withdrawCotiFees(uint256 amount) external onlyOwner nonReentrant {
588
+ if (feeRecipient == address(0)) revert FeeRecipientNotSet();
309
589
  if (amount == 0) revert AmountZero();
310
590
  if (amount > accumulatedCotiFees) revert InsufficientAccumulatedFees();
311
591
  if (amount > address(this).balance) revert InsufficientEthBalance();
312
592
 
313
593
  accumulatedCotiFees -= amount;
314
594
 
315
- (bool success, ) = to.call{value: amount}("");
595
+ (bool success, ) = feeRecipient.call{value: amount}("");
316
596
  if (!success) revert EthTransferFailed();
597
+
598
+ emit CotiFeesWithdrawn(feeRecipient, amount);
317
599
  }
318
600
  }