@towns-protocol/web3 0.0.191

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 (327) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +3 -0
  3. package/dist/ContractHelpers.d.ts +18 -0
  4. package/dist/ContractHelpers.d.ts.map +1 -0
  5. package/dist/ContractHelpers.js +75 -0
  6. package/dist/ContractHelpers.js.map +1 -0
  7. package/dist/ContractTypes.d.ts +143 -0
  8. package/dist/ContractTypes.d.ts.map +1 -0
  9. package/dist/ContractTypes.js +65 -0
  10. package/dist/ContractTypes.js.map +1 -0
  11. package/dist/ConvertersEntitlements.d.ts +10 -0
  12. package/dist/ConvertersEntitlements.d.ts.map +1 -0
  13. package/dist/ConvertersEntitlements.js +120 -0
  14. package/dist/ConvertersEntitlements.js.map +1 -0
  15. package/dist/ConvertersRoles.d.ts +8 -0
  16. package/dist/ConvertersRoles.d.ts.map +1 -0
  17. package/dist/ConvertersRoles.js +94 -0
  18. package/dist/ConvertersRoles.js.map +1 -0
  19. package/dist/DelegateRegistry.d.ts +3 -0
  20. package/dist/DelegateRegistry.d.ts.map +1 -0
  21. package/dist/DelegateRegistry.js +72 -0
  22. package/dist/DelegateRegistry.js.map +1 -0
  23. package/dist/EntitlementCache.d.ts +20 -0
  24. package/dist/EntitlementCache.d.ts.map +1 -0
  25. package/dist/EntitlementCache.js +41 -0
  26. package/dist/EntitlementCache.js.map +1 -0
  27. package/dist/EntitlementCache.test.d.ts +5 -0
  28. package/dist/EntitlementCache.test.d.ts.map +1 -0
  29. package/dist/EntitlementCache.test.js +130 -0
  30. package/dist/EntitlementCache.test.js.map +1 -0
  31. package/dist/ISpaceDapp.d.ts +193 -0
  32. package/dist/ISpaceDapp.d.ts.map +1 -0
  33. package/dist/ISpaceDapp.js +2 -0
  34. package/dist/ISpaceDapp.js.map +1 -0
  35. package/dist/IStaticContractsInfo.d.ts +28 -0
  36. package/dist/IStaticContractsInfo.d.ts.map +1 -0
  37. package/dist/IStaticContractsInfo.js +13 -0
  38. package/dist/IStaticContractsInfo.js.map +1 -0
  39. package/dist/LocalhostWeb3Provider.d.ts +15 -0
  40. package/dist/LocalhostWeb3Provider.d.ts.map +1 -0
  41. package/dist/LocalhostWeb3Provider.js +60 -0
  42. package/dist/LocalhostWeb3Provider.js.map +1 -0
  43. package/dist/MockCrossChainEntitlement.d.ts +6 -0
  44. package/dist/MockCrossChainEntitlement.d.ts.map +1 -0
  45. package/dist/MockCrossChainEntitlement.js +104 -0
  46. package/dist/MockCrossChainEntitlement.js.map +1 -0
  47. package/dist/MockERC1155.d.ts +6 -0
  48. package/dist/MockERC1155.d.ts.map +1 -0
  49. package/dist/MockERC1155.js +518 -0
  50. package/dist/MockERC1155.js.map +1 -0
  51. package/dist/MockERC20.d.ts +6 -0
  52. package/dist/MockERC20.d.ts.map +1 -0
  53. package/dist/MockERC20.js +574 -0
  54. package/dist/MockERC20.js.map +1 -0
  55. package/dist/MockERC721A.d.ts +1563 -0
  56. package/dist/MockERC721A.d.ts.map +1 -0
  57. package/dist/MockERC721A.js +1913 -0
  58. package/dist/MockERC721A.js.map +1 -0
  59. package/dist/RiverRegistryFactory.d.ts +5 -0
  60. package/dist/RiverRegistryFactory.d.ts.map +1 -0
  61. package/dist/RiverRegistryFactory.js +5 -0
  62. package/dist/RiverRegistryFactory.js.map +1 -0
  63. package/dist/SpaceDappFactory.d.ts +5 -0
  64. package/dist/SpaceDappFactory.d.ts.map +1 -0
  65. package/dist/SpaceDappFactory.js +8 -0
  66. package/dist/SpaceDappFactory.js.map +1 -0
  67. package/dist/TestCrossChainEntitlement.d.ts +14 -0
  68. package/dist/TestCrossChainEntitlement.d.ts.map +1 -0
  69. package/dist/TestCrossChainEntitlement.js +100 -0
  70. package/dist/TestCrossChainEntitlement.js.map +1 -0
  71. package/dist/TestEthBalance.d.ts +60 -0
  72. package/dist/TestEthBalance.d.ts.map +1 -0
  73. package/dist/TestEthBalance.js +94 -0
  74. package/dist/TestEthBalance.js.map +1 -0
  75. package/dist/TestGatingERC1155.d.ts +17 -0
  76. package/dist/TestGatingERC1155.d.ts.map +1 -0
  77. package/dist/TestGatingERC1155.js +101 -0
  78. package/dist/TestGatingERC1155.js.map +1 -0
  79. package/dist/TestGatingERC20.d.ts +17 -0
  80. package/dist/TestGatingERC20.d.ts.map +1 -0
  81. package/dist/TestGatingERC20.js +149 -0
  82. package/dist/TestGatingERC20.js.map +1 -0
  83. package/dist/TestGatingNFT.d.ts +17 -0
  84. package/dist/TestGatingNFT.d.ts.map +1 -0
  85. package/dist/TestGatingNFT.js +140 -0
  86. package/dist/TestGatingNFT.js.map +1 -0
  87. package/dist/TestGatingUtils.d.ts +15 -0
  88. package/dist/TestGatingUtils.d.ts.map +1 -0
  89. package/dist/TestGatingUtils.js +112 -0
  90. package/dist/TestGatingUtils.js.map +1 -0
  91. package/dist/Utils.d.ts +59 -0
  92. package/dist/Utils.d.ts.map +1 -0
  93. package/dist/Utils.js +122 -0
  94. package/dist/Utils.js.map +1 -0
  95. package/dist/Web3Constants.d.ts +6 -0
  96. package/dist/Web3Constants.d.ts.map +1 -0
  97. package/dist/Web3Constants.js +7 -0
  98. package/dist/Web3Constants.js.map +1 -0
  99. package/dist/Web3Constants.test.d.ts +2 -0
  100. package/dist/Web3Constants.test.d.ts.map +1 -0
  101. package/dist/Web3Constants.test.js +15 -0
  102. package/dist/Web3Constants.test.js.map +1 -0
  103. package/dist/chain.d.ts +65 -0
  104. package/dist/chain.d.ts.map +1 -0
  105. package/dist/chain.js +48 -0
  106. package/dist/chain.js.map +1 -0
  107. package/dist/entitlement.d.ts +146 -0
  108. package/dist/entitlement.d.ts.map +1 -0
  109. package/dist/entitlement.js +931 -0
  110. package/dist/entitlement.js.map +1 -0
  111. package/dist/entitlement.test.d.ts +2 -0
  112. package/dist/entitlement.test.d.ts.map +1 -0
  113. package/dist/entitlement.test.js +1743 -0
  114. package/dist/entitlement.test.js.map +1 -0
  115. package/dist/error-types.d.ts +7 -0
  116. package/dist/error-types.d.ts.map +1 -0
  117. package/dist/error-types.js +13 -0
  118. package/dist/error-types.js.map +1 -0
  119. package/dist/index.d.ts +76 -0
  120. package/dist/index.d.ts.map +1 -0
  121. package/dist/index.js +76 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/types.d.ts +29 -0
  124. package/dist/types.d.ts.map +1 -0
  125. package/dist/types.js +2 -0
  126. package/dist/types.js.map +1 -0
  127. package/dist/utils.test.d.ts +2 -0
  128. package/dist/utils.test.d.ts.map +1 -0
  129. package/dist/utils.test.js +44 -0
  130. package/dist/utils.test.js.map +1 -0
  131. package/dist/v3/BaseContractShim.d.ts +28 -0
  132. package/dist/v3/BaseContractShim.d.ts.map +1 -0
  133. package/dist/v3/BaseContractShim.js +185 -0
  134. package/dist/v3/BaseContractShim.js.map +1 -0
  135. package/dist/v3/BaseRegistry.d.ts +30 -0
  136. package/dist/v3/BaseRegistry.d.ts.map +1 -0
  137. package/dist/v3/BaseRegistry.js +64 -0
  138. package/dist/v3/BaseRegistry.js.map +1 -0
  139. package/dist/v3/EIP-712.d.ts +35 -0
  140. package/dist/v3/EIP-712.d.ts.map +1 -0
  141. package/dist/v3/EIP-712.js +57 -0
  142. package/dist/v3/EIP-712.js.map +1 -0
  143. package/dist/v3/IBanningShim.d.ts +7 -0
  144. package/dist/v3/IBanningShim.d.ts.map +1 -0
  145. package/dist/v3/IBanningShim.js +8 -0
  146. package/dist/v3/IBanningShim.js.map +1 -0
  147. package/dist/v3/IChannelShim.d.ts +8 -0
  148. package/dist/v3/IChannelShim.d.ts.map +1 -0
  149. package/dist/v3/IChannelShim.js +8 -0
  150. package/dist/v3/IChannelShim.js.map +1 -0
  151. package/dist/v3/ICreateSpaceShim.d.ts +9 -0
  152. package/dist/v3/ICreateSpaceShim.d.ts.map +1 -0
  153. package/dist/v3/ICreateSpaceShim.js +8 -0
  154. package/dist/v3/ICreateSpaceShim.js.map +1 -0
  155. package/dist/v3/IDropFacetShim.d.ts +7 -0
  156. package/dist/v3/IDropFacetShim.d.ts.map +1 -0
  157. package/dist/v3/IDropFacetShim.js +8 -0
  158. package/dist/v3/IDropFacetShim.js.map +1 -0
  159. package/dist/v3/IERC721AQueryableShim.d.ts +7 -0
  160. package/dist/v3/IERC721AQueryableShim.d.ts.map +1 -0
  161. package/dist/v3/IERC721AQueryableShim.js +8 -0
  162. package/dist/v3/IERC721AQueryableShim.js.map +1 -0
  163. package/dist/v3/IERC721AShim.d.ts +7 -0
  164. package/dist/v3/IERC721AShim.d.ts.map +1 -0
  165. package/dist/v3/IERC721AShim.js +8 -0
  166. package/dist/v3/IERC721AShim.js.map +1 -0
  167. package/dist/v3/IEntitlementCheckerShim.d.ts +7 -0
  168. package/dist/v3/IEntitlementCheckerShim.d.ts.map +1 -0
  169. package/dist/v3/IEntitlementCheckerShim.js +8 -0
  170. package/dist/v3/IEntitlementCheckerShim.js.map +1 -0
  171. package/dist/v3/IEntitlementDataQueryableShim.d.ts +8 -0
  172. package/dist/v3/IEntitlementDataQueryableShim.d.ts.map +1 -0
  173. package/dist/v3/IEntitlementDataQueryableShim.js +8 -0
  174. package/dist/v3/IEntitlementDataQueryableShim.js.map +1 -0
  175. package/dist/v3/IEntitlementsShim.d.ts +8 -0
  176. package/dist/v3/IEntitlementsShim.d.ts.map +1 -0
  177. package/dist/v3/IEntitlementsShim.js +8 -0
  178. package/dist/v3/IEntitlementsShim.js.map +1 -0
  179. package/dist/v3/ILegacySpaceArchitectShim.d.ts +8 -0
  180. package/dist/v3/ILegacySpaceArchitectShim.d.ts.map +1 -0
  181. package/dist/v3/ILegacySpaceArchitectShim.js +8 -0
  182. package/dist/v3/ILegacySpaceArchitectShim.js.map +1 -0
  183. package/dist/v3/IMembershipMetadataShim.d.ts +7 -0
  184. package/dist/v3/IMembershipMetadataShim.d.ts.map +1 -0
  185. package/dist/v3/IMembershipMetadataShim.js +8 -0
  186. package/dist/v3/IMembershipMetadataShim.js.map +1 -0
  187. package/dist/v3/IMembershipShim.d.ts +18 -0
  188. package/dist/v3/IMembershipShim.d.ts.map +1 -0
  189. package/dist/v3/IMembershipShim.js +73 -0
  190. package/dist/v3/IMembershipShim.js.map +1 -0
  191. package/dist/v3/IMulticallShim.d.ts +7 -0
  192. package/dist/v3/IMulticallShim.d.ts.map +1 -0
  193. package/dist/v3/IMulticallShim.js +8 -0
  194. package/dist/v3/IMulticallShim.js.map +1 -0
  195. package/dist/v3/INodeOperatorShim.d.ts +7 -0
  196. package/dist/v3/INodeOperatorShim.d.ts.map +1 -0
  197. package/dist/v3/INodeOperatorShim.js +8 -0
  198. package/dist/v3/INodeOperatorShim.js.map +1 -0
  199. package/dist/v3/INodeRegistryShim.d.ts +7 -0
  200. package/dist/v3/INodeRegistryShim.d.ts.map +1 -0
  201. package/dist/v3/INodeRegistryShim.js +8 -0
  202. package/dist/v3/INodeRegistryShim.js.map +1 -0
  203. package/dist/v3/IOperatorRegistryShim.d.ts +7 -0
  204. package/dist/v3/IOperatorRegistryShim.d.ts.map +1 -0
  205. package/dist/v3/IOperatorRegistryShim.js +8 -0
  206. package/dist/v3/IOperatorRegistryShim.js.map +1 -0
  207. package/dist/v3/IPrepayShim.d.ts +7 -0
  208. package/dist/v3/IPrepayShim.d.ts.map +1 -0
  209. package/dist/v3/IPrepayShim.js +8 -0
  210. package/dist/v3/IPrepayShim.js.map +1 -0
  211. package/dist/v3/IPricingShim.d.ts +8 -0
  212. package/dist/v3/IPricingShim.d.ts.map +1 -0
  213. package/dist/v3/IPricingShim.js +8 -0
  214. package/dist/v3/IPricingShim.js.map +1 -0
  215. package/dist/v3/IReviewShim.d.ts +61 -0
  216. package/dist/v3/IReviewShim.d.ts.map +1 -0
  217. package/dist/v3/IReviewShim.js +101 -0
  218. package/dist/v3/IReviewShim.js.map +1 -0
  219. package/dist/v3/IRiverPointsShim.d.ts +7 -0
  220. package/dist/v3/IRiverPointsShim.d.ts.map +1 -0
  221. package/dist/v3/IRiverPointsShim.js +8 -0
  222. package/dist/v3/IRiverPointsShim.js.map +1 -0
  223. package/dist/v3/IRolesShim.d.ts +8 -0
  224. package/dist/v3/IRolesShim.d.ts.map +1 -0
  225. package/dist/v3/IRolesShim.js +8 -0
  226. package/dist/v3/IRolesShim.js.map +1 -0
  227. package/dist/v3/IRuleEntitlementShim.d.ts +6 -0
  228. package/dist/v3/IRuleEntitlementShim.d.ts.map +1 -0
  229. package/dist/v3/IRuleEntitlementShim.js +3 -0
  230. package/dist/v3/IRuleEntitlementShim.js.map +1 -0
  231. package/dist/v3/IRuleEntitlementV2Shim.d.ts +6 -0
  232. package/dist/v3/IRuleEntitlementV2Shim.d.ts.map +1 -0
  233. package/dist/v3/IRuleEntitlementV2Shim.js +3 -0
  234. package/dist/v3/IRuleEntitlementV2Shim.js.map +1 -0
  235. package/dist/v3/ISpaceArchitectShim.d.ts +8 -0
  236. package/dist/v3/ISpaceArchitectShim.d.ts.map +1 -0
  237. package/dist/v3/ISpaceArchitectShim.js +38 -0
  238. package/dist/v3/ISpaceArchitectShim.js.map +1 -0
  239. package/dist/v3/ISpaceDelegationShim.d.ts +7 -0
  240. package/dist/v3/ISpaceDelegationShim.d.ts.map +1 -0
  241. package/dist/v3/ISpaceDelegationShim.js +8 -0
  242. package/dist/v3/ISpaceDelegationShim.js.map +1 -0
  243. package/dist/v3/ISpaceOwnerShim.d.ts +8 -0
  244. package/dist/v3/ISpaceOwnerShim.d.ts.map +1 -0
  245. package/dist/v3/ISpaceOwnerShim.js +8 -0
  246. package/dist/v3/ISpaceOwnerShim.js.map +1 -0
  247. package/dist/v3/IStreamRegistryShim.d.ts +7 -0
  248. package/dist/v3/IStreamRegistryShim.d.ts.map +1 -0
  249. package/dist/v3/IStreamRegistryShim.js +8 -0
  250. package/dist/v3/IStreamRegistryShim.js.map +1 -0
  251. package/dist/v3/ITippingShim.d.ts +20 -0
  252. package/dist/v3/ITippingShim.d.ts.map +1 -0
  253. package/dist/v3/ITippingShim.js +46 -0
  254. package/dist/v3/ITippingShim.js.map +1 -0
  255. package/dist/v3/ITreasuryShim.d.ts +7 -0
  256. package/dist/v3/ITreasuryShim.d.ts.map +1 -0
  257. package/dist/v3/ITreasuryShim.js +8 -0
  258. package/dist/v3/ITreasuryShim.js.map +1 -0
  259. package/dist/v3/MockERC721AShim.d.ts +7 -0
  260. package/dist/v3/MockERC721AShim.d.ts.map +1 -0
  261. package/dist/v3/MockERC721AShim.js +8 -0
  262. package/dist/v3/MockERC721AShim.js.map +1 -0
  263. package/dist/v3/OwnableFacetShim.d.ts +7 -0
  264. package/dist/v3/OwnableFacetShim.d.ts.map +1 -0
  265. package/dist/v3/OwnableFacetShim.js +8 -0
  266. package/dist/v3/OwnableFacetShim.js.map +1 -0
  267. package/dist/v3/PlatformRequirements.d.ts +10 -0
  268. package/dist/v3/PlatformRequirements.d.ts.map +1 -0
  269. package/dist/v3/PlatformRequirements.js +17 -0
  270. package/dist/v3/PlatformRequirements.js.map +1 -0
  271. package/dist/v3/PricingModules.d.ts +13 -0
  272. package/dist/v3/PricingModules.d.ts.map +1 -0
  273. package/dist/v3/PricingModules.js +23 -0
  274. package/dist/v3/PricingModules.js.map +1 -0
  275. package/dist/v3/RiverAirdropDapp.d.ts +16 -0
  276. package/dist/v3/RiverAirdropDapp.d.ts.map +1 -0
  277. package/dist/v3/RiverAirdropDapp.js +30 -0
  278. package/dist/v3/RiverAirdropDapp.js.map +1 -0
  279. package/dist/v3/RiverRegistry.d.ts +32 -0
  280. package/dist/v3/RiverRegistry.d.ts.map +1 -0
  281. package/dist/v3/RiverRegistry.js +96 -0
  282. package/dist/v3/RiverRegistry.js.map +1 -0
  283. package/dist/v3/RuleEntitlementShim.d.ts +11 -0
  284. package/dist/v3/RuleEntitlementShim.d.ts.map +1 -0
  285. package/dist/v3/RuleEntitlementShim.js +38 -0
  286. package/dist/v3/RuleEntitlementShim.js.map +1 -0
  287. package/dist/v3/RuleEntitlementV2Shim.d.ts +11 -0
  288. package/dist/v3/RuleEntitlementV2Shim.d.ts.map +1 -0
  289. package/dist/v3/RuleEntitlementV2Shim.js +38 -0
  290. package/dist/v3/RuleEntitlementV2Shim.js.map +1 -0
  291. package/dist/v3/Space.d.ts +97 -0
  292. package/dist/v3/Space.d.ts.map +1 -0
  293. package/dist/v3/Space.js +440 -0
  294. package/dist/v3/Space.js.map +1 -0
  295. package/dist/v3/SpaceDapp.d.ts +212 -0
  296. package/dist/v3/SpaceDapp.d.ts.map +1 -0
  297. package/dist/v3/SpaceDapp.js +1164 -0
  298. package/dist/v3/SpaceDapp.js.map +1 -0
  299. package/dist/v3/SpaceOwner.d.ts +13 -0
  300. package/dist/v3/SpaceOwner.d.ts.map +1 -0
  301. package/dist/v3/SpaceOwner.js +18 -0
  302. package/dist/v3/SpaceOwner.js.map +1 -0
  303. package/dist/v3/SpaceRegistrar.d.ts +25 -0
  304. package/dist/v3/SpaceRegistrar.d.ts.map +1 -0
  305. package/dist/v3/SpaceRegistrar.js +56 -0
  306. package/dist/v3/SpaceRegistrar.js.map +1 -0
  307. package/dist/v3/TokenPausableFacetShim.d.ts +7 -0
  308. package/dist/v3/TokenPausableFacetShim.d.ts.map +1 -0
  309. package/dist/v3/TokenPausableFacetShim.js +8 -0
  310. package/dist/v3/TokenPausableFacetShim.js.map +1 -0
  311. package/dist/v3/UserEntitlementShim.d.ts +11 -0
  312. package/dist/v3/UserEntitlementShim.d.ts.map +1 -0
  313. package/dist/v3/UserEntitlementShim.js +44 -0
  314. package/dist/v3/UserEntitlementShim.js.map +1 -0
  315. package/dist/v3/WalletLink.d.ts +50 -0
  316. package/dist/v3/WalletLink.d.ts.map +1 -0
  317. package/dist/v3/WalletLink.js +215 -0
  318. package/dist/v3/WalletLink.js.map +1 -0
  319. package/dist/v3/WalletLinkShim.d.ts +7 -0
  320. package/dist/v3/WalletLinkShim.d.ts.map +1 -0
  321. package/dist/v3/WalletLinkShim.js +8 -0
  322. package/dist/v3/WalletLinkShim.js.map +1 -0
  323. package/dist/v3/index.d.ts +24 -0
  324. package/dist/v3/index.d.ts.map +1 -0
  325. package/dist/v3/index.js +24 -0
  326. package/dist/v3/index.js.map +1 -0
  327. package/package.json +54 -0
@@ -0,0 +1,1743 @@
1
+ import { ethers } from 'ethers';
2
+ import { CheckOperationType, LogicalOperationType, encodeRuleData, decodeRuleData, encodeRuleDataV2, decodeRuleDataV2, NoopOperation, OperationType, evaluateTree, postOrderArrayToTree, treeToRuleData, ruleDataToOperations, encodeThresholdParams, decodeThresholdParams, encodeERC1155Params, decodeERC1155Params, createOperationsTree, EncodedNoopRuleData, DecodedCheckOperationBuilder, evaluateOperationsForEntitledWallet, findEthereumProviders, } from './entitlement';
3
+ import { MOCK_ADDRESS, MOCK_ADDRESS_2, MOCK_ADDRESS_3, MOCK_ADDRESS_4, MOCK_ADDRESS_5, } from './Utils';
4
+ import { zeroAddress } from 'viem';
5
+ import { convertRuleDataV2ToV1 } from './ConvertersEntitlements';
6
+ import debug from 'debug';
7
+ import { computeDelegatorsForProvider } from './DelegateRegistry';
8
+ const log = debug('test');
9
+ function makeRandomOperation(depth) {
10
+ const rand = Math.random();
11
+ if ((depth > 5 && depth < 10 && rand < 1 / 3) || (depth < 10 && rand < 1 / 2)) {
12
+ return {
13
+ opType: OperationType.LOGICAL,
14
+ logicalType: LogicalOperationType.AND,
15
+ leftOperation: makeRandomOperation(depth + 1),
16
+ rightOperation: makeRandomOperation(depth + 1),
17
+ };
18
+ }
19
+ else if ((depth > 5 && depth < 10 && rand < 2 / 3) || (depth < 10 && rand > 1 / 2)) {
20
+ return {
21
+ opType: OperationType.LOGICAL,
22
+ logicalType: LogicalOperationType.OR,
23
+ leftOperation: makeRandomOperation(depth + 1),
24
+ rightOperation: makeRandomOperation(depth + 1),
25
+ };
26
+ }
27
+ else {
28
+ return {
29
+ opType: OperationType.CHECK,
30
+ checkType: CheckOperationType.MOCK,
31
+ chainId: rand > 0.5 ? 1n : 0n,
32
+ contractAddress: generateRandomEthAddress(),
33
+ params: encodeThresholdParams({ threshold: rand > 0.5 ? 500n : 10n }),
34
+ };
35
+ }
36
+ }
37
+ it('random', async () => {
38
+ const operation = makeRandomOperation(0);
39
+ // it takes a Uint8Array and returns a Uint8Array
40
+ const controller = new AbortController();
41
+ const result = await evaluateTree(controller, [], xchainConfig, operation);
42
+ expect(result).toBeDefined();
43
+ });
44
+ function generateRandomEthAddress() {
45
+ let address = '0x';
46
+ const characters = '0123456789abcdef';
47
+ for (let i = 0; i < 40; i++) {
48
+ address += characters.charAt(Math.floor(Math.random() * characters.length));
49
+ }
50
+ return address;
51
+ }
52
+ /**
53
+ * An operation that always returns true
54
+ */
55
+ const falseCheck = {
56
+ opType: OperationType.CHECK,
57
+ checkType: CheckOperationType.MOCK,
58
+ chainId: 0n,
59
+ contractAddress: `0x0`,
60
+ params: encodeThresholdParams({ threshold: 10n }),
61
+ };
62
+ const slowFalseCheck = {
63
+ opType: OperationType.CHECK,
64
+ checkType: CheckOperationType.MOCK,
65
+ chainId: 0n,
66
+ contractAddress: '0x1',
67
+ params: encodeThresholdParams({ threshold: 500n }),
68
+ };
69
+ const trueCheck = {
70
+ opType: OperationType.CHECK,
71
+ checkType: CheckOperationType.MOCK,
72
+ chainId: 1n,
73
+ contractAddress: '0x0',
74
+ params: encodeThresholdParams({ threshold: 10n }),
75
+ };
76
+ const slowTrueCheck = {
77
+ opType: OperationType.CHECK,
78
+ checkType: CheckOperationType.MOCK,
79
+ chainId: 1n,
80
+ contractAddress: '0x1',
81
+ params: encodeThresholdParams({ threshold: 500n }),
82
+ };
83
+ // We have a custom NFT contract deployed to both ethereum sepolia and base sepolia where we
84
+ // can mint NFTs for testing. These are included in our unit tests because the local chain
85
+ // stack does not always behave the same as remote chains, so our xchain tests use them. We
86
+ // reproduce the same unit tests here to ensure parity between evaluation in xchain and the
87
+ // client.
88
+ // Contract addresses for the test NFT contracts.
89
+ const SepoliaTestNftContract = '0xb088b3f2b35511A611bF2aaC13fE605d491D6C19';
90
+ const SepoliaTestNftWallet_1Token = '0x1FDBA84c2153568bc22686B88B617CF64cdb0637';
91
+ const SepoliaTestNftWallet_3Tokens = '0xB79Af997239A334355F60DBeD75bEDf30AcD37bD';
92
+ const SepoliaTestNftWallet_2Tokens = '0x8cECcB1e5537040Fc63A06C88b4c1dE61880dA4d';
93
+ const ethereumSepoliaChainId = 11155111n;
94
+ const baseSepoliaChainId = 84532n;
95
+ const nftCheckEthereumSepolia = {
96
+ opType: OperationType.CHECK,
97
+ checkType: CheckOperationType.ERC721,
98
+ chainId: ethereumSepoliaChainId,
99
+ contractAddress: SepoliaTestNftContract,
100
+ params: encodeThresholdParams({ threshold: 1n }),
101
+ };
102
+ const nftMultiCheckEthereumSepolia = {
103
+ opType: OperationType.CHECK,
104
+ checkType: CheckOperationType.ERC721,
105
+ chainId: ethereumSepoliaChainId,
106
+ contractAddress: SepoliaTestNftContract,
107
+ params: encodeThresholdParams({ threshold: 6n }),
108
+ };
109
+ const nftMultiCheckHighThresholdEthereumSepolia = {
110
+ opType: OperationType.CHECK,
111
+ checkType: CheckOperationType.ERC721,
112
+ chainId: ethereumSepoliaChainId,
113
+ contractAddress: SepoliaTestNftContract,
114
+ params: encodeThresholdParams({ threshold: 100n }),
115
+ };
116
+ const nftCheckBaseSepolia = {
117
+ opType: OperationType.CHECK,
118
+ checkType: CheckOperationType.ERC721,
119
+ chainId: 84532n,
120
+ contractAddress: SepoliaTestNftContract,
121
+ params: encodeThresholdParams({ threshold: 1n }),
122
+ };
123
+ const nftMultiCheckBaseSepolia = {
124
+ opType: OperationType.CHECK,
125
+ checkType: CheckOperationType.ERC721,
126
+ chainId: 84532n,
127
+ contractAddress: SepoliaTestNftContract,
128
+ params: encodeThresholdParams({ threshold: 6n }),
129
+ };
130
+ const nftMultiCheckHighThresholdBaseSepolia = {
131
+ opType: OperationType.CHECK,
132
+ checkType: CheckOperationType.ERC721,
133
+ chainId: 84532n,
134
+ contractAddress: SepoliaTestNftContract,
135
+ params: encodeThresholdParams({ threshold: 100n }),
136
+ };
137
+ const xchainConfig = {
138
+ supportedRpcUrls: {
139
+ [Number(ethereumSepoliaChainId)]: process.env.ETH_SEPOLIA_RPC_URL ?? 'https://ethereum-sepolia-rpc.publicnode.com',
140
+ [Number(baseSepoliaChainId)]: process.env.BASE_SEPOLIA_RPC_URL ?? 'https://sepolia.base.org',
141
+ },
142
+ etherNativeNetworkIds: [Number(ethereumSepoliaChainId), Number(baseSepoliaChainId)],
143
+ ethereumNetworkIds: [Number(ethereumSepoliaChainId)],
144
+ };
145
+ const minimalEtherChainsConfig = {
146
+ supportedRpcUrls: {
147
+ [Number(ethereumSepoliaChainId)]: process.env.ETH_SEPOLIA_RPC_URL ?? 'https://ethereum-sepolia-rpc.publicnode.com',
148
+ [Number(baseSepoliaChainId)]: process.env.BASE_SEPOLIA_RPC_URL ?? 'https://sepolia.base.org',
149
+ },
150
+ etherNativeNetworkIds: [Number(ethereumSepoliaChainId)],
151
+ ethereumNetworkIds: [Number(ethereumSepoliaChainId)],
152
+ };
153
+ const nftCases = [
154
+ {
155
+ desc: 'base sepolia',
156
+ check: nftCheckBaseSepolia,
157
+ wallets: [SepoliaTestNftWallet_1Token],
158
+ expectedResult: true,
159
+ },
160
+ {
161
+ desc: 'base sepolia (no tokens)',
162
+ check: nftCheckBaseSepolia,
163
+ wallets: [ethers.constants.AddressZero],
164
+ expectedResult: false,
165
+ },
166
+ {
167
+ desc: 'base sepolia (insufficient balance)',
168
+ check: nftMultiCheckBaseSepolia,
169
+ wallets: [SepoliaTestNftWallet_1Token],
170
+ expectedResult: false,
171
+ },
172
+ {
173
+ desc: 'base sepolia multi-wallet',
174
+ check: nftMultiCheckBaseSepolia,
175
+ wallets: [
176
+ SepoliaTestNftWallet_1Token,
177
+ SepoliaTestNftWallet_2Tokens,
178
+ SepoliaTestNftWallet_3Tokens,
179
+ ],
180
+ expectedResult: true,
181
+ },
182
+ {
183
+ desc: 'base sepolia multi-wallet (insufficient balance)',
184
+ check: nftMultiCheckHighThresholdBaseSepolia,
185
+ wallets: [
186
+ SepoliaTestNftWallet_1Token,
187
+ SepoliaTestNftWallet_2Tokens,
188
+ SepoliaTestNftWallet_3Tokens,
189
+ ],
190
+ expectedResult: false,
191
+ },
192
+ {
193
+ desc: 'eth sepolia',
194
+ check: nftCheckEthereumSepolia,
195
+ wallets: [SepoliaTestNftWallet_1Token],
196
+ expectedResult: true,
197
+ },
198
+ {
199
+ desc: 'eth sepolia (no tokens)',
200
+ check: nftCheckEthereumSepolia,
201
+ wallets: [ethers.constants.AddressZero],
202
+ expectedResult: false,
203
+ },
204
+ {
205
+ desc: 'eth sepolia (insufficient balance)',
206
+ check: nftMultiCheckEthereumSepolia,
207
+ wallets: [SepoliaTestNftWallet_1Token],
208
+ expectedResult: false,
209
+ },
210
+ {
211
+ desc: 'eth sepolia multi-wallet',
212
+ check: nftMultiCheckEthereumSepolia,
213
+ wallets: [
214
+ SepoliaTestNftWallet_1Token,
215
+ SepoliaTestNftWallet_2Tokens,
216
+ SepoliaTestNftWallet_3Tokens,
217
+ ],
218
+ expectedResult: true,
219
+ },
220
+ {
221
+ desc: 'eth sepolia multi-wallet (insufficient balance)',
222
+ check: nftMultiCheckHighThresholdEthereumSepolia,
223
+ wallets: [
224
+ SepoliaTestNftWallet_1Token,
225
+ SepoliaTestNftWallet_2Tokens,
226
+ SepoliaTestNftWallet_3Tokens,
227
+ ],
228
+ expectedResult: false,
229
+ },
230
+ ];
231
+ it.concurrent.each(nftCases)('erc721Check - $desc', async (props) => {
232
+ const { check, wallets, expectedResult } = props;
233
+ const controller = new AbortController();
234
+ const result = await evaluateTree(controller, wallets, xchainConfig, check);
235
+ if (expectedResult) {
236
+ expect(result).toBeTruthy();
237
+ expect(result).not.toEqual(zeroAddress);
238
+ }
239
+ else {
240
+ expect(result).toEqual(zeroAddress);
241
+ }
242
+ });
243
+ // These are the addresses of the chain link test contract on base sepolia and ethereum sepolia.
244
+ const baseSepoliaChainLinkContract = '0xE4aB69C077896252FAFBD49EFD26B5D171A32410';
245
+ const ethSepoliaChainLinkContract = '0x779877A7B0D9E8603169DdbD7836e478b4624789';
246
+ // The following are the addresses of the wallets that hold the chain link tokens for testing.
247
+ // Some wallet addresses are duplicated for the sake of self-documenting variable names.
248
+ const sepoliaChainLinkWallet_50Link = '0x4BCfC6962Ab0297aF801da21216014F53B46E991';
249
+ const sepoliaChainLinkWallet_25Link = '0xa4D440AeA5F555feEB5AEa0ddcED6e1B9FaD6A9C';
250
+ const baseSepoliaChainLinkWallet_25Link2 = '0x4BCfC6962Ab0297aF801da21216014F53B46E991';
251
+ const baseSepoliaChainLinkWallet_25Link = '0xa4D440AeA5F555feEB5AEa0ddcED6e1B9FaD6A9C';
252
+ const testEmptyAccount = '0xb227905F186095083869928BAb49cA9CE9546817';
253
+ // This wallet has .4ETH on Sepolia, and .1ETH on Base Sepolia
254
+ const ethWallet_0_5Eth = '0x3ef41b0469c1B808Caad9d643F596023e2aa8f11';
255
+ // This wallet has .1ETH on Sepolia, and .1ETH on Base Sepolia
256
+ const ethWallet_0_2Eth = '0x4BD04Bf2AAC02238bCcFA75D7bc4Cfd2c019c331';
257
+ const chainlinkExp = BigInt(10) ** BigInt(18);
258
+ // ERC1155 test contracts and wallets
259
+ const baseSepoliaErc1155Contract = '0x60327B4F2936E02B910e8A236d46D0B7C1986DCB';
260
+ const baseSepoliaErc1155Wallet_TokenId0_700Tokens = '0x1FDBA84c2153568bc22686B88B617CF64cdb0637';
261
+ const baseSepoliaErc1155Wallet_TokenId0_300Tokens = '0xB79Af997239A334355F60DBeD75bEDf30AcD37bD';
262
+ const baseSepoliaErc1155Wallet_TokenId1_100Tokens = '0x1FDBA84c2153568bc22686B88B617CF64cdb0637';
263
+ const baseSepoliaErc1155Wallet_TokenId1_50Tokens = '0xB79Af997239A334355F60DBeD75bEDf30AcD37bD';
264
+ const ethBalance_gt_0_7 = {
265
+ opType: OperationType.CHECK,
266
+ checkType: CheckOperationType.ETH_BALANCE,
267
+ chainId: ethereumSepoliaChainId,
268
+ contractAddress: ethers.constants.AddressZero,
269
+ params: encodeThresholdParams({ threshold: 700000000000000001n }),
270
+ };
271
+ const ethBalance_0_7 = {
272
+ ...ethBalance_gt_0_7,
273
+ params: encodeThresholdParams({ threshold: 700000000000000000n }),
274
+ };
275
+ const ethBalance_0_5 = {
276
+ ...ethBalance_gt_0_7,
277
+ params: encodeThresholdParams({ threshold: 500000000000000000n }),
278
+ };
279
+ const ethBalance_0_4 = {
280
+ ...ethBalance_gt_0_7,
281
+ params: encodeThresholdParams({ threshold: 400000000000000000n }),
282
+ };
283
+ const erc20ChainLinkCheckBaseSepolia_20Tokens = {
284
+ opType: OperationType.CHECK,
285
+ checkType: CheckOperationType.ERC20,
286
+ chainId: 84532n,
287
+ contractAddress: baseSepoliaChainLinkContract,
288
+ params: encodeThresholdParams({ threshold: 20n * chainlinkExp }),
289
+ };
290
+ const erc20ChainLinkCheckBaseSepolia_30Tokens = {
291
+ ...erc20ChainLinkCheckBaseSepolia_20Tokens,
292
+ params: encodeThresholdParams({ threshold: 30n * chainlinkExp }),
293
+ };
294
+ const erc20ChainLinkCheckBaseSepolia_50Tokens = {
295
+ ...erc20ChainLinkCheckBaseSepolia_20Tokens,
296
+ params: encodeThresholdParams({ threshold: 50n * chainlinkExp }),
297
+ };
298
+ const erc20ChainLinkCheckBaseSepolia_90Tokens = {
299
+ ...erc20ChainLinkCheckBaseSepolia_20Tokens,
300
+ params: encodeThresholdParams({ threshold: 90n * chainlinkExp }),
301
+ };
302
+ const erc20ChainLinkEthereumSepolia_20Tokens = {
303
+ opType: OperationType.CHECK,
304
+ checkType: CheckOperationType.ERC20,
305
+ chainId: ethereumSepoliaChainId,
306
+ contractAddress: ethSepoliaChainLinkContract,
307
+ params: encodeThresholdParams({ threshold: 20n * chainlinkExp }),
308
+ };
309
+ const erc20ChainLinkCheckEthereumSepolia_30Tokens = {
310
+ ...erc20ChainLinkEthereumSepolia_20Tokens,
311
+ params: encodeThresholdParams({ threshold: 30n * chainlinkExp }),
312
+ };
313
+ const erc20ChainLinkCheckEthereumSepolia_75Tokens = {
314
+ ...erc20ChainLinkEthereumSepolia_20Tokens,
315
+ params: encodeThresholdParams({ threshold: 75n * chainlinkExp }),
316
+ };
317
+ const erc20ChainLinkCheckEthereumSepolia_90Tokens = {
318
+ ...erc20ChainLinkEthereumSepolia_20Tokens,
319
+ params: encodeThresholdParams({ threshold: 90n * chainlinkExp }),
320
+ };
321
+ const erc1155CheckBaseSepolia_TokenId0_700Tokens = {
322
+ opType: OperationType.CHECK,
323
+ checkType: CheckOperationType.ERC1155,
324
+ chainId: baseSepoliaChainId,
325
+ contractAddress: baseSepoliaErc1155Contract,
326
+ params: encodeERC1155Params({ threshold: 700n, tokenId: 0n }),
327
+ };
328
+ const erc1155CheckBaseSepolia_TokenId0_1000Tokens = {
329
+ ...erc1155CheckBaseSepolia_TokenId0_700Tokens,
330
+ params: encodeERC1155Params({ threshold: 1000n, tokenId: 0n }),
331
+ };
332
+ const erc1155CheckBaseSepolia_TokenId0_1001Tokens = {
333
+ ...erc1155CheckBaseSepolia_TokenId0_700Tokens,
334
+ params: encodeERC1155Params({ threshold: 1001n, tokenId: 0n }),
335
+ };
336
+ const erc1155CheckBaseSepolia_TokenId1_100Tokens = {
337
+ opType: OperationType.CHECK,
338
+ checkType: CheckOperationType.ERC1155,
339
+ chainId: baseSepoliaChainId,
340
+ contractAddress: baseSepoliaErc1155Contract,
341
+ params: encodeERC1155Params({ threshold: 100n, tokenId: 1n }),
342
+ };
343
+ const erc1155CheckBaseSepolia_TokenId1_150Tokens = {
344
+ ...erc1155CheckBaseSepolia_TokenId1_100Tokens,
345
+ params: encodeERC1155Params({ threshold: 150n, tokenId: 1n }),
346
+ };
347
+ const erc1155CheckBaseSepolia_TokenId1_151Tokens = {
348
+ ...erc1155CheckBaseSepolia_TokenId1_100Tokens,
349
+ params: encodeERC1155Params({ threshold: 151n, tokenId: 1n }),
350
+ };
351
+ const erc1155Cases = [
352
+ {
353
+ desc: 'base sepolia token id 0 (no wallets)',
354
+ check: erc1155CheckBaseSepolia_TokenId0_700Tokens,
355
+ wallets: [],
356
+ expectedResult: false,
357
+ },
358
+ {
359
+ desc: 'base sepolia token id 0 (single wallet, insufficient balance)',
360
+ check: erc1155CheckBaseSepolia_TokenId0_700Tokens,
361
+ wallets: [baseSepoliaErc1155Wallet_TokenId0_300Tokens],
362
+ expectedResult: false,
363
+ },
364
+ {
365
+ desc: 'base sepolia token id 0 (single wallet)',
366
+ check: erc1155CheckBaseSepolia_TokenId0_700Tokens,
367
+ wallets: [baseSepoliaErc1155Wallet_TokenId0_700Tokens],
368
+ expectedResult: true,
369
+ },
370
+ {
371
+ desc: 'base sepolia token id 0 (multiwallet, insufficient balance)',
372
+ check: erc1155CheckBaseSepolia_TokenId0_1001Tokens,
373
+ wallets: [
374
+ baseSepoliaErc1155Wallet_TokenId0_700Tokens,
375
+ baseSepoliaErc1155Wallet_TokenId0_300Tokens,
376
+ ],
377
+ expectedResult: false,
378
+ },
379
+ {
380
+ desc: 'base sepolia token id 0 (multiwallet)',
381
+ check: erc1155CheckBaseSepolia_TokenId0_1000Tokens,
382
+ wallets: [
383
+ baseSepoliaErc1155Wallet_TokenId0_700Tokens,
384
+ baseSepoliaErc1155Wallet_TokenId0_300Tokens,
385
+ ],
386
+ expectedResult: true,
387
+ },
388
+ {
389
+ desc: 'base sepolia token id 1 (no wallets)',
390
+ check: erc1155CheckBaseSepolia_TokenId1_100Tokens,
391
+ wallets: [],
392
+ expectedResult: false,
393
+ },
394
+ {
395
+ desc: 'base sepolia token id 1 (single wallet, insufficient balance)',
396
+ check: erc1155CheckBaseSepolia_TokenId1_100Tokens,
397
+ wallets: [baseSepoliaErc1155Wallet_TokenId1_50Tokens],
398
+ expectedResult: false,
399
+ },
400
+ {
401
+ desc: 'base sepolia token id 1 (single wallet)',
402
+ check: erc1155CheckBaseSepolia_TokenId1_100Tokens,
403
+ wallets: [baseSepoliaErc1155Wallet_TokenId1_100Tokens],
404
+ expectedResult: true,
405
+ },
406
+ {
407
+ desc: 'base sepolia token id 1 (multiwallet, insufficient balance)',
408
+ check: erc1155CheckBaseSepolia_TokenId1_151Tokens,
409
+ wallets: [
410
+ baseSepoliaErc1155Wallet_TokenId1_100Tokens,
411
+ baseSepoliaErc1155Wallet_TokenId1_50Tokens,
412
+ ],
413
+ expectedResult: false,
414
+ },
415
+ {
416
+ desc: 'base sepolia token id 1 (multiwallet)',
417
+ check: erc1155CheckBaseSepolia_TokenId1_150Tokens,
418
+ wallets: [
419
+ baseSepoliaErc1155Wallet_TokenId1_100Tokens,
420
+ baseSepoliaErc1155Wallet_TokenId1_50Tokens,
421
+ ],
422
+ expectedResult: true,
423
+ },
424
+ ];
425
+ it.concurrent.each(erc1155Cases)('ERC1155 Check - $desc', async (props) => {
426
+ const { check, wallets, expectedResult } = props;
427
+ const controller = new AbortController();
428
+ const result = await evaluateTree(controller, wallets, xchainConfig, check);
429
+ if (expectedResult) {
430
+ expect(result).not.toEqual(zeroAddress);
431
+ }
432
+ else {
433
+ expect(result).toEqual(zeroAddress);
434
+ }
435
+ });
436
+ const ethBalanceCases = [
437
+ {
438
+ desc: 'eth balance with no wallet',
439
+ check: ethBalance_0_5,
440
+ wallets: [],
441
+ expectedResult: false,
442
+ },
443
+ {
444
+ desc: 'Eth balance across chains',
445
+ check: ethBalance_0_5,
446
+ wallets: [ethWallet_0_5Eth],
447
+ expectedResult: true,
448
+ },
449
+ {
450
+ desc: 'Eth balance across chains (insufficient balance)',
451
+ check: ethBalance_0_5,
452
+ wallets: [ethWallet_0_2Eth],
453
+ expectedResult: false,
454
+ },
455
+ {
456
+ desc: 'Eth balance across chains (multiwallet)',
457
+ check: ethBalance_0_7,
458
+ wallets: [ethWallet_0_5Eth, ethWallet_0_2Eth],
459
+ expectedResult: true,
460
+ },
461
+ {
462
+ desc: 'Eth balance across chains (multiwallet, insufficient balance)',
463
+ check: ethBalance_gt_0_7,
464
+ wallets: [ethWallet_0_5Eth, ethWallet_0_2Eth],
465
+ expectedResult: false,
466
+ },
467
+ ];
468
+ it.concurrent.each(ethBalanceCases)('Eth Balance Check - $desc', async (props) => {
469
+ const { check, wallets, expectedResult } = props;
470
+ const controller = new AbortController();
471
+ const result = await evaluateTree(controller, wallets, xchainConfig, check);
472
+ if (expectedResult) {
473
+ expect(result).toBeTruthy();
474
+ expect(result).not.toEqual(zeroAddress);
475
+ }
476
+ else {
477
+ expect(result).toEqual(zeroAddress);
478
+ }
479
+ });
480
+ const ethBalanceCasesMinimalEtherChains = [
481
+ {
482
+ desc: 'positive result',
483
+ check: ethBalance_0_4,
484
+ wallets: [ethWallet_0_5Eth],
485
+ expectedResult: true,
486
+ },
487
+ {
488
+ desc: 'negative result',
489
+ check: ethBalance_0_5,
490
+ wallets: [ethWallet_0_5Eth],
491
+ expectedResult: false,
492
+ },
493
+ ];
494
+ it.concurrent.each(ethBalanceCasesMinimalEtherChains)('Eth Balance Check - Ether chains < xChain supported chains - $desc', async (props) => {
495
+ const { check, wallets, expectedResult } = props;
496
+ const controller = new AbortController();
497
+ const result = await evaluateTree(controller, wallets, minimalEtherChainsConfig, check);
498
+ if (expectedResult) {
499
+ expect(result).toBeTruthy();
500
+ expect(result).not.toEqual(zeroAddress);
501
+ }
502
+ else {
503
+ expect(result).toEqual(zeroAddress);
504
+ }
505
+ });
506
+ const erc20Cases = [
507
+ {
508
+ desc: 'base sepolia (empty wallet, false)',
509
+ check: erc20ChainLinkCheckBaseSepolia_20Tokens,
510
+ wallets: [testEmptyAccount],
511
+ expectedResult: false,
512
+ },
513
+ {
514
+ desc: 'base sepolia (single wallet)',
515
+ check: erc20ChainLinkCheckBaseSepolia_20Tokens,
516
+ wallets: [baseSepoliaChainLinkWallet_25Link],
517
+ expectedResult: true,
518
+ },
519
+ {
520
+ desc: 'base sepolia (two wallets)',
521
+ check: erc20ChainLinkCheckBaseSepolia_20Tokens,
522
+ wallets: [baseSepoliaChainLinkWallet_25Link, testEmptyAccount],
523
+ expectedResult: true,
524
+ },
525
+ {
526
+ desc: 'base sepolia (false)',
527
+ check: erc20ChainLinkCheckBaseSepolia_30Tokens,
528
+ wallets: [baseSepoliaChainLinkWallet_25Link],
529
+ expectedResult: false,
530
+ },
531
+ {
532
+ desc: 'base sepolia (two wallets, false)',
533
+ check: erc20ChainLinkCheckBaseSepolia_30Tokens,
534
+ wallets: [baseSepoliaChainLinkWallet_25Link, testEmptyAccount],
535
+ expectedResult: false,
536
+ },
537
+ {
538
+ desc: 'base sepolia (two nonempty wallets, true)',
539
+ check: erc20ChainLinkCheckBaseSepolia_30Tokens,
540
+ wallets: [baseSepoliaChainLinkWallet_25Link, baseSepoliaChainLinkWallet_25Link2],
541
+ expectedResult: true,
542
+ },
543
+ {
544
+ desc: 'base sepolia (two nonempty wallets, exact balance - true)',
545
+ check: erc20ChainLinkCheckBaseSepolia_50Tokens,
546
+ wallets: [baseSepoliaChainLinkWallet_25Link, baseSepoliaChainLinkWallet_25Link2],
547
+ expectedResult: true,
548
+ },
549
+ {
550
+ desc: 'base sepolia (two nonempty wallets, false)',
551
+ check: erc20ChainLinkCheckBaseSepolia_90Tokens,
552
+ wallets: [baseSepoliaChainLinkWallet_25Link, baseSepoliaChainLinkWallet_25Link2],
553
+ expectedResult: false,
554
+ },
555
+ {
556
+ desc: 'eth sepolia (empty wallet, false)',
557
+ check: erc20ChainLinkCheckEthereumSepolia_30Tokens,
558
+ wallets: [testEmptyAccount],
559
+ expectedResult: false,
560
+ },
561
+ {
562
+ desc: 'eth sepolia (single wallet)',
563
+ check: erc20ChainLinkEthereumSepolia_20Tokens,
564
+ wallets: [sepoliaChainLinkWallet_25Link],
565
+ expectedResult: true,
566
+ },
567
+ {
568
+ desc: 'eth sepolia (two wallets)',
569
+ check: erc20ChainLinkEthereumSepolia_20Tokens,
570
+ wallets: [sepoliaChainLinkWallet_25Link, testEmptyAccount],
571
+ expectedResult: true,
572
+ },
573
+ {
574
+ desc: 'eth sepolia (false)',
575
+ check: erc20ChainLinkCheckBaseSepolia_30Tokens,
576
+ wallets: [sepoliaChainLinkWallet_25Link],
577
+ expectedResult: false,
578
+ },
579
+ {
580
+ desc: 'eth sepolia (two wallets, false)',
581
+ check: erc20ChainLinkCheckBaseSepolia_30Tokens,
582
+ wallets: [sepoliaChainLinkWallet_25Link, testEmptyAccount],
583
+ expectedResult: false,
584
+ },
585
+ {
586
+ desc: 'eth sepolia (two nonempty wallets, exact balance - true)',
587
+ check: erc20ChainLinkCheckEthereumSepolia_75Tokens,
588
+ wallets: [sepoliaChainLinkWallet_25Link, sepoliaChainLinkWallet_50Link],
589
+ expectedResult: true,
590
+ },
591
+ {
592
+ desc: 'eth sepolia (two nonempty wallets, false)',
593
+ check: erc20ChainLinkCheckEthereumSepolia_90Tokens,
594
+ wallets: [sepoliaChainLinkWallet_25Link, sepoliaChainLinkWallet_50Link],
595
+ expectedResult: false,
596
+ },
597
+ ];
598
+ it.concurrent.each(erc20Cases)('erc20Check - $desc', async (props) => {
599
+ const { check, wallets, expectedResult } = props;
600
+ const controller = new AbortController();
601
+ const result = await evaluateTree(controller, wallets, xchainConfig, check);
602
+ if (expectedResult) {
603
+ expect(result).toBeTruthy();
604
+ expect(result).not.toEqual(zeroAddress);
605
+ }
606
+ else {
607
+ expect(result).toEqual(zeroAddress);
608
+ }
609
+ });
610
+ const errorTests = [
611
+ {
612
+ desc: 'unknown check type',
613
+ check: {
614
+ ...erc20ChainLinkCheckBaseSepolia_20Tokens,
615
+ checkType: CheckOperationType.NONE,
616
+ },
617
+ error: 'Unknown check operation type',
618
+ },
619
+ {
620
+ desc: 'erc20 invalid check (chainId)',
621
+ check: {
622
+ ...erc20ChainLinkCheckBaseSepolia_20Tokens,
623
+ chainId: -1n,
624
+ },
625
+ error: 'Invalid chain id for check operation ERC20',
626
+ },
627
+ {
628
+ desc: 'erc20 invalid check (contractAddress)',
629
+ check: {
630
+ ...erc20ChainLinkCheckBaseSepolia_20Tokens,
631
+ contractAddress: ethers.constants.AddressZero,
632
+ },
633
+ error: 'Invalid contract address for check operation ERC20',
634
+ },
635
+ {
636
+ desc: 'erc20 invalid check (threshold)',
637
+ check: {
638
+ ...erc20ChainLinkCheckBaseSepolia_20Tokens,
639
+ params: encodeThresholdParams({ threshold: 0n }),
640
+ },
641
+ error: 'Invalid threshold for check operation ERC20',
642
+ },
643
+ {
644
+ desc: 'erc721 invalid check (chainId)',
645
+ check: {
646
+ ...nftCheckBaseSepolia,
647
+ opType: OperationType.CHECK,
648
+ chainId: -1n,
649
+ },
650
+ error: 'Invalid chain id for check operation ERC721',
651
+ },
652
+ {
653
+ desc: 'erc721 invalid check (contractAddress)',
654
+ check: {
655
+ ...nftCheckBaseSepolia,
656
+ opType: OperationType.CHECK,
657
+ contractAddress: ethers.constants.AddressZero,
658
+ },
659
+ error: 'Invalid contract address for check operation ERC721',
660
+ },
661
+ {
662
+ desc: 'erc721 invalid check (threshold)',
663
+ check: {
664
+ ...nftCheckBaseSepolia,
665
+ opType: OperationType.CHECK,
666
+ params: encodeThresholdParams({ threshold: 0n }),
667
+ },
668
+ error: 'Invalid threshold for check operation ERC721',
669
+ },
670
+ {
671
+ desc: 'cross chain entitlement invalid check (chainId)',
672
+ check: {
673
+ opType: OperationType.CHECK,
674
+ checkType: CheckOperationType.ISENTITLED,
675
+ chainId: -1n,
676
+ contractAddress: nftCheckBaseSepolia.contractAddress,
677
+ },
678
+ error: 'Invalid chain id for check operation ISENTITLED',
679
+ },
680
+ {
681
+ desc: 'cross chain entitlement invalid check (contractAddress)',
682
+ check: {
683
+ opType: OperationType.CHECK,
684
+ checkType: CheckOperationType.ISENTITLED,
685
+ chainId: 1n,
686
+ contractAddress: ethers.constants.AddressZero,
687
+ },
688
+ error: 'Invalid contract address for check operation ISENTITLED',
689
+ },
690
+ {
691
+ desc: 'erc1155 invalid check (chainId)',
692
+ check: {
693
+ opType: OperationType.CHECK,
694
+ checkType: CheckOperationType.ERC1155,
695
+ chainId: -1n,
696
+ contractAddress: MOCK_ADDRESS,
697
+ params: encodeERC1155Params({ tokenId: 1n, threshold: 1n }),
698
+ },
699
+ error: 'Invalid chain id for check operation ERC1155',
700
+ },
701
+ {
702
+ desc: 'erc 1155 invalid check (contractAddress)',
703
+ check: {
704
+ opType: OperationType.CHECK,
705
+ checkType: CheckOperationType.ERC1155,
706
+ chainId: 1n,
707
+ contractAddress: ethers.constants.AddressZero,
708
+ },
709
+ error: 'Invalid contract address for check operation ERC1155',
710
+ },
711
+ {
712
+ desc: 'erc1155 invalid check (threshold)',
713
+ check: {
714
+ opType: OperationType.CHECK,
715
+ checkType: CheckOperationType.ERC1155,
716
+ chainId: 1n,
717
+ contractAddress: MOCK_ADDRESS,
718
+ params: encodeERC1155Params({ tokenId: 1n, threshold: 0n }),
719
+ },
720
+ error: 'Invalid threshold for check operation ERC1155',
721
+ },
722
+ {
723
+ desc: 'eth balance invalid check (invalid threshold: 0)',
724
+ check: {
725
+ opType: OperationType.CHECK,
726
+ checkType: CheckOperationType.ETH_BALANCE,
727
+ chainId: 0n,
728
+ contractAddress: zeroAddress,
729
+ params: encodeThresholdParams({ threshold: 0n }),
730
+ },
731
+ error: 'Invalid threshold for check operation ETH_BALANCE',
732
+ },
733
+ ];
734
+ it.concurrent.each(errorTests)('error - $desc', async (props) => {
735
+ const { check, error } = props;
736
+ const controller = new AbortController();
737
+ await expect(evaluateTree(controller, [SepoliaTestNftWallet_1Token], xchainConfig, check)).rejects.toThrow(error);
738
+ });
739
+ const orCases = [
740
+ { leftCheck: trueCheck, rightCheck: trueCheck, expectedResult: MOCK_ADDRESS },
741
+ { leftCheck: trueCheck, rightCheck: falseCheck, expectedResult: MOCK_ADDRESS },
742
+ { leftCheck: falseCheck, rightCheck: trueCheck, expectedResult: MOCK_ADDRESS },
743
+ { leftCheck: falseCheck, rightCheck: falseCheck, expectedResult: ethers.constants.AddressZero },
744
+ ];
745
+ it.concurrent.each(orCases)('orOperation', async (props) => {
746
+ const { leftCheck, rightCheck, expectedResult } = props;
747
+ const orOperation = {
748
+ opType: OperationType.LOGICAL,
749
+ logicalType: LogicalOperationType.OR,
750
+ leftOperation: leftCheck,
751
+ rightOperation: rightCheck,
752
+ };
753
+ const controller = new AbortController();
754
+ const result = await evaluateTree(controller, [], xchainConfig, orOperation);
755
+ expect(result).toBe(expectedResult);
756
+ });
757
+ const slowOrCases = [
758
+ {
759
+ leftCheck: trueCheck,
760
+ rightCheck: slowTrueCheck,
761
+ expectedResult: MOCK_ADDRESS,
762
+ expectedTime: 10,
763
+ },
764
+ {
765
+ leftCheck: trueCheck,
766
+ rightCheck: slowFalseCheck,
767
+ expectedResult: MOCK_ADDRESS,
768
+ expectedTime: 10,
769
+ },
770
+ {
771
+ leftCheck: slowFalseCheck,
772
+ rightCheck: trueCheck,
773
+ expectedResult: MOCK_ADDRESS,
774
+ expectedTime: 10,
775
+ },
776
+ {
777
+ leftCheck: falseCheck,
778
+ rightCheck: slowFalseCheck,
779
+ expectedResult: ethers.constants.AddressZero,
780
+ expectedTime: 500,
781
+ },
782
+ ];
783
+ it.concurrent.each(slowOrCases)('slowOrOperation', async (props) => {
784
+ const { leftCheck, rightCheck, expectedResult, expectedTime } = props;
785
+ const operation = {
786
+ opType: OperationType.LOGICAL,
787
+ logicalType: LogicalOperationType.OR,
788
+ leftOperation: leftCheck,
789
+ rightOperation: rightCheck,
790
+ };
791
+ const controller = new AbortController();
792
+ const start = performance.now();
793
+ const result = await evaluateTree(controller, [], xchainConfig, operation);
794
+ const timeTaken = performance.now() - start;
795
+ expect(timeTaken).toBeCloseTo(expectedTime, -2);
796
+ expect(result).toBe(expectedResult);
797
+ });
798
+ const andCases = [
799
+ { leftCheck: trueCheck, rightCheck: trueCheck, expectedResult: MOCK_ADDRESS },
800
+ { leftCheck: trueCheck, rightCheck: falseCheck, expectedResult: ethers.constants.AddressZero },
801
+ { leftCheck: falseCheck, rightCheck: trueCheck, expectedResult: ethers.constants.AddressZero },
802
+ { leftCheck: falseCheck, rightCheck: falseCheck, expectedResult: ethers.constants.AddressZero },
803
+ ];
804
+ it.concurrent.each(andCases)('andOperation', async (props) => {
805
+ const { leftCheck, rightCheck, expectedResult } = props;
806
+ const operation = {
807
+ opType: OperationType.LOGICAL,
808
+ logicalType: LogicalOperationType.AND,
809
+ leftOperation: leftCheck,
810
+ rightOperation: rightCheck,
811
+ };
812
+ const controller = new AbortController();
813
+ const result = await evaluateTree(controller, [], xchainConfig, operation);
814
+ expect(result).toBe(expectedResult);
815
+ });
816
+ const slowAndCases = [
817
+ {
818
+ leftCheck: trueCheck,
819
+ rightCheck: slowTrueCheck,
820
+ expectedResult: MOCK_ADDRESS,
821
+ expectedTime: 500,
822
+ },
823
+ {
824
+ leftCheck: slowTrueCheck,
825
+ rightCheck: falseCheck,
826
+ expectedResult: ethers.constants.AddressZero,
827
+ expectedTime: 10,
828
+ },
829
+ {
830
+ leftCheck: falseCheck,
831
+ rightCheck: slowTrueCheck,
832
+ expectedResult: ethers.constants.AddressZero,
833
+ expectedTime: 10,
834
+ },
835
+ {
836
+ leftCheck: falseCheck,
837
+ rightCheck: slowFalseCheck,
838
+ expectedResult: ethers.constants.AddressZero,
839
+ expectedTime: 10,
840
+ },
841
+ ];
842
+ it.concurrent.each(slowAndCases)('slowAndOperation', async (props) => {
843
+ const { leftCheck, rightCheck, expectedResult, expectedTime } = props;
844
+ const operation = {
845
+ opType: OperationType.LOGICAL,
846
+ logicalType: LogicalOperationType.AND,
847
+ leftOperation: leftCheck,
848
+ rightOperation: rightCheck,
849
+ };
850
+ const controller = new AbortController();
851
+ const start = performance.now();
852
+ const result = await evaluateTree(controller, [], xchainConfig, operation);
853
+ const timeTaken = performance.now() - start;
854
+ expect(result).toBe(expectedResult);
855
+ expect(timeTaken).toBeCloseTo(expectedTime, -2);
856
+ });
857
+ const hotWallet = '0x10F0ABcC19f37CE6131809b105D4d7Ac5343F77D';
858
+ const hotWallet2 = '0xca477fFcD9baa0E56B6fa5d7221D99f981A135C7';
859
+ const coldWallet = '0xF2BcBF25fA8fE28D755f1C6e1630A09a1E23457f';
860
+ const coldWallet2 = '0x32e52d188600F27d12A65120160aA28b1108C050';
861
+ const coldWallet3 = '0xBda05058243FEf202FB4925b3877373396A08768';
862
+ describe('computeDelegatorsForProvider', () => {
863
+ it.concurrent('single hot wallet maps to single cold wallet', async () => {
864
+ const providers = await findEthereumProviders(xchainConfig);
865
+ expect(providers.length).toBe(1);
866
+ const provider = providers[0];
867
+ const delegated = await computeDelegatorsForProvider(provider, [hotWallet]);
868
+ expect(delegated).toHaveLength(1);
869
+ expect(delegated).toEqual(expect.arrayContaining([coldWallet]));
870
+ });
871
+ it.concurrent('single hot wallet maps to multiple cold wallets', async () => {
872
+ const providers = await findEthereumProviders(xchainConfig);
873
+ expect(providers.length).toBe(1);
874
+ const provider = providers[0];
875
+ const delegated = await computeDelegatorsForProvider(provider, [hotWallet2]);
876
+ expect(delegated).toHaveLength(2);
877
+ expect(delegated).toEqual(expect.arrayContaining([coldWallet2, coldWallet3]));
878
+ });
879
+ it.concurrent('multiple hot wallets map to multiple cold wallets', async () => {
880
+ const providers = await findEthereumProviders(xchainConfig);
881
+ expect(providers.length).toBe(1);
882
+ const provider = providers[0];
883
+ const delegated = await computeDelegatorsForProvider(provider, [hotWallet, hotWallet2]);
884
+ expect(delegated).toHaveLength(3);
885
+ expect(delegated).toEqual(expect.arrayContaining([coldWallet, coldWallet2, coldWallet3]));
886
+ });
887
+ });
888
+ it('empty', async () => {
889
+ const controller = new AbortController();
890
+ const result = await evaluateTree(controller, [], xchainConfig, undefined);
891
+ expect(result).toBe(ethers.constants.AddressZero);
892
+ });
893
+ it('true', async () => {
894
+ const operation = trueCheck;
895
+ const controller = new AbortController();
896
+ const result = await evaluateTree(controller, [], xchainConfig, operation);
897
+ expect(result).toBe(MOCK_ADDRESS);
898
+ });
899
+ it('false', async () => {
900
+ const operation = falseCheck;
901
+ const controller = new AbortController();
902
+ const result = await evaluateTree(controller, [], xchainConfig, operation);
903
+ expect(result).toBe(ethers.constants.AddressZero);
904
+ });
905
+ it('encode/decode rule data v2', async () => {
906
+ const randomTree = makeRandomOperation(5);
907
+ const data = treeToRuleData(randomTree);
908
+ const encoded = encodeRuleDataV2(data);
909
+ const decodedDag = decodeRuleDataV2(encoded);
910
+ const operations = ruleDataToOperations(decodedDag);
911
+ const newTree = postOrderArrayToTree(operations);
912
+ expect(randomTree.opType === newTree.opType).toBeTruthy();
913
+ });
914
+ it('decode empty ruledata v2 to NoopRuleData v1', async () => {
915
+ const converted = convertRuleDataV2ToV1(decodeRuleDataV2(EncodedNoopRuleData));
916
+ expect(converted.operations).toHaveLength(0);
917
+ expect(converted.checkOperations).toHaveLength(0);
918
+ expect(converted.logicalOperations).toHaveLength(0);
919
+ });
920
+ // encode/decode should respect address equality semantics but may not maintain case
921
+ function addressesEqual(a, b) {
922
+ return a.toLowerCase() === b.toLowerCase();
923
+ }
924
+ it('encode/decode rule data', async () => {
925
+ const randomTree = makeRandomOperation(5);
926
+ const data = treeToRuleData(randomTree);
927
+ const v1 = convertRuleDataV2ToV1(data);
928
+ const encoded = encodeRuleData(v1);
929
+ const decodedDag = decodeRuleData(encoded);
930
+ for (let i = 0; i < v1.operations.length; i++) {
931
+ expect(v1.operations[i].opType).toBe(decodedDag.operations[i].opType);
932
+ expect(v1.operations[i].index).toBe(decodedDag.operations[i].index);
933
+ }
934
+ for (let i = 0; i < v1.logicalOperations.length; i++) {
935
+ expect(v1.logicalOperations[i].logOpType).toBe(decodedDag.logicalOperations[i].logOpType);
936
+ expect(v1.logicalOperations[i].leftOperationIndex).toBe(decodedDag.logicalOperations[i].leftOperationIndex);
937
+ expect(v1.logicalOperations[i].rightOperationIndex).toBe(decodedDag.logicalOperations[i].rightOperationIndex);
938
+ }
939
+ for (let i = 0; i < v1.checkOperations.length; i++) {
940
+ expect(v1.checkOperations[i].opType).toBe(decodedDag.checkOperations[i].opType);
941
+ expect(v1.checkOperations[i].chainId).toBe(decodedDag.checkOperations[i].chainId);
942
+ expect(addressesEqual(v1.checkOperations[i].contractAddress, decodedDag.checkOperations[i].contractAddress)).toBeTruthy();
943
+ expect(v1.checkOperations[i].threshold).toBe(decodedDag.checkOperations[i].threshold);
944
+ }
945
+ });
946
+ describe.concurrent('threshold params', () => {
947
+ it('encode/decode', () => {
948
+ const encodedParams = encodeThresholdParams({ threshold: BigInt(100) });
949
+ const decodedParams = decodeThresholdParams(encodedParams);
950
+ expect(decodedParams).toEqual({ threshold: BigInt(100) });
951
+ });
952
+ it('encode invalid params', () => {
953
+ expect(() => encodeThresholdParams({ threshold: BigInt(-1) })).toThrow('Invalid threshold -1: must be greater than or equal to 0');
954
+ });
955
+ });
956
+ describe.concurrent('erc1155 params', () => {
957
+ it('encode invalid params', () => {
958
+ expect(() => encodeERC1155Params({ threshold: BigInt(-1), tokenId: BigInt(100) })).toThrow('Invalid threshold -1: must be greater than or equal to 0');
959
+ });
960
+ it('encode invalid token id', () => {
961
+ expect(() => encodeERC1155Params({ threshold: BigInt(100), tokenId: BigInt(-1) })).toThrow('Invalid tokenId -1: must be greater than or equal to 0');
962
+ });
963
+ it('encode/decode', () => {
964
+ const encodedParams = encodeERC1155Params({ threshold: BigInt(200), tokenId: BigInt(100) });
965
+ const decodedParams = decodeERC1155Params(encodedParams);
966
+ expect(decodedParams).toEqual({ threshold: BigInt(200), tokenId: BigInt(100) });
967
+ });
968
+ });
969
+ function assertRuleDatasEqual(actual, expected) {
970
+ expect(expected.operations.length).toBe(actual.operations.length);
971
+ for (let i = 0; i < expected.operations.length; i++) {
972
+ expect(expected.operations[i].opType).toBe(actual.operations[i].opType);
973
+ expect(expected.operations[i].index).toBe(actual.operations[i].index);
974
+ }
975
+ expect(expected.checkOperations.length).toBe(actual.checkOperations.length);
976
+ for (let i = 0; i < expected.checkOperations.length; i++) {
977
+ expect(expected.checkOperations[i].opType).toBe(actual.checkOperations[i].opType);
978
+ expect(expected.checkOperations[i].chainId).toBe(actual.checkOperations[i].chainId);
979
+ expect(expected.checkOperations[i].contractAddress).toBe(actual.checkOperations[i].contractAddress);
980
+ expect(expected.checkOperations[i].params).toBe(actual.checkOperations[i].params);
981
+ }
982
+ expect(expected.logicalOperations.length).toBe(actual.logicalOperations.length);
983
+ for (let i = 0; i < expected.logicalOperations.length; i++) {
984
+ expect(expected.logicalOperations[i].logOpType).toBe(actual.logicalOperations[i].logOpType);
985
+ expect(expected.logicalOperations[i].leftOperationIndex).toBe(actual.logicalOperations[i].leftOperationIndex);
986
+ }
987
+ }
988
+ function assertOperationEqual(actual, expected) {
989
+ expect(actual.opType).toBe(expected.opType);
990
+ if (expected.opType === OperationType.CHECK) {
991
+ const actualCheck = actual;
992
+ const expectedCheck = expected;
993
+ expect(actualCheck.checkType).toBe(expectedCheck.checkType);
994
+ expect(actualCheck.chainId).toBe(expectedCheck.chainId);
995
+ expect(actualCheck.contractAddress).toBe(expectedCheck.contractAddress);
996
+ expect(actualCheck.params).toBe(expectedCheck.params);
997
+ }
998
+ else if (expected.opType === OperationType.LOGICAL) {
999
+ const actualLogical = actual;
1000
+ const expectedLogical = expected;
1001
+ expect(actualLogical.logicalType).toBe(expectedLogical.logicalType);
1002
+ // This check involves some redundance since these element have been visited already,
1003
+ // but it ensures that embedded operations in the tree are equal since the
1004
+ // operations tree does not use indices, but builds a tree directly.
1005
+ assertOperationEqual(actualLogical.leftOperation, expectedLogical.leftOperation);
1006
+ assertOperationEqual(actualLogical.rightOperation, expectedLogical.rightOperation);
1007
+ }
1008
+ else if (expected.opType === OperationType.NONE) {
1009
+ expect(actual.opType).toBe(expected.opType);
1010
+ }
1011
+ }
1012
+ function assertOperationsEqual(actual, expected) {
1013
+ expect(expected.length).toBe(actual.length);
1014
+ for (let i = 0; i < expected.length; i++) {
1015
+ assertOperationEqual(actual[i], expected[i]);
1016
+ }
1017
+ }
1018
+ describe.concurrent('createOperationsTree', () => {
1019
+ it('empty', () => {
1020
+ const checkOp = [];
1021
+ const tree = createOperationsTree(checkOp);
1022
+ expect(tree).toEqual({
1023
+ operations: [NoopOperation],
1024
+ checkOperations: [],
1025
+ logicalOperations: [],
1026
+ });
1027
+ // Validate conversion of rule data to operations tree (used for evaluation)
1028
+ const operations = ruleDataToOperations(tree);
1029
+ assertOperationsEqual(operations, [NoopOperation]);
1030
+ });
1031
+ it('custom entitlement check', () => {
1032
+ const checkOp = [
1033
+ {
1034
+ type: CheckOperationType.ISENTITLED,
1035
+ chainId: 1234n,
1036
+ address: MOCK_ADDRESS,
1037
+ byteEncodedParams: `0xdeadbeefdeadbeef12341234`,
1038
+ },
1039
+ ];
1040
+ const tree = createOperationsTree(checkOp);
1041
+ // Validate the constructed rule data
1042
+ assertRuleDatasEqual(tree, {
1043
+ operations: [
1044
+ {
1045
+ opType: OperationType.CHECK,
1046
+ index: 0,
1047
+ },
1048
+ ],
1049
+ checkOperations: [
1050
+ {
1051
+ opType: CheckOperationType.ISENTITLED,
1052
+ chainId: 1234n,
1053
+ contractAddress: MOCK_ADDRESS,
1054
+ params: `0xdeadbeefdeadbeef12341234`,
1055
+ },
1056
+ ],
1057
+ logicalOperations: [],
1058
+ });
1059
+ });
1060
+ it('single check', () => {
1061
+ const checkOp = [
1062
+ {
1063
+ type: CheckOperationType.ERC721,
1064
+ chainId: 1n,
1065
+ address: MOCK_ADDRESS,
1066
+ threshold: BigInt(1),
1067
+ },
1068
+ ];
1069
+ const tree = createOperationsTree(checkOp);
1070
+ // Validate the constructed rule data
1071
+ assertRuleDatasEqual(tree, {
1072
+ operations: [
1073
+ {
1074
+ opType: OperationType.CHECK,
1075
+ index: 0,
1076
+ },
1077
+ ],
1078
+ checkOperations: [
1079
+ {
1080
+ opType: CheckOperationType.ERC721,
1081
+ chainId: 1n,
1082
+ contractAddress: MOCK_ADDRESS,
1083
+ params: encodeThresholdParams({ threshold: BigInt(1) }),
1084
+ },
1085
+ ],
1086
+ logicalOperations: [],
1087
+ });
1088
+ });
1089
+ it('two checks', () => {
1090
+ const checkOp = [
1091
+ {
1092
+ type: CheckOperationType.ISENTITLED,
1093
+ chainId: 1n,
1094
+ address: MOCK_ADDRESS,
1095
+ },
1096
+ {
1097
+ type: CheckOperationType.ERC721,
1098
+ chainId: 1n,
1099
+ address: MOCK_ADDRESS_2,
1100
+ threshold: BigInt(1),
1101
+ },
1102
+ ];
1103
+ const tree = createOperationsTree(checkOp);
1104
+ // Validate the constructed rule data
1105
+ assertRuleDatasEqual(tree, {
1106
+ operations: [
1107
+ {
1108
+ opType: OperationType.CHECK,
1109
+ index: 0,
1110
+ },
1111
+ {
1112
+ opType: OperationType.CHECK,
1113
+ index: 1,
1114
+ },
1115
+ {
1116
+ opType: OperationType.LOGICAL,
1117
+ index: 0,
1118
+ },
1119
+ ],
1120
+ checkOperations: [
1121
+ {
1122
+ opType: CheckOperationType.ISENTITLED,
1123
+ chainId: 1n,
1124
+ contractAddress: MOCK_ADDRESS,
1125
+ params: '0x',
1126
+ },
1127
+ {
1128
+ opType: CheckOperationType.ERC721,
1129
+ chainId: 1n,
1130
+ contractAddress: MOCK_ADDRESS_2,
1131
+ params: encodeThresholdParams({ threshold: BigInt(1) }),
1132
+ },
1133
+ ],
1134
+ logicalOperations: [
1135
+ {
1136
+ logOpType: LogicalOperationType.OR,
1137
+ leftOperationIndex: 0,
1138
+ rightOperationIndex: 1,
1139
+ },
1140
+ ],
1141
+ });
1142
+ // Validate conversion of rule data to operations tree (used for evaluation)
1143
+ const operations = ruleDataToOperations(tree);
1144
+ const check1 = {
1145
+ opType: OperationType.CHECK,
1146
+ checkType: CheckOperationType.ISENTITLED,
1147
+ chainId: 1n,
1148
+ contractAddress: MOCK_ADDRESS,
1149
+ params: '0x',
1150
+ };
1151
+ const check2 = {
1152
+ opType: OperationType.CHECK,
1153
+ checkType: CheckOperationType.ERC721,
1154
+ chainId: 1n,
1155
+ contractAddress: MOCK_ADDRESS_2,
1156
+ params: encodeThresholdParams({ threshold: BigInt(1) }),
1157
+ };
1158
+ assertOperationsEqual(operations, [
1159
+ check1,
1160
+ check2,
1161
+ {
1162
+ opType: OperationType.LOGICAL,
1163
+ logicalType: LogicalOperationType.OR,
1164
+ leftOperation: check1,
1165
+ rightOperation: check2,
1166
+ },
1167
+ ]);
1168
+ });
1169
+ it('three checks', () => {
1170
+ /*
1171
+ 3-check tree:
1172
+ ============
1173
+
1174
+ logical2
1175
+ --------
1176
+ / \
1177
+ logical1 check3
1178
+ --------
1179
+ / \
1180
+ check1 check2
1181
+
1182
+ Postorder: check1, check2, logical1, check3, logical2
1183
+ */
1184
+ const checkOp = [
1185
+ {
1186
+ type: CheckOperationType.ISENTITLED,
1187
+ chainId: 1n,
1188
+ address: MOCK_ADDRESS,
1189
+ byteEncodedParams: `0xabcdef`,
1190
+ },
1191
+ {
1192
+ type: CheckOperationType.ERC721,
1193
+ chainId: 2n,
1194
+ address: MOCK_ADDRESS_2,
1195
+ threshold: BigInt(1),
1196
+ },
1197
+ {
1198
+ type: CheckOperationType.ERC20,
1199
+ chainId: 3n,
1200
+ address: MOCK_ADDRESS_3,
1201
+ threshold: BigInt(1),
1202
+ },
1203
+ ];
1204
+ const tree = createOperationsTree(checkOp);
1205
+ // Validate the constructed rule data
1206
+ assertRuleDatasEqual(tree, {
1207
+ operations: [
1208
+ {
1209
+ opType: OperationType.CHECK,
1210
+ index: 0,
1211
+ },
1212
+ {
1213
+ opType: OperationType.CHECK,
1214
+ index: 1,
1215
+ },
1216
+ {
1217
+ opType: OperationType.LOGICAL,
1218
+ index: 0,
1219
+ },
1220
+ {
1221
+ opType: OperationType.CHECK,
1222
+ index: 2,
1223
+ },
1224
+ {
1225
+ opType: OperationType.LOGICAL,
1226
+ index: 1,
1227
+ },
1228
+ ],
1229
+ checkOperations: [
1230
+ {
1231
+ opType: CheckOperationType.ISENTITLED,
1232
+ chainId: 1n,
1233
+ contractAddress: MOCK_ADDRESS,
1234
+ params: '0xabcdef',
1235
+ },
1236
+ {
1237
+ opType: CheckOperationType.ERC721,
1238
+ chainId: 2n,
1239
+ contractAddress: MOCK_ADDRESS_2,
1240
+ params: encodeThresholdParams({ threshold: BigInt(1) }),
1241
+ },
1242
+ {
1243
+ opType: CheckOperationType.ERC20,
1244
+ chainId: 3n,
1245
+ contractAddress: MOCK_ADDRESS_3,
1246
+ params: encodeThresholdParams({ threshold: BigInt(1) }),
1247
+ },
1248
+ ],
1249
+ logicalOperations: [
1250
+ {
1251
+ logOpType: LogicalOperationType.OR,
1252
+ leftOperationIndex: 0,
1253
+ rightOperationIndex: 1,
1254
+ },
1255
+ {
1256
+ logOpType: LogicalOperationType.OR,
1257
+ leftOperationIndex: 2,
1258
+ rightOperationIndex: 3,
1259
+ },
1260
+ ],
1261
+ });
1262
+ // Validate conversion of rule data to operations tree (used for evaluation)
1263
+ const operations = ruleDataToOperations(tree);
1264
+ const check1 = {
1265
+ opType: OperationType.CHECK,
1266
+ checkType: CheckOperationType.ISENTITLED,
1267
+ chainId: 1n,
1268
+ contractAddress: MOCK_ADDRESS,
1269
+ params: '0xabcdef',
1270
+ };
1271
+ const check2 = {
1272
+ opType: OperationType.CHECK,
1273
+ checkType: CheckOperationType.ERC721,
1274
+ chainId: 2n,
1275
+ contractAddress: MOCK_ADDRESS_2,
1276
+ params: encodeThresholdParams({ threshold: BigInt(1) }),
1277
+ };
1278
+ const check3 = {
1279
+ opType: OperationType.CHECK,
1280
+ checkType: CheckOperationType.ERC20,
1281
+ chainId: 3n,
1282
+ contractAddress: MOCK_ADDRESS_3,
1283
+ params: encodeThresholdParams({ threshold: BigInt(1) }),
1284
+ };
1285
+ const logical1 = {
1286
+ opType: OperationType.LOGICAL,
1287
+ logicalType: LogicalOperationType.OR,
1288
+ leftOperation: check1,
1289
+ rightOperation: check2,
1290
+ };
1291
+ const logical2 = {
1292
+ opType: OperationType.LOGICAL,
1293
+ logicalType: LogicalOperationType.OR,
1294
+ leftOperation: logical1,
1295
+ rightOperation: check3,
1296
+ };
1297
+ assertOperationsEqual(operations, [check1, check2, logical1, check3, logical2]);
1298
+ });
1299
+ it('five checks', () => {
1300
+ /*
1301
+ 5-check tree:
1302
+ =============
1303
+
1304
+ logical4
1305
+ --------
1306
+ / \
1307
+ logical3 check5
1308
+ --------
1309
+ / \
1310
+ logical1 logical2
1311
+ -------- --------
1312
+ / \ / \
1313
+ check1 check2 check3 check4
1314
+
1315
+ Postorder: check1, check2, logical1, check3, check4, logical2, logical3, check5, logical4
1316
+ */
1317
+ const checkOp = [
1318
+ {
1319
+ type: CheckOperationType.ISENTITLED,
1320
+ chainId: 1n,
1321
+ address: MOCK_ADDRESS,
1322
+ byteEncodedParams: `0xabcdef`,
1323
+ },
1324
+ {
1325
+ type: CheckOperationType.ERC721,
1326
+ chainId: 2n,
1327
+ address: MOCK_ADDRESS_2,
1328
+ threshold: BigInt(2),
1329
+ },
1330
+ {
1331
+ type: CheckOperationType.ERC20,
1332
+ chainId: 3n,
1333
+ address: MOCK_ADDRESS_3,
1334
+ threshold: BigInt(3),
1335
+ },
1336
+ {
1337
+ type: CheckOperationType.ERC721,
1338
+ chainId: 4n,
1339
+ address: MOCK_ADDRESS_4,
1340
+ threshold: BigInt(4),
1341
+ },
1342
+ {
1343
+ type: CheckOperationType.ERC20,
1344
+ chainId: 5n,
1345
+ address: MOCK_ADDRESS_5,
1346
+ threshold: BigInt(5),
1347
+ },
1348
+ ];
1349
+ const tree = createOperationsTree(checkOp);
1350
+ // Validate the constructed rule data
1351
+ log('tree', tree);
1352
+ const expectedTree = {
1353
+ operations: [
1354
+ {
1355
+ opType: OperationType.CHECK,
1356
+ index: 0,
1357
+ },
1358
+ {
1359
+ opType: OperationType.CHECK,
1360
+ index: 1,
1361
+ },
1362
+ {
1363
+ opType: OperationType.LOGICAL,
1364
+ index: 0,
1365
+ },
1366
+ {
1367
+ opType: OperationType.CHECK,
1368
+ index: 2,
1369
+ },
1370
+ {
1371
+ opType: OperationType.CHECK,
1372
+ index: 3,
1373
+ },
1374
+ {
1375
+ opType: OperationType.LOGICAL,
1376
+ index: 1,
1377
+ },
1378
+ {
1379
+ opType: OperationType.LOGICAL,
1380
+ index: 2,
1381
+ },
1382
+ {
1383
+ opType: OperationType.CHECK,
1384
+ index: 4,
1385
+ },
1386
+ {
1387
+ opType: OperationType.LOGICAL,
1388
+ index: 3,
1389
+ },
1390
+ ],
1391
+ checkOperations: [
1392
+ {
1393
+ opType: CheckOperationType.ISENTITLED,
1394
+ chainId: 1n,
1395
+ contractAddress: MOCK_ADDRESS,
1396
+ params: '0xabcdef',
1397
+ },
1398
+ {
1399
+ opType: CheckOperationType.ERC721,
1400
+ chainId: 2n,
1401
+ contractAddress: MOCK_ADDRESS_2,
1402
+ params: encodeThresholdParams({ threshold: BigInt(2) }),
1403
+ },
1404
+ {
1405
+ opType: CheckOperationType.ERC20,
1406
+ chainId: 3n,
1407
+ contractAddress: MOCK_ADDRESS_3,
1408
+ params: encodeThresholdParams({ threshold: BigInt(3) }),
1409
+ },
1410
+ {
1411
+ opType: CheckOperationType.ERC721,
1412
+ chainId: 4n,
1413
+ contractAddress: MOCK_ADDRESS_4,
1414
+ params: encodeThresholdParams({ threshold: BigInt(4) }),
1415
+ },
1416
+ {
1417
+ opType: CheckOperationType.ERC20,
1418
+ chainId: 5n,
1419
+ contractAddress: MOCK_ADDRESS_5,
1420
+ params: encodeThresholdParams({ threshold: BigInt(5) }),
1421
+ },
1422
+ ],
1423
+ logicalOperations: [
1424
+ {
1425
+ logOpType: LogicalOperationType.OR,
1426
+ leftOperationIndex: 0,
1427
+ rightOperationIndex: 1,
1428
+ },
1429
+ {
1430
+ logOpType: LogicalOperationType.OR,
1431
+ leftOperationIndex: 3,
1432
+ rightOperationIndex: 4,
1433
+ },
1434
+ {
1435
+ logOpType: LogicalOperationType.OR,
1436
+ leftOperationIndex: 2,
1437
+ rightOperationIndex: 5,
1438
+ },
1439
+ {
1440
+ logOpType: LogicalOperationType.OR,
1441
+ leftOperationIndex: 6,
1442
+ rightOperationIndex: 7,
1443
+ },
1444
+ ],
1445
+ };
1446
+ assertRuleDatasEqual(tree, expectedTree);
1447
+ // Validate conversion of rule data to operations tree (used for evaluation)
1448
+ const operations = ruleDataToOperations(tree);
1449
+ const check1 = {
1450
+ opType: OperationType.CHECK,
1451
+ checkType: CheckOperationType.ISENTITLED,
1452
+ chainId: 1n,
1453
+ contractAddress: MOCK_ADDRESS,
1454
+ params: '0xabcdef',
1455
+ };
1456
+ const check2 = {
1457
+ opType: OperationType.CHECK,
1458
+ checkType: CheckOperationType.ERC721,
1459
+ chainId: 2n,
1460
+ contractAddress: MOCK_ADDRESS_2,
1461
+ params: encodeThresholdParams({ threshold: BigInt(2) }),
1462
+ };
1463
+ const check3 = {
1464
+ opType: OperationType.CHECK,
1465
+ checkType: CheckOperationType.ERC20,
1466
+ chainId: 3n,
1467
+ contractAddress: MOCK_ADDRESS_3,
1468
+ params: encodeThresholdParams({ threshold: BigInt(3) }),
1469
+ };
1470
+ const check4 = {
1471
+ opType: OperationType.CHECK,
1472
+ checkType: CheckOperationType.ERC721,
1473
+ chainId: 4n,
1474
+ contractAddress: MOCK_ADDRESS_4,
1475
+ params: encodeThresholdParams({ threshold: BigInt(4) }),
1476
+ };
1477
+ const check5 = {
1478
+ opType: OperationType.CHECK,
1479
+ checkType: CheckOperationType.ERC20,
1480
+ chainId: 5n,
1481
+ contractAddress: MOCK_ADDRESS_5,
1482
+ params: encodeThresholdParams({ threshold: BigInt(5) }),
1483
+ };
1484
+ const logical1 = {
1485
+ opType: OperationType.LOGICAL,
1486
+ logicalType: LogicalOperationType.OR,
1487
+ leftOperation: check1,
1488
+ rightOperation: check2,
1489
+ };
1490
+ const logical2 = {
1491
+ opType: OperationType.LOGICAL,
1492
+ logicalType: LogicalOperationType.OR,
1493
+ leftOperation: check3,
1494
+ rightOperation: check4,
1495
+ };
1496
+ const logical3 = {
1497
+ opType: OperationType.LOGICAL,
1498
+ logicalType: LogicalOperationType.OR,
1499
+ leftOperation: logical1,
1500
+ rightOperation: logical2,
1501
+ };
1502
+ const logical4 = {
1503
+ opType: OperationType.LOGICAL,
1504
+ logicalType: LogicalOperationType.OR,
1505
+ leftOperation: logical3,
1506
+ rightOperation: check5,
1507
+ };
1508
+ const expectedOperations = [
1509
+ check1,
1510
+ check2,
1511
+ logical1,
1512
+ check3,
1513
+ check4,
1514
+ logical2,
1515
+ logical3,
1516
+ check5,
1517
+ logical4,
1518
+ ];
1519
+ assertOperationsEqual(operations, expectedOperations);
1520
+ });
1521
+ });
1522
+ describe.concurrent('evaluateOperationsForEntitledWallet', () => {
1523
+ it.concurrent('4 checks - evaluateOperationsForEntitledWallet', async () => {
1524
+ const checkOp = [
1525
+ // pass
1526
+ {
1527
+ type: CheckOperationType.ERC1155,
1528
+ chainId: baseSepoliaChainId,
1529
+ address: baseSepoliaErc1155Contract,
1530
+ threshold: BigInt(700),
1531
+ tokenId: 0n,
1532
+ },
1533
+ // fail
1534
+ {
1535
+ type: CheckOperationType.ISENTITLED,
1536
+ chainId: 1n,
1537
+ address: MOCK_ADDRESS,
1538
+ byteEncodedParams: `0xabcdef`,
1539
+ },
1540
+ // fail
1541
+ {
1542
+ type: CheckOperationType.ERC1155,
1543
+ chainId: baseSepoliaChainId,
1544
+ address: baseSepoliaErc1155Contract,
1545
+ threshold: BigInt(900),
1546
+ tokenId: 0n,
1547
+ },
1548
+ // fail
1549
+ {
1550
+ type: CheckOperationType.ERC1155,
1551
+ chainId: baseSepoliaChainId,
1552
+ address: baseSepoliaErc1155Contract,
1553
+ threshold: BigInt(10_000),
1554
+ tokenId: 1n,
1555
+ },
1556
+ ];
1557
+ const tree = createOperationsTree(checkOp);
1558
+ const operations = ruleDataToOperations(tree);
1559
+ // if evaluateOperationsForEntitledWallet does not internally create a postOrderArrayToTree,
1560
+ // this will fail past a threshold of 4 Check operations
1561
+ const result = await evaluateOperationsForEntitledWallet(operations, [baseSepoliaErc1155Wallet_TokenId0_700Tokens], xchainConfig);
1562
+ expect(result).not.toEqual(zeroAddress);
1563
+ });
1564
+ });
1565
+ describe.concurrent('DecodedCheckOpBuilder', () => {
1566
+ it('Untyped', () => {
1567
+ expect(() => {
1568
+ new DecodedCheckOperationBuilder().build();
1569
+ }).toThrow('DecodedCheckOperation requires a type');
1570
+ });
1571
+ it('ERC20s', () => {
1572
+ expect(() => {
1573
+ new DecodedCheckOperationBuilder()
1574
+ .setType(CheckOperationType.ERC20)
1575
+ .setAddress(zeroAddress)
1576
+ .setThreshold(1n)
1577
+ .build();
1578
+ }).toThrow('DecodedCheckOperation of type ERC20 requires a chainId');
1579
+ expect(() => {
1580
+ new DecodedCheckOperationBuilder()
1581
+ .setType(CheckOperationType.ERC20)
1582
+ .setChainId(1n)
1583
+ .setThreshold(1n)
1584
+ .build();
1585
+ }).toThrow('DecodedCheckOperation of type ERC20 requires an address');
1586
+ expect(() => {
1587
+ new DecodedCheckOperationBuilder()
1588
+ .setType(CheckOperationType.ERC20)
1589
+ .setChainId(1n)
1590
+ .setAddress(zeroAddress)
1591
+ .build();
1592
+ }).toThrow('DecodedCheckOperation of type ERC20 requires a threshold');
1593
+ // Valid example
1594
+ const decoded = new DecodedCheckOperationBuilder()
1595
+ .setType(CheckOperationType.ERC20)
1596
+ .setChainId(1n)
1597
+ .setAddress(zeroAddress)
1598
+ .setThreshold(5n)
1599
+ .build();
1600
+ expect(decoded).toEqual({
1601
+ type: CheckOperationType.ERC20,
1602
+ chainId: 1n,
1603
+ address: zeroAddress,
1604
+ threshold: 5n,
1605
+ });
1606
+ });
1607
+ it('ERC721s', () => {
1608
+ expect(() => {
1609
+ new DecodedCheckOperationBuilder()
1610
+ .setType(CheckOperationType.ERC721)
1611
+ .setAddress(zeroAddress)
1612
+ .setThreshold(1n)
1613
+ .build();
1614
+ }).toThrow('DecodedCheckOperation of type ERC721 requires a chainId');
1615
+ expect(() => {
1616
+ new DecodedCheckOperationBuilder()
1617
+ .setType(CheckOperationType.ERC721)
1618
+ .setChainId(1n)
1619
+ .setThreshold(1n)
1620
+ .build();
1621
+ }).toThrow('DecodedCheckOperation of type ERC721 requires an address');
1622
+ expect(() => {
1623
+ new DecodedCheckOperationBuilder()
1624
+ .setType(CheckOperationType.ERC721)
1625
+ .setChainId(1n)
1626
+ .setAddress(zeroAddress)
1627
+ .build();
1628
+ }).toThrow('DecodedCheckOperation of type ERC721 requires a threshold');
1629
+ // Valid example
1630
+ const decoded = new DecodedCheckOperationBuilder()
1631
+ .setType(CheckOperationType.ERC721)
1632
+ .setChainId(1n)
1633
+ .setAddress(zeroAddress)
1634
+ .setThreshold(5n)
1635
+ .build();
1636
+ expect(decoded).toEqual({
1637
+ type: CheckOperationType.ERC721,
1638
+ chainId: 1n,
1639
+ address: zeroAddress,
1640
+ threshold: 5n,
1641
+ });
1642
+ });
1643
+ it('ERC1155s', () => {
1644
+ expect(() => {
1645
+ new DecodedCheckOperationBuilder()
1646
+ .setType(CheckOperationType.ERC1155)
1647
+ .setAddress(zeroAddress)
1648
+ .setThreshold(1n)
1649
+ .setTokenId(5n)
1650
+ .build();
1651
+ }).toThrow('DecodedCheckOperation of type ERC1155 requires a chainId');
1652
+ expect(() => {
1653
+ new DecodedCheckOperationBuilder()
1654
+ .setType(CheckOperationType.ERC1155)
1655
+ .setChainId(1n)
1656
+ .setThreshold(1n)
1657
+ .setTokenId(5n)
1658
+ .build();
1659
+ }).toThrow('DecodedCheckOperation of type ERC1155 requires an address');
1660
+ expect(() => {
1661
+ new DecodedCheckOperationBuilder()
1662
+ .setType(CheckOperationType.ERC1155)
1663
+ .setChainId(1n)
1664
+ .setAddress(zeroAddress)
1665
+ .setTokenId(5n)
1666
+ .build();
1667
+ }).toThrow('DecodedCheckOperation of type ERC1155 requires a threshold');
1668
+ expect(() => {
1669
+ new DecodedCheckOperationBuilder()
1670
+ .setType(CheckOperationType.ERC1155)
1671
+ .setChainId(1n)
1672
+ .setAddress(zeroAddress)
1673
+ .setThreshold(3n)
1674
+ .build();
1675
+ }).toThrow('DecodedCheckOperation of type ERC1155 requires a tokenId');
1676
+ // Valid example
1677
+ const decoded = new DecodedCheckOperationBuilder()
1678
+ .setType(CheckOperationType.ERC1155)
1679
+ .setChainId(1n)
1680
+ .setAddress(zeroAddress)
1681
+ .setThreshold(5n)
1682
+ .setTokenId(9n)
1683
+ .build();
1684
+ expect(decoded).toEqual({
1685
+ type: CheckOperationType.ERC1155,
1686
+ chainId: 1n,
1687
+ address: zeroAddress,
1688
+ threshold: 5n,
1689
+ tokenId: 9n,
1690
+ });
1691
+ });
1692
+ it('ETH_BALANCE', () => {
1693
+ expect(() => {
1694
+ new DecodedCheckOperationBuilder().setType(CheckOperationType.ETH_BALANCE).build();
1695
+ }).toThrow('DecodedCheckOperation of type ETH_BALANCE requires a threshold');
1696
+ // Valid example
1697
+ const decoded = new DecodedCheckOperationBuilder()
1698
+ .setType(CheckOperationType.ETH_BALANCE)
1699
+ .setThreshold(5n)
1700
+ .build();
1701
+ expect(decoded).toEqual({
1702
+ type: CheckOperationType.ETH_BALANCE,
1703
+ threshold: 5n,
1704
+ });
1705
+ });
1706
+ it('ISENTITLED', () => {
1707
+ expect(() => {
1708
+ new DecodedCheckOperationBuilder()
1709
+ .setType(CheckOperationType.ISENTITLED)
1710
+ .setAddress(zeroAddress)
1711
+ .setByteEncodedParams('0xabcdef1234')
1712
+ .build();
1713
+ }).toThrow('DecodedCheckOperation of type ISENTITLED requires a chainId');
1714
+ expect(() => {
1715
+ new DecodedCheckOperationBuilder()
1716
+ .setType(CheckOperationType.ISENTITLED)
1717
+ .setChainId(1n)
1718
+ .setByteEncodedParams('0xabcdef1234')
1719
+ .build();
1720
+ }).toThrow('DecodedCheckOperation of type ISENTITLED requires an address');
1721
+ expect(() => {
1722
+ new DecodedCheckOperationBuilder()
1723
+ .setType(CheckOperationType.ISENTITLED)
1724
+ .setChainId(1n)
1725
+ .setAddress(zeroAddress)
1726
+ .build();
1727
+ }).toThrow('DecodedCheckOperation of type ISENTITLED requires byteEncodedParams');
1728
+ // Valid example
1729
+ const decoded = new DecodedCheckOperationBuilder()
1730
+ .setType(CheckOperationType.ISENTITLED)
1731
+ .setChainId(1n)
1732
+ .setAddress(zeroAddress)
1733
+ .setByteEncodedParams('0xabcdef1234')
1734
+ .build();
1735
+ expect(decoded).toEqual({
1736
+ type: CheckOperationType.ISENTITLED,
1737
+ chainId: 1n,
1738
+ address: zeroAddress,
1739
+ byteEncodedParams: `0xabcdef1234`,
1740
+ });
1741
+ });
1742
+ });
1743
+ //# sourceMappingURL=entitlement.test.js.map