@dev.sail.money/sailor 0.0.2-12

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 (319) hide show
  1. package/AGENTS.md +111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +337 -0
  4. package/docs/PERMISSION_MODEL.md +93 -0
  5. package/examples/permissions/BoundedBet_Limitless_Base.sol +96 -0
  6. package/examples/permissions/BoundedBorrow_AaveV3_Arbitrum.sol +94 -0
  7. package/examples/permissions/BoundedPerp_GMXv2_Arbitrum.sol +143 -0
  8. package/examples/permissions/BoundedSwap_UniswapV3_Base.sol +113 -0
  9. package/examples/permissions/BoundedSwap_UniswapV4_Unichain.sol +144 -0
  10. package/examples/permissions/BoundedTransfer_ERC20_Ethereum.sol +73 -0
  11. package/examples/permissions/README.md +52 -0
  12. package/examples/permissions/foundry.toml +10 -0
  13. package/examples/permissions/interfaces/IPermission.sol +18 -0
  14. package/package.json +39 -0
  15. package/packages/cli/README.md +34 -0
  16. package/packages/cli/dist/index.cjs +42801 -0
  17. package/packages/cli/dist/server.cjs +51201 -0
  18. package/packages/sdk/README.md +65 -0
  19. package/packages/sdk/dist/abis/MandateFactory.d.ts +140 -0
  20. package/packages/sdk/dist/abis/MandateFactory.d.ts.map +1 -0
  21. package/packages/sdk/dist/abis/MandateFactory.js +93 -0
  22. package/packages/sdk/dist/abis/MandateFactory.js.map +1 -0
  23. package/packages/sdk/dist/abis/SailGovernance.d.ts +57 -0
  24. package/packages/sdk/dist/abis/SailGovernance.d.ts.map +1 -0
  25. package/packages/sdk/dist/abis/SailGovernance.js +52 -0
  26. package/packages/sdk/dist/abis/SailGovernance.js.map +1 -0
  27. package/packages/sdk/dist/abis/SailKernel.d.ts +466 -0
  28. package/packages/sdk/dist/abis/SailKernel.d.ts.map +1 -0
  29. package/packages/sdk/dist/abis/SailKernel.js +311 -0
  30. package/packages/sdk/dist/abis/SailKernel.js.map +1 -0
  31. package/packages/sdk/dist/abis/index.d.ts +4 -0
  32. package/packages/sdk/dist/abis/index.d.ts.map +1 -0
  33. package/packages/sdk/dist/abis/index.js +7 -0
  34. package/packages/sdk/dist/abis/index.js.map +1 -0
  35. package/packages/sdk/dist/capabilities.d.ts +77 -0
  36. package/packages/sdk/dist/capabilities.d.ts.map +1 -0
  37. package/packages/sdk/dist/capabilities.js +158 -0
  38. package/packages/sdk/dist/capabilities.js.map +1 -0
  39. package/packages/sdk/dist/client.d.ts +37 -0
  40. package/packages/sdk/dist/client.d.ts.map +1 -0
  41. package/packages/sdk/dist/client.js +646 -0
  42. package/packages/sdk/dist/client.js.map +1 -0
  43. package/packages/sdk/dist/deployments.d.ts +82 -0
  44. package/packages/sdk/dist/deployments.d.ts.map +1 -0
  45. package/packages/sdk/dist/deployments.js +197 -0
  46. package/packages/sdk/dist/deployments.js.map +1 -0
  47. package/packages/sdk/dist/discovery.d.ts +10 -0
  48. package/packages/sdk/dist/discovery.d.ts.map +1 -0
  49. package/packages/sdk/dist/discovery.js +41 -0
  50. package/packages/sdk/dist/discovery.js.map +1 -0
  51. package/packages/sdk/dist/eip712.d.ts +257 -0
  52. package/packages/sdk/dist/eip712.d.ts.map +1 -0
  53. package/packages/sdk/dist/eip712.js +255 -0
  54. package/packages/sdk/dist/eip712.js.map +1 -0
  55. package/packages/sdk/dist/errors.d.ts +47 -0
  56. package/packages/sdk/dist/errors.d.ts.map +1 -0
  57. package/packages/sdk/dist/errors.js +168 -0
  58. package/packages/sdk/dist/errors.js.map +1 -0
  59. package/packages/sdk/dist/fees.d.ts +16 -0
  60. package/packages/sdk/dist/fees.d.ts.map +1 -0
  61. package/packages/sdk/dist/fees.js +51 -0
  62. package/packages/sdk/dist/fees.js.map +1 -0
  63. package/packages/sdk/dist/index.d.ts +23 -0
  64. package/packages/sdk/dist/index.d.ts.map +1 -0
  65. package/packages/sdk/dist/index.js +16 -0
  66. package/packages/sdk/dist/index.js.map +1 -0
  67. package/packages/sdk/dist/intelligence.d.ts +923 -0
  68. package/packages/sdk/dist/intelligence.d.ts.map +1 -0
  69. package/packages/sdk/dist/intelligence.js +357 -0
  70. package/packages/sdk/dist/intelligence.js.map +1 -0
  71. package/packages/sdk/dist/keyring.d.ts +60 -0
  72. package/packages/sdk/dist/keyring.d.ts.map +1 -0
  73. package/packages/sdk/dist/keyring.js +159 -0
  74. package/packages/sdk/dist/keyring.js.map +1 -0
  75. package/packages/sdk/dist/lifi.d.ts +83 -0
  76. package/packages/sdk/dist/lifi.d.ts.map +1 -0
  77. package/packages/sdk/dist/lifi.js +69 -0
  78. package/packages/sdk/dist/lifi.js.map +1 -0
  79. package/packages/sdk/dist/safe.d.ts +158 -0
  80. package/packages/sdk/dist/safe.d.ts.map +1 -0
  81. package/packages/sdk/dist/safe.js +163 -0
  82. package/packages/sdk/dist/safe.js.map +1 -0
  83. package/packages/sdk/dist/signing.d.ts +106 -0
  84. package/packages/sdk/dist/signing.d.ts.map +1 -0
  85. package/packages/sdk/dist/signing.js +2 -0
  86. package/packages/sdk/dist/signing.js.map +1 -0
  87. package/packages/sdk/dist/templates/ammLiquidity.d.ts +16 -0
  88. package/packages/sdk/dist/templates/ammLiquidity.d.ts.map +1 -0
  89. package/packages/sdk/dist/templates/ammLiquidity.js +60 -0
  90. package/packages/sdk/dist/templates/ammLiquidity.js.map +1 -0
  91. package/packages/sdk/dist/templates/approveAndCallBatch.d.ts +14 -0
  92. package/packages/sdk/dist/templates/approveAndCallBatch.d.ts.map +1 -0
  93. package/packages/sdk/dist/templates/approveAndCallBatch.js +53 -0
  94. package/packages/sdk/dist/templates/approveAndCallBatch.js.map +1 -0
  95. package/packages/sdk/dist/templates/boundedBorrow.d.ts +16 -0
  96. package/packages/sdk/dist/templates/boundedBorrow.d.ts.map +1 -0
  97. package/packages/sdk/dist/templates/boundedBorrow.js +56 -0
  98. package/packages/sdk/dist/templates/boundedBorrow.js.map +1 -0
  99. package/packages/sdk/dist/templates/boundedSwap.d.ts +16 -0
  100. package/packages/sdk/dist/templates/boundedSwap.d.ts.map +1 -0
  101. package/packages/sdk/dist/templates/boundedSwap.js +56 -0
  102. package/packages/sdk/dist/templates/boundedSwap.js.map +1 -0
  103. package/packages/sdk/dist/templates/defiBundle.d.ts +14 -0
  104. package/packages/sdk/dist/templates/defiBundle.d.ts.map +1 -0
  105. package/packages/sdk/dist/templates/defiBundle.js +52 -0
  106. package/packages/sdk/dist/templates/defiBundle.js.map +1 -0
  107. package/packages/sdk/dist/templates/index.d.ts +15 -0
  108. package/packages/sdk/dist/templates/index.d.ts.map +1 -0
  109. package/packages/sdk/dist/templates/index.js +8 -0
  110. package/packages/sdk/dist/templates/index.js.map +1 -0
  111. package/packages/sdk/dist/templates/pendle.d.ts +14 -0
  112. package/packages/sdk/dist/templates/pendle.d.ts.map +1 -0
  113. package/packages/sdk/dist/templates/pendle.js +52 -0
  114. package/packages/sdk/dist/templates/pendle.js.map +1 -0
  115. package/packages/sdk/dist/templates/transferTarget.d.ts +10 -0
  116. package/packages/sdk/dist/templates/transferTarget.d.ts.map +1 -0
  117. package/packages/sdk/dist/templates/transferTarget.js +42 -0
  118. package/packages/sdk/dist/templates/transferTarget.js.map +1 -0
  119. package/packages/sdk/dist/types.d.ts +382 -0
  120. package/packages/sdk/dist/types.d.ts.map +1 -0
  121. package/packages/sdk/dist/types.js +2 -0
  122. package/packages/sdk/dist/types.js.map +1 -0
  123. package/packages/sdk/package.json +52 -0
  124. package/packages/ui/dist/assets/Arc-VDBY7LNS-BChRXCXW.js +1 -0
  125. package/packages/ui/dist/assets/Brave-BRAKJXDS-mq-Xo37j.js +1 -0
  126. package/packages/ui/dist/assets/Browser-76IHF3Y2-BMhRaC5Z.js +1 -0
  127. package/packages/ui/dist/assets/Chrome-65Q5P54Y-DR9MQEVr.js +1 -0
  128. package/packages/ui/dist/assets/Edge-XSPUTORV-DEoZslQE.js +1 -0
  129. package/packages/ui/dist/assets/Firefox-AAHGJQIP-Bp_Hm04m.js +1 -0
  130. package/packages/ui/dist/assets/Linux-OO4TNCLJ-B0aw93n9.js +1 -0
  131. package/packages/ui/dist/assets/Macos-MW4AE7LN-Vvm8Drw3.js +1 -0
  132. package/packages/ui/dist/assets/Opera-KQZLSACL-Cwv5MDFy.js +1 -0
  133. package/packages/ui/dist/assets/Safari-ZPL37GXR-C4Ggg6rz.js +1 -0
  134. package/packages/ui/dist/assets/Windows-PPTHQER6-BlyV2p7Y.js +1 -0
  135. package/packages/ui/dist/assets/add-DaJhwIBV.js +15 -0
  136. package/packages/ui/dist/assets/all-wallets-BUxsqWXi.js +6 -0
  137. package/packages/ui/dist/assets/apechain-SX5YFU6N-q5qBv-mp.js +1 -0
  138. package/packages/ui/dist/assets/app-store-DkltwTqE.js +17 -0
  139. package/packages/ui/dist/assets/apple-owVOeaIT.js +18 -0
  140. package/packages/ui/dist/assets/ar_AR-LIPSOZP5-BQrIDibT.js +1519 -0
  141. package/packages/ui/dist/assets/arbitrum-WURIBY6W-CqVkHBr5.js +1 -0
  142. package/packages/ui/dist/assets/arrow-bottom-D2mmNJve.js +8 -0
  143. package/packages/ui/dist/assets/arrow-bottom-circle-CbNYijx-.js +11 -0
  144. package/packages/ui/dist/assets/arrow-left-DJB61s4C.js +8 -0
  145. package/packages/ui/dist/assets/arrow-right-BBrsQ9R4.js +8 -0
  146. package/packages/ui/dist/assets/arrow-top-Cil6bOc8.js +8 -0
  147. package/packages/ui/dist/assets/assets-Q6ZU7ZJ5-P8HioiAD.js +1 -0
  148. package/packages/ui/dist/assets/avalanche-KOMJD3XY-Dsn_JPR4.js +1 -0
  149. package/packages/ui/dist/assets/bank-CbwEmRo3.js +14 -0
  150. package/packages/ui/dist/assets/base-OAXLRA4F-CoYTVIiL.js +1 -0
  151. package/packages/ui/dist/assets/base-QS6CYWIN-CsjdbWCf.js +1 -0
  152. package/packages/ui/dist/assets/basic-CLNfjw3m.js +2128 -0
  153. package/packages/ui/dist/assets/berachain-NJECWIVC-DumxnFvf.js +1 -0
  154. package/packages/ui/dist/assets/blast-V555OVXZ-BbhJh1tj.js +1 -0
  155. package/packages/ui/dist/assets/browser-B5TtF4Pb.js +14 -0
  156. package/packages/ui/dist/assets/bsc-N647EYR2-B2nLKXWV.js +1 -0
  157. package/packages/ui/dist/assets/card-CO7BVB-C.js +14 -0
  158. package/packages/ui/dist/assets/ccip-2W7K3_J3.js +1 -0
  159. package/packages/ui/dist/assets/celo-GEP4TUHG-CenIBYLU.js +1 -0
  160. package/packages/ui/dist/assets/checkmark-BEtSHq9m.js +11 -0
  161. package/packages/ui/dist/assets/checkmark-bold-D9xGHzPE.js +8 -0
  162. package/packages/ui/dist/assets/chevron-bottom-BDztht6i.js +8 -0
  163. package/packages/ui/dist/assets/chevron-left-EV4GFNbc.js +8 -0
  164. package/packages/ui/dist/assets/chevron-right-B4_bB9oR.js +8 -0
  165. package/packages/ui/dist/assets/chevron-top-D54xPNzF.js +8 -0
  166. package/packages/ui/dist/assets/chrome-store-DYUpAJJq.js +61 -0
  167. package/packages/ui/dist/assets/clock-Ca1T1Soz.js +8 -0
  168. package/packages/ui/dist/assets/close-BZqWjurK.js +8 -0
  169. package/packages/ui/dist/assets/coinPlaceholder-e6fl2XDo.js +8 -0
  170. package/packages/ui/dist/assets/compass-DCLC7zIh.js +8 -0
  171. package/packages/ui/dist/assets/connect-UA7M4XW6-IY3X6Bmr.js +1 -0
  172. package/packages/ui/dist/assets/copy-Th2AaD-O.js +15 -0
  173. package/packages/ui/dist/assets/core-Ckx_cyuH.js +907 -0
  174. package/packages/ui/dist/assets/create-FASO7PVG-D_rvSpre.js +1 -0
  175. package/packages/ui/dist/assets/cronos-HJPAQTAE-BEOvlOC4.js +1 -0
  176. package/packages/ui/dist/assets/cursor-DV7rOqbJ.js +3 -0
  177. package/packages/ui/dist/assets/cursor-transparent-BKHeABKB.js +12 -0
  178. package/packages/ui/dist/assets/de_DE-YE3KOFHU-BRt5ztUe.js +1519 -0
  179. package/packages/ui/dist/assets/degen-FQQ4XGHB-CeHTs88l.js +1 -0
  180. package/packages/ui/dist/assets/desktop-CBjY8t6F.js +9 -0
  181. package/packages/ui/dist/assets/disconnect-DbSs2cli.js +8 -0
  182. package/packages/ui/dist/assets/discord-ZlLOAUkM.js +17 -0
  183. package/packages/ui/dist/assets/es_419-7LMPU7G4-DH7rM0yQ.js +1519 -0
  184. package/packages/ui/dist/assets/ethereum-RGGVA4PY-SWGOlkuk.js +1 -0
  185. package/packages/ui/dist/assets/etherscan-CKUrqWYN.js +6 -0
  186. package/packages/ui/dist/assets/events-CiKP71cK.js +1 -0
  187. package/packages/ui/dist/assets/exclamation-triangle-DA1QzFiO.js +4 -0
  188. package/packages/ui/dist/assets/extension-BVJkmvpJ.js +8 -0
  189. package/packages/ui/dist/assets/external-link-D_bsR7B2.js +8 -0
  190. package/packages/ui/dist/assets/facebook-CmFmhojx.js +26 -0
  191. package/packages/ui/dist/assets/fallback-Ofl6uSnB.js +1 -0
  192. package/packages/ui/dist/assets/farcaster-Co-M3Ss8.js +12 -0
  193. package/packages/ui/dist/assets/filters-B1WwNaFU.js +8 -0
  194. package/packages/ui/dist/assets/flow-5FQJFCTK-CUie2reO.js +1 -0
  195. package/packages/ui/dist/assets/fr_FR-VBJP3ZLL-B-_ocunw.js +1519 -0
  196. package/packages/ui/dist/assets/github-CP4fP6gn.js +18 -0
  197. package/packages/ui/dist/assets/gnosis-37ZC4RBL-B137OtHZ.js +1 -0
  198. package/packages/ui/dist/assets/google-CsOIXJ6V.js +18 -0
  199. package/packages/ui/dist/assets/gravity-J5YQHTYH-Bj6B0uod.js +1 -0
  200. package/packages/ui/dist/assets/hardhat-TX56IT5N-CV1FY-wE.js +1 -0
  201. package/packages/ui/dist/assets/help-circle-DiMkomdF.js +12 -0
  202. package/packages/ui/dist/assets/hi_IN-WBVD5XYI-D73g2UFs.js +1519 -0
  203. package/packages/ui/dist/assets/hyperevm-VKPAA4SA-CHwraEsx.js +1 -0
  204. package/packages/ui/dist/assets/id-lmscL5LX.js +12 -0
  205. package/packages/ui/dist/assets/id_ID-SBYANJ7G-Cjpa4ay6.js +1519 -0
  206. package/packages/ui/dist/assets/image-B-ubJrY5.js +4 -0
  207. package/packages/ui/dist/assets/index-BaukYv-x.js +16 -0
  208. package/packages/ui/dist/assets/index-CF0KMmke.js +395 -0
  209. package/packages/ui/dist/assets/index-CKxgNxS9.css +1 -0
  210. package/packages/ui/dist/assets/index-CZR1Qjhs.js +1 -0
  211. package/packages/ui/dist/assets/index-DVgfCzCo.js +1 -0
  212. package/packages/ui/dist/assets/index-Dbh5V1Z0.js +1 -0
  213. package/packages/ui/dist/assets/index-Q2Yai4Fe.js +2103 -0
  214. package/packages/ui/dist/assets/index.es-C78cE5SI.js +26 -0
  215. package/packages/ui/dist/assets/info-Cqg57EVo.js +3 -0
  216. package/packages/ui/dist/assets/info-circle-DkeSWNKV.js +12 -0
  217. package/packages/ui/dist/assets/ink-FZMYZWHG-62p-5IK5.js +1 -0
  218. package/packages/ui/dist/assets/ja_JP-ZRMWJV3I-DXbifiMm.js +1519 -0
  219. package/packages/ui/dist/assets/kaia-65D2U3PU-JmuLQ4gC.js +1 -0
  220. package/packages/ui/dist/assets/ko_KR-FR54RFUG-upinSHjQ.js +1519 -0
  221. package/packages/ui/dist/assets/lightbulb-DNlO4qKh.js +3 -0
  222. package/packages/ui/dist/assets/linea-QRMVQ5DY-DuI3vv0d.js +1 -0
  223. package/packages/ui/dist/assets/login-UP3DZBGS-Db_wM5oQ.js +1 -0
  224. package/packages/ui/dist/assets/mail-kVQ8Jb9Y.js +8 -0
  225. package/packages/ui/dist/assets/manta-SI27YFEJ-CpVOKa06.js +1 -0
  226. package/packages/ui/dist/assets/mantle-CKIUT334-DR2WgqzU.js +1 -0
  227. package/packages/ui/dist/assets/metaMaskWallet-EI6MED72-D5HFOsnz.js +1 -0
  228. package/packages/ui/dist/assets/metamask-sdk-CBalSvz7.js +542 -0
  229. package/packages/ui/dist/assets/mobile-BEteuhF7.js +9 -0
  230. package/packages/ui/dist/assets/monad-4KWC6TSS-DVXSkpiz.js +1 -0
  231. package/packages/ui/dist/assets/more-DBWmXQli.js +11 -0
  232. package/packages/ui/dist/assets/ms_MY-EZSGYYYQ-4cPLK-3L.js +1519 -0
  233. package/packages/ui/dist/assets/native-CJ5et6AR.js +1 -0
  234. package/packages/ui/dist/assets/network-placeholder-Dg1uUHiL.js +14 -0
  235. package/packages/ui/dist/assets/nftPlaceholder-i3AHSiD9.js +8 -0
  236. package/packages/ui/dist/assets/off-BtMm0fi2.js +8 -0
  237. package/packages/ui/dist/assets/optimism-HAF2GUT7-ec6Nqxs9.js +1 -0
  238. package/packages/ui/dist/assets/parseSignature-Cb5FlWWg.js +1 -0
  239. package/packages/ui/dist/assets/play-store-iKKkXa6a.js +32 -0
  240. package/packages/ui/dist/assets/plus-CA5NaRtb.js +13 -0
  241. package/packages/ui/dist/assets/polygon-WW6ZI7PM-DXlmm4L1.js +1 -0
  242. package/packages/ui/dist/assets/pt_BR-JQFQ3P4L-DOHfdcA2.js +1519 -0
  243. package/packages/ui/dist/assets/qr-code-D2kiqR7h.js +6 -0
  244. package/packages/ui/dist/assets/rainbowWallet-O26YNBMX-DUhYus-9.js +1 -0
  245. package/packages/ui/dist/assets/recycle-horizontal-Dcme7R03.js +9 -0
  246. package/packages/ui/dist/assets/refresh-Dega3sDp.js +8 -0
  247. package/packages/ui/dist/assets/refresh-S4T5V5GX-CwqIaaxK.js +1 -0
  248. package/packages/ui/dist/assets/reown-logo-xNkksyWJ.js +12 -0
  249. package/packages/ui/dist/assets/ronin-EMCPYXZT-N-QBHZdV.js +1 -0
  250. package/packages/ui/dist/assets/ru_RU-Z42UEJBP-Cvb2oWxQ.js +1519 -0
  251. package/packages/ui/dist/assets/safeWallet-5MNKTR5Z-D-5imDLD.js +1 -0
  252. package/packages/ui/dist/assets/sanko-RHQYXGM5-OX010CbN.js +1 -0
  253. package/packages/ui/dist/assets/scan-4UYSQ56Q-CjMz6-XC.js +1 -0
  254. package/packages/ui/dist/assets/scroll-5OBGQVOV-DJFECiai.js +1 -0
  255. package/packages/ui/dist/assets/search-HYl7NO8x.js +8 -0
  256. package/packages/ui/dist/assets/secp256k1-Cxd6_SiH.js +1 -0
  257. package/packages/ui/dist/assets/send-CJU8CUAo.js +15 -0
  258. package/packages/ui/dist/assets/sign-A7IJEUT5-CGsRnPrd.js +1 -0
  259. package/packages/ui/dist/assets/superposition-HG6MMR2Y-bRkgatRO.js +1 -0
  260. package/packages/ui/dist/assets/swapHorizontal-IMUKiUre.js +8 -0
  261. package/packages/ui/dist/assets/swapHorizontalBold-CNYnNJ9-.js +8 -0
  262. package/packages/ui/dist/assets/swapHorizontalMedium-B9VxEYsT.js +16 -0
  263. package/packages/ui/dist/assets/swapHorizontalRoundedBold-Dz33l_Jh.js +8 -0
  264. package/packages/ui/dist/assets/swapVertical-CHUmjVJ0.js +8 -0
  265. package/packages/ui/dist/assets/telegram-kl9S2mbU.js +16 -0
  266. package/packages/ui/dist/assets/th_TH-4YB4VSB2-BUipNP-V.js +1519 -0
  267. package/packages/ui/dist/assets/three-dots-U5lhA1Am.js +5 -0
  268. package/packages/ui/dist/assets/tr_TR-5FKHPPIO-D5jTpIm9.js +1519 -0
  269. package/packages/ui/dist/assets/twitch-KTEUWXEp.js +18 -0
  270. package/packages/ui/dist/assets/twitterIcon-BHiq8mRg.js +6 -0
  271. package/packages/ui/dist/assets/uk_UA-ZD4IBC52-DgnQrpzl.js +1519 -0
  272. package/packages/ui/dist/assets/unichain-C5BWO2ZY-BfguYsnu.js +1 -0
  273. package/packages/ui/dist/assets/verify-CfN-BXNd.js +8 -0
  274. package/packages/ui/dist/assets/verify-filled-DwZccetj.js +8 -0
  275. package/packages/ui/dist/assets/vi_VN-5EVRZKLY-x078672g.js +1519 -0
  276. package/packages/ui/dist/assets/w3m-modal-CS-PFqPE.js +642 -0
  277. package/packages/ui/dist/assets/wallet-DVlGkhOY.js +8 -0
  278. package/packages/ui/dist/assets/wallet-placeholder-CvR_iEWX.js +14 -0
  279. package/packages/ui/dist/assets/walletConnectWallet-YHWKVTDY-D3lyiczV.js +1 -0
  280. package/packages/ui/dist/assets/walletconnect-8pZBDvVI.js +30 -0
  281. package/packages/ui/dist/assets/warning-circle-ylLEE0Yp.js +12 -0
  282. package/packages/ui/dist/assets/x-C_TBsTMj.js +12 -0
  283. package/packages/ui/dist/assets/xdc-KJ3TDBYO-DNV6zchh.js +1 -0
  284. package/packages/ui/dist/assets/zetachain-TLDS5IPW-Udhyw16T.js +1 -0
  285. package/packages/ui/dist/assets/zh_CN-4XK5YJPR-Bt6Yz5Ek.js +1519 -0
  286. package/packages/ui/dist/assets/zh_HK-N4YN2WSI-Cvzl1V16.js +1519 -0
  287. package/packages/ui/dist/assets/zh_TW-CNCRXH6Z-BNelatfN.js +1519 -0
  288. package/packages/ui/dist/assets/zksync-DH7HK5U4-Dt4usFw6.js +1 -0
  289. package/packages/ui/dist/assets/zora-FYL5H3IO-iB4wygST.js +1 -0
  290. package/packages/ui/dist/index.html +14 -0
  291. package/scripts/check-docs.mjs +262 -0
  292. package/scripts/check-init.mjs +109 -0
  293. package/scripts/postinstall.js +366 -0
  294. package/templates/custom-mandate/.sail/contracts/interfaces/IPermission.sol +18 -0
  295. package/templates/custom-mandate/README.md +85 -0
  296. package/templates/custom-mandate/foundry.toml +8 -0
  297. package/templates/custom-mandate/mandates/BoundedCallPermission.sol +35 -0
  298. package/templates/custom-mandate/mandates/README.md +16 -0
  299. package/templates/dca-rebalancer/.cursor/rules +25 -0
  300. package/templates/dca-rebalancer/.env.example +6 -0
  301. package/templates/dca-rebalancer/.github/workflows/agent-tick.yml +32 -0
  302. package/templates/dca-rebalancer/.sail/.gitkeep +0 -0
  303. package/templates/dca-rebalancer/.sail/README.md +13 -0
  304. package/templates/dca-rebalancer/.sail/config.json +10 -0
  305. package/templates/dca-rebalancer/AGENTS.md +246 -0
  306. package/templates/dca-rebalancer/AGENT_PLAYBOOK.md +110 -0
  307. package/templates/dca-rebalancer/CLAUDE.md +2 -0
  308. package/templates/dca-rebalancer/README.md +16 -0
  309. package/templates/dca-rebalancer/_gitignore +13 -0
  310. package/templates/dca-rebalancer/docs/PERMISSION_MODEL.md +93 -0
  311. package/templates/dca-rebalancer/package.json +17 -0
  312. package/templates/dca-rebalancer/src/agent.ts +253 -0
  313. package/templates/dca-rebalancer/src/config.ts +27 -0
  314. package/templates/dca-rebalancer/src/mandate.ts +67 -0
  315. package/templates/dca-rebalancer/tsconfig.json +8 -0
  316. package/templates/dca-rebalancer/ui/README.md +3 -0
  317. package/templates/lifi-permissions/LifiBoundedApprovePermissionCloneable.sol +84 -0
  318. package/templates/lifi-permissions/LifiDiamondSwapPermissionCloneable.sol +97 -0
  319. package/templates/lifi-permissions/README.md +53 -0
@@ -0,0 +1,253 @@
1
+ /**
2
+ * DCA-rebalancer agent — Base mainnet, selective SailKernel.
3
+ *
4
+ * Strategy: on each tick, if the SMA holds enough USDC, swap a fixed amount
5
+ * into WETH via Uniswap V3 SwapRouter02.
6
+ *
7
+ * Slippage protection: QuoterV2 is called off-chain before each swap.
8
+ * amountOutMinimum = expectedOut × (1 − SLIPPAGE_BPS / 10 000)
9
+ * If QuoterV2 is unavailable or returns 0, the agent skips the tick entirely
10
+ * (fail closed — never submits with amountOutMinimum = 0).
11
+ *
12
+ * Selective kernel: the runner supports dispatchBatch, but this agent returns at
13
+ * most ONE dispatch per tick for simplicity:
14
+ * - An approve, if the router allowance is insufficient.
15
+ * - A swap, if allowance is sufficient and a valid quote is available.
16
+ * Next tick handles the other step.
17
+ *
18
+ * The agent does NOT call dispatch.single() itself — it returns intent objects
19
+ * ({calls, txHash:'0x', ...}) and the runner submits them.
20
+ *
21
+ * PERMISSION ROUTING (default — probe path):
22
+ * This template returns plain Dispatch objects with no `permission` field. The
23
+ * runner automatically probes each registered permission via off-chain evaluate()
24
+ * and routes each call to the first permission that accepts it. This is the
25
+ * recommended default: zero agent-side knowledge of permission addresses required.
26
+ *
27
+ * OPTIONAL OVERRIDE (skip probe for a known permission):
28
+ * If the agent knows exactly which permission governs a call, it can set the
29
+ * optional `permission` field on the returned Dispatch to skip the probe:
30
+ *
31
+ * import type { Address } from "viem";
32
+ * const MY_SWAP_PERMISSION = "0x..." as Address;
33
+ * return [{ ...dispatch, permission: MY_SWAP_PERMISSION }];
34
+ *
35
+ * This is an optimisation only — the probe path is equally correct.
36
+ */
37
+
38
+ import type { Agent, AgentContext, Call, Dispatch } from "@sail/sdk";
39
+ import { encodeFunctionData, type PublicClient } from "viem";
40
+ import {
41
+ ALLOWED_TOKENS,
42
+ MIN_USDC_TO_SWAP,
43
+ QUOTER_V2,
44
+ REBALANCE_THRESHOLD,
45
+ SLIPPAGE_BPS,
46
+ SWAP_AMOUNT_USDC,
47
+ SWAP_FEE_TIER,
48
+ SWAP_ROUTER,
49
+ } from "./mandate.js";
50
+
51
+ // ── ABI fragments ─────────────────────────────────────────────────────────────
52
+
53
+ const ERC20_ABI = [
54
+ {
55
+ name: "allowance",
56
+ type: "function",
57
+ stateMutability: "view",
58
+ inputs: [
59
+ { name: "owner", type: "address" },
60
+ { name: "spender", type: "address" },
61
+ ],
62
+ outputs: [{ type: "uint256" }],
63
+ },
64
+ {
65
+ name: "approve",
66
+ type: "function",
67
+ stateMutability: "nonpayable",
68
+ inputs: [
69
+ { name: "spender", type: "address" },
70
+ { name: "amount", type: "uint256" },
71
+ ],
72
+ outputs: [{ type: "bool" }],
73
+ },
74
+ ] as const;
75
+
76
+ // Uniswap V3 QuoterV2 — quoteExactInputSingle (struct-params variant).
77
+ // Called via eth_call (publicClient.simulateContract) since the function
78
+ // is marked nonpayable but is safe to simulate as a read.
79
+ const QUOTER_V2_ABI = [
80
+ {
81
+ name: "quoteExactInputSingle",
82
+ type: "function",
83
+ stateMutability: "nonpayable",
84
+ inputs: [
85
+ {
86
+ name: "params",
87
+ type: "tuple",
88
+ components: [
89
+ { name: "tokenIn", type: "address" },
90
+ { name: "tokenOut", type: "address" },
91
+ { name: "amountIn", type: "uint256" },
92
+ { name: "fee", type: "uint24" },
93
+ { name: "sqrtPriceLimitX96", type: "uint160" },
94
+ ],
95
+ },
96
+ ],
97
+ outputs: [
98
+ { name: "amountOut", type: "uint256" },
99
+ { name: "sqrtPriceX96After", type: "uint160" },
100
+ { name: "initializedTicksCrossed", type: "uint32" },
101
+ { name: "gasEstimate", type: "uint256" },
102
+ ],
103
+ },
104
+ ] as const;
105
+
106
+ const SWAP_ROUTER_ABI = [
107
+ {
108
+ name: "exactInputSingle",
109
+ type: "function",
110
+ stateMutability: "payable",
111
+ inputs: [
112
+ {
113
+ name: "params",
114
+ type: "tuple",
115
+ components: [
116
+ { name: "tokenIn", type: "address" },
117
+ { name: "tokenOut", type: "address" },
118
+ { name: "fee", type: "uint24" },
119
+ { name: "recipient", type: "address" },
120
+ { name: "amountIn", type: "uint256" },
121
+ { name: "amountOutMinimum", type: "uint256" },
122
+ { name: "sqrtPriceLimitX96", type: "uint160" },
123
+ ],
124
+ },
125
+ ],
126
+ outputs: [{ name: "amountOut", type: "uint256" }],
127
+ },
128
+ ] as const;
129
+
130
+ // ── Intent builder ────────────────────────────────────────────────────────────
131
+
132
+ /** Wrap a single EVM call as a Dispatch intent (no txHash yet — runner submits). */
133
+ function intent(call: Call): Dispatch {
134
+ return { txHash: "0x", calls: [call], success: false, gasUsed: 0n };
135
+ }
136
+
137
+ // ── Agent ─────────────────────────────────────────────────────────────────────
138
+
139
+ export const agent: Agent = {
140
+ name: "dca-rebalancer",
141
+ description:
142
+ `DCA into WETH with USDC on Base via Uniswap V3. ` +
143
+ `Rebalances when allocation drift exceeds ${REBALANCE_THRESHOLD * 100}%. ` +
144
+ `Slippage tolerance: ${SLIPPAGE_BPS / 100}%.`,
145
+
146
+ async tick(ctx: AgentContext): Promise<Dispatch[]> {
147
+ const { safe } = ctx;
148
+
149
+ ctx.log(`tick — block ${ctx.blockNumber}, sma ${safe}`);
150
+
151
+ // publicClient is injected by the runner via ctx.data._publicClient
152
+ // so the agent can make arbitrary on-chain reads (allowance, QuoterV2).
153
+ const pc = ctx.data._publicClient as PublicClient | undefined;
154
+ if (!pc) {
155
+ ctx.log("no publicClient in ctx.data — skipping tick");
156
+ return [];
157
+ }
158
+
159
+ const usdc = ALLOWED_TOKENS[0]!;
160
+ const weth = ALLOWED_TOKENS[1]!;
161
+
162
+ // ── Step 1: Check USDC balance ────────────────────────────────────────────
163
+ const usdcBalance = await ctx.read.balance(usdc);
164
+ ctx.log(`USDC balance: ${usdcBalance} (min to swap: ${MIN_USDC_TO_SWAP})`);
165
+
166
+ if (usdcBalance < MIN_USDC_TO_SWAP) {
167
+ ctx.log("USDC balance below minimum — skipping tick");
168
+ return [];
169
+ }
170
+
171
+ // ── Step 2: Check allowance — approve first if needed ─────────────────────
172
+ const allowance = await pc.readContract({
173
+ address: usdc,
174
+ abi: ERC20_ABI,
175
+ functionName: "allowance",
176
+ args: [safe, SWAP_ROUTER],
177
+ });
178
+
179
+ if (allowance < SWAP_AMOUNT_USDC) {
180
+ ctx.log(`allowance (${allowance}) < swap amount (${SWAP_AMOUNT_USDC}) — submitting approve`);
181
+ // Approve max uint256 once so subsequent ticks skip this step.
182
+ const approveCall: Call = {
183
+ target: usdc,
184
+ value: 0n,
185
+ data: encodeFunctionData({
186
+ abi: ERC20_ABI,
187
+ functionName: "approve",
188
+ args: [SWAP_ROUTER, 2n ** 256n - 1n],
189
+ }),
190
+ };
191
+ return [intent(approveCall)];
192
+ }
193
+
194
+ // ── Step 3: Quote via QuoterV2 — fail closed ──────────────────────────────
195
+ let expectedOut: bigint;
196
+ try {
197
+ const result = await pc.simulateContract({
198
+ address: QUOTER_V2,
199
+ abi: QUOTER_V2_ABI,
200
+ functionName: "quoteExactInputSingle",
201
+ args: [
202
+ {
203
+ tokenIn: usdc,
204
+ tokenOut: weth,
205
+ amountIn: SWAP_AMOUNT_USDC,
206
+ fee: SWAP_FEE_TIER,
207
+ sqrtPriceLimitX96: 0n,
208
+ },
209
+ ],
210
+ });
211
+ expectedOut = (result.result as [bigint, bigint, number, bigint])[0];
212
+ } catch (e) {
213
+ ctx.log(`QuoterV2 unavailable: ${(e as Error).message.slice(0, 100)} — skipping tick (fail closed)`);
214
+ return [];
215
+ }
216
+
217
+ if (expectedOut === 0n) {
218
+ ctx.log("QuoterV2 returned 0 expected output — skipping tick (fail closed)");
219
+ return [];
220
+ }
221
+
222
+ // ── Step 4: Compute amountOutMinimum with slippage ────────────────────────
223
+ const minOut = (expectedOut * BigInt(10_000 - SLIPPAGE_BPS)) / 10_000n;
224
+ ctx.log(
225
+ `quote: ${expectedOut} wei WETH, minOut (${SLIPPAGE_BPS / 100}% slippage): ${minOut}`,
226
+ );
227
+
228
+ // ── Step 5: Encode swap call ──────────────────────────────────────────────
229
+ const swapCall: Call = {
230
+ // Uniswap V3 SwapRouter02 on Base
231
+ target: SWAP_ROUTER,
232
+ value: 0n,
233
+ data: encodeFunctionData({
234
+ abi: SWAP_ROUTER_ABI,
235
+ functionName: "exactInputSingle",
236
+ args: [
237
+ {
238
+ tokenIn: usdc,
239
+ tokenOut: weth,
240
+ fee: SWAP_FEE_TIER,
241
+ recipient: safe, // output stays in the SMA
242
+ amountIn: SWAP_AMOUNT_USDC,
243
+ amountOutMinimum: minOut, // slippage-protected — never 0
244
+ sqrtPriceLimitX96: 0n,
245
+ },
246
+ ],
247
+ }),
248
+ };
249
+
250
+ ctx.log(`submitting swap: ${SWAP_AMOUNT_USDC} USDC → WETH, minOut=${minOut}`);
251
+ return [intent(swapCall)];
252
+ },
253
+ };
@@ -0,0 +1,27 @@
1
+ import { SailorClient } from "@sail/sdk";
2
+
3
+ /** Reads RPC_URL and CHAIN_ID from environment (set via .sail/.env.local or GitHub Secrets). */
4
+ export function getEnvConfig(): { rpcUrl: string; chainId: number } {
5
+ const rpcUrl = process.env["RPC_URL"];
6
+ if (!rpcUrl) {
7
+ throw new Error(
8
+ "RPC_URL is not set.\n" +
9
+ "Run the Sailor setup guide (open this folder in your LLM tool and say 'start') or\n" +
10
+ "add RPC_URL to .sail/.env.local manually.",
11
+ );
12
+ }
13
+
14
+ const chainId = Number(process.env["CHAIN_ID"] ?? "8453"); // Default: Base mainnet
15
+ if (Number.isNaN(chainId)) {
16
+ throw new Error(`Invalid CHAIN_ID: ${process.env["CHAIN_ID"]}`);
17
+ }
18
+
19
+ return { rpcUrl, chainId };
20
+ }
21
+
22
+ /** Builds a SailorClient from environment config. */
23
+ export function createClient(): SailorClient {
24
+ const { rpcUrl, chainId } = getEnvConfig();
25
+ // SailorClient constructor is not implemented yet — this is illustrative.
26
+ return new SailorClient({ rpcUrl, chainId });
27
+ }
@@ -0,0 +1,67 @@
1
+ import type { Address } from "@sail/sdk";
2
+
3
+ // ── Token addresses (Base mainnet) ────────────────────────────────────────────
4
+
5
+ /**
6
+ * Tokens in the DCA basket.
7
+ * ALLOWED_TOKENS[0] = USDC (input — what the agent spends)
8
+ * ALLOWED_TOKENS[1] = WETH (output — what the agent accumulates)
9
+ */
10
+ export const ALLOWED_TOKENS: Address[] = [
11
+ "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base (6 decimals)
12
+ "0x4200000000000000000000000000000000000006", // WETH on Base (18 decimals)
13
+ ];
14
+
15
+ // ── Swap parameters ───────────────────────────────────────────────────────────
16
+
17
+ /**
18
+ * Amount of USDC to spend per swap (in USDC base units, 6 decimals).
19
+ * Default: 5 USDC. Adjust before deploying to production.
20
+ */
21
+ export const SWAP_AMOUNT_USDC = 5_000_000n; // 5 USDC
22
+
23
+ /**
24
+ * Minimum USDC balance the SMA must hold before a swap is attempted.
25
+ * Must be ≥ SWAP_AMOUNT_USDC. Adds a safety margin so a single swap
26
+ * doesn't drain the account to zero.
27
+ */
28
+ export const MIN_USDC_TO_SWAP = 6_000_000n; // 6 USDC
29
+
30
+ /**
31
+ * Slippage tolerance in basis points (100 = 1%).
32
+ * amountOutMinimum = quote × (1 − SLIPPAGE_BPS / 10 000).
33
+ * If no quote is available, the agent skips the swap entirely (fail closed).
34
+ *
35
+ * Tighten for large trades or illiquid pairs; loosen if valid swaps are
36
+ * frequently denied by price impact. Default 1% is conservative for
37
+ * USDC/WETH on Base.
38
+ */
39
+ export const SLIPPAGE_BPS = 100; // 1%
40
+
41
+ /**
42
+ * Uniswap V3 pool fee tier for the USDC/WETH pool on Base.
43
+ * 500 = 0.05% — the most liquid USDC/WETH pool on Base mainnet.
44
+ */
45
+ export const SWAP_FEE_TIER = 500;
46
+
47
+ // ── Rebalancing ───────────────────────────────────────────────────────────────
48
+
49
+ /** Rebalance when allocation drift exceeds this fraction (0.05 = 5%). */
50
+ export const REBALANCE_THRESHOLD = 0.05;
51
+
52
+ // ── Contract addresses (Base mainnet) ─────────────────────────────────────────
53
+
54
+ /** Uniswap SwapRouter02 on Base. Target for exactInputSingle swaps. */
55
+ export const SWAP_ROUTER: Address = "0x2626664c2603336E57B271c5C0b26F421741e481";
56
+
57
+ /**
58
+ * Uniswap V3 QuoterV2 on Base.
59
+ * Called off-chain (via eth_call) to obtain the expected output amount
60
+ * before computing amountOutMinimum. If this call fails, the agent skips
61
+ * the swap — it never submits with amountOutMinimum = 0.
62
+ *
63
+ * Note: amountOutMinimum is set by the agent from the QuoterV2 result.
64
+ * For defense-in-depth, add an on-chain minimum check in your permission
65
+ * contract so the kernel also validates the minimum out requirement.
66
+ */
67
+ export const QUOTER_V2: Address = "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a";
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "noEmit": true
6
+ },
7
+ "include": ["src"]
8
+ }
@@ -0,0 +1,3 @@
1
+ # UI
2
+
3
+ Vite + React UI lands in the next prompt.
@@ -0,0 +1,84 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.26;
3
+
4
+ import {IPermission, Context} from "../../.sail/contracts/interfaces/IPermission.sol";
5
+ import {CloneInitializable} from "../../.sail/contracts/templates/base/CloneInitializable.sol";
6
+
7
+ /// @title LifiBoundedApprovePermissionCloneable
8
+ /// @notice EIP-1167 clone-template approval permission with PER-TOKEN caps. The
9
+ /// logic contract is deployed once and registered in the SDK's
10
+ /// standaloneTemplates; each account clones it via
11
+ /// PermissionFactory.deployAndAttach and configures via initialize().
12
+ ///
13
+ /// The manager may ONLY approve the LiFi Diamond, and only on tokens that
14
+ /// have a configured cap, up to that token's cap. Passes through any
15
+ /// non-approve call (conjunctive model).
16
+ ///
17
+ /// Caps are PER TOKEN (not one global cap) because token value and decimals
18
+ /// differ — e.g. 1 DAI = 1e18 base units vs 1 USDC = 1e6. A single cap can't
19
+ /// bound both sensibly.
20
+ contract LifiBoundedApprovePermissionCloneable is IPermission, CloneInitializable {
21
+ bytes4 private constant APPROVE = 0x095ea7b3;
22
+ address public constant LIFI_DIAMOND = 0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE;
23
+
24
+ // Per-token approve cap, in the token's base units. 0 = token not allowed.
25
+ // A mapping occupies its own slot pointer and does not pack with the
26
+ // CloneInitializable `_initialized` bool at slot 0.
27
+ mapping(address token => uint256 cap) public maxApprovePerToken;
28
+ address public permissionSigner;
29
+
30
+ error NotPermissionSigner();
31
+ error ZeroAddress();
32
+ error LengthMismatch();
33
+
34
+ modifier onlyPermissionSigner() {
35
+ if (msg.sender != permissionSigner) revert NotPermissionSigner();
36
+ _;
37
+ }
38
+
39
+ /// @dev Lock the logic contract; only clones (fresh storage) can be initialized.
40
+ constructor() {
41
+ _disableInitializers();
42
+ }
43
+
44
+ /// @notice One-time per-clone configuration.
45
+ /// @param tokens Tokens the manager may approve to the LiFi Diamond.
46
+ /// @param caps Per-token cap (token base units); index-aligned with `tokens`.
47
+ /// @param _permissionSigner Owner wallet; sole authority for post-init updates.
48
+ function initialize(
49
+ address[] memory tokens,
50
+ uint256[] memory caps,
51
+ address _permissionSigner
52
+ ) external initializer {
53
+ if (_permissionSigner == address(0)) revert ZeroAddress();
54
+ if (tokens.length != caps.length) revert LengthMismatch();
55
+ permissionSigner = _permissionSigner;
56
+ for (uint256 i; i < tokens.length; i++) {
57
+ maxApprovePerToken[tokens[i]] = caps[i];
58
+ }
59
+ }
60
+
61
+ /// @notice Set (cap > 0) or clear (cap == 0) a token's per-tx approve cap.
62
+ function setTokenCap(address token, uint256 cap) external onlyPermissionSigner {
63
+ maxApprovePerToken[token] = cap;
64
+ }
65
+
66
+ function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
67
+ // Pass through calls outside this permission's domain (conjunctive model).
68
+ if (ctx.selector != APPROVE) return true;
69
+ if (ctx.target == address(0)) return false; // token is ctx.target
70
+ if (txData.length < 68) return false;
71
+
72
+ (address spender, uint256 amount) = abi.decode(txData[4:], (address, uint256));
73
+ if (spender != LIFI_DIAMOND) return false;
74
+
75
+ uint256 cap = maxApprovePerToken[ctx.target];
76
+ if (cap == 0) return false; // token not allowed
77
+ if (amount > cap) return false; // over the per-token cap
78
+ return true;
79
+ }
80
+
81
+ function discriminator() external pure returns (bytes32) {
82
+ return keccak256("LifiBoundedApprovePermissionCloneable.v1");
83
+ }
84
+ }
@@ -0,0 +1,97 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.26;
3
+
4
+ import {IPermission, Context} from "../../.sail/contracts/interfaces/IPermission.sol";
5
+ import {CloneInitializable} from "../../.sail/contracts/templates/base/CloneInitializable.sol";
6
+
7
+ /// @title LifiDiamondSwapPermissionCloneable
8
+ /// @notice EIP-1167 clone-template version of LifiDiamondSwapPermission. The logic
9
+ /// contract is deployed once and registered in the SDK's standaloneTemplates;
10
+ /// each account gets its own clone via PermissionFactory.deployAndAttach,
11
+ /// configured through initialize() (NOT the constructor).
12
+ ///
13
+ /// Restricts manager-initiated swaps to the official LiFi Diamond on Base:
14
+ /// - target must be the LiFi Diamond,
15
+ /// - selector must be allowlisted,
16
+ /// - receiver embedded in the calldata must equal ctx.account (the SMA),
17
+ /// - the minAmount field must not exceed the configured cap.
18
+ /// Passes through any call whose target is not the diamond (conjunctive model).
19
+ ///
20
+ /// Calldata layout (validated against live Base quotes):
21
+ /// selector(4) + word0(32) + word1(32) + word2(32) + receiver(32) + minAmount(32)
22
+ /// → receiver at offset 100, minAmount at offset 132.
23
+ contract LifiDiamondSwapPermissionCloneable is IPermission, CloneInitializable {
24
+ // Official LiFi Diamond on Base Mainnet.
25
+ address public constant LIFI_DIAMOND = 0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE;
26
+
27
+ // Storage starts after CloneInitializable's `_initialized` bool (slot 0). A
28
+ // mapping occupies its own slot pointer and does not pack with the bool.
29
+ mapping(bytes4 selector => bool) public isAllowedSelector;
30
+ uint256 public maxMinAmountPerTx;
31
+ address public permissionSigner;
32
+
33
+ error NotPermissionSigner();
34
+ error ZeroAddress();
35
+
36
+ modifier onlyPermissionSigner() {
37
+ if (msg.sender != permissionSigner) revert NotPermissionSigner();
38
+ _;
39
+ }
40
+
41
+ /// @dev Lock the logic contract; only clones (fresh storage) can be initialized.
42
+ constructor() {
43
+ _disableInitializers();
44
+ }
45
+
46
+ /// @notice One-time per-clone configuration.
47
+ /// @param allowedSelectors LiFi Diamond selectors to allowlist on init.
48
+ /// @param _maxMinAmountPerTx Cap on the minAmount field (type(uint256).max = uncapped).
49
+ /// @param _permissionSigner Owner wallet; sole authority for post-init updates.
50
+ function initialize(
51
+ bytes4[] memory allowedSelectors,
52
+ uint256 _maxMinAmountPerTx,
53
+ address _permissionSigner
54
+ ) external initializer {
55
+ if (_permissionSigner == address(0)) revert ZeroAddress();
56
+ maxMinAmountPerTx = _maxMinAmountPerTx;
57
+ permissionSigner = _permissionSigner;
58
+ for (uint256 i; i < allowedSelectors.length; i++) {
59
+ isAllowedSelector[allowedSelectors[i]] = true;
60
+ }
61
+ }
62
+
63
+ function setMaxMinAmountPerTx(uint256 newMax) external onlyPermissionSigner {
64
+ maxMinAmountPerTx = newMax;
65
+ }
66
+
67
+ /// @notice Add a LiFi selector. Only after verifying its calldata places
68
+ /// `receiver` at offset 100 and `minAmount` at offset 132.
69
+ function addSelector(bytes4 selector) external onlyPermissionSigner {
70
+ isAllowedSelector[selector] = true;
71
+ }
72
+
73
+ function removeSelector(bytes4 selector) external onlyPermissionSigner {
74
+ isAllowedSelector[selector] = false;
75
+ }
76
+
77
+ uint256 private constant RECEIVER_OFFSET = 100;
78
+ uint256 private constant MIN_DATA_LEN = 164;
79
+
80
+ function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
81
+ // Pass through calls outside this permission's domain (conjunctive model).
82
+ if (ctx.target != LIFI_DIAMOND) return true;
83
+ if (!isAllowedSelector[ctx.selector]) return false;
84
+ if (txData.length < MIN_DATA_LEN) return false;
85
+
86
+ address receiver = abi.decode(txData[RECEIVER_OFFSET:RECEIVER_OFFSET + 32], (address));
87
+ uint256 minAmount = abi.decode(txData[RECEIVER_OFFSET + 32:RECEIVER_OFFSET + 64], (uint256));
88
+
89
+ if (receiver != ctx.account) return false;
90
+ if (minAmount > maxMinAmountPerTx) return false;
91
+ return true;
92
+ }
93
+
94
+ function discriminator() external pure returns (bytes32) {
95
+ return keccak256("LifiDiamondSwapPermissionCloneable.v1");
96
+ }
97
+ }
@@ -0,0 +1,53 @@
1
+ # LiFi clone-permission templates
2
+
3
+ Canonical source (for reference) of the EIP-1167 **clone** permission templates
4
+ used for LiFi-based swaps/DCA. The logic contracts are deployed once per chain and
5
+ registered in the SDK deployment registry
6
+ (`packages/sdk/src/deployments.ts` → `standaloneTemplates` / `cloneTemplates`).
7
+ Each account gets its own clone via `PermissionFactory.deployAndAttach`, configured
8
+ through `initialize()` (never the constructor).
9
+
10
+ These follow the `CloneInitializable` pattern: the constructor calls
11
+ `_disableInitializers()` to permanently lock the logic contract, and a one-time
12
+ `initialize()` (guarded by the `initializer` modifier) configures each clone.
13
+
14
+ > The `import` paths reference `../../.sail/contracts/{interfaces,templates/base}`
15
+ > from the Foundry project they were built in
16
+ > (`tests/base-mainnet-agent-01/`). This folder is **reference source** — sailor has
17
+ > no Foundry build. Build/deploy happens in that project via
18
+ > `scripts/deploy-clone-templates.ts`.
19
+
20
+ > **Note:** The kernels bundled in `@sail/sdk` (Base, Base Sepolia, Arbitrum, Unichain) now all run the **selective** dispatch model — verified on-chain against each kernel's `DISPATCH_TYPEHASH`. These templates were written for the older conjunctive model and include pass-through logic (`return true` for calls outside their domain) that is not required on selective kernels. Review before deploying against a selective kernel; the pass-through logic is harmless but unnecessary.
21
+
22
+ ## Contracts
23
+
24
+ ### LifiDiamondSwapPermissionCloneable → `boundedLiFi`
25
+ Restricts manager swaps to the official LiFi Diamond:
26
+ target == diamond, selector allowlisted, embedded receiver == `ctx.account`,
27
+ `minAmount <= maxMinAmountPerTx`. Passes through any call whose target is not the
28
+ diamond (conjunctive-kernel rule).
29
+
30
+ `initialize(bytes4[] allowedSelectors, uint256 maxMinAmountPerTx, address permissionSigner)`
31
+
32
+ ### LifiBoundedApprovePermissionCloneable → `boundedApprove`
33
+ Approve only the LiFi Diamond, only on tokens with a configured cap, up to that
34
+ cap. **Per-token caps** (`mapping(token => cap)`) because token value/decimals
35
+ differ (1 DAI = 1e18 vs 1 USDC = 1e6). Passes through non-approve calls.
36
+
37
+ `initialize(address[] tokens, uint256[] caps, address permissionSigner)`
38
+
39
+ ## Deployed logic addresses
40
+
41
+ | Template | Chain | Address |
42
+ |---|---|---|
43
+ | boundedLiFi | Base mainnet (8453) | `0xF1abcF774250fD1A8147B56DA07Bf9021064650A` |
44
+ | boundedApprove | Base mainnet (8453) | `0x9c0b86daf9e75d759a5D165aD7366e52b3353fD8` |
45
+
46
+ Both verified `initialized() == true` (logic locked) post-deploy.
47
+
48
+ ## Conjunctive-kernel note
49
+
50
+ Both Base kernels use the **conjunctive** dispatch model: every registered
51
+ permission is evaluated and ALL must return true. So a permission MUST pass through
52
+ calls outside its own domain (return `true`), or it bricks unrelated dispatches.
53
+ Both templates above do this.