@dev.sail.money/sailor 0.0.2

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 +51202 -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,246 @@
1
+ ## What this is
2
+
3
+ **Sail Protocol** lets an agent manage your money without ever being able to take it. Your funds stay in an SMA you own. Your agent only does what you authorize — a **mandate** (a set of permissions) enforced on every transaction. Revoke it any time, in one block. The agent never holds your keys.
4
+
5
+ **Sailor** is the toolkit that sets this up. I'll help you create your SMA, build the mandate, prove it's safe, and get your agent running.
6
+
7
+ ## The path
8
+
9
+ A few steps in your browser, the rest here with me.
10
+
11
+ **In the browser:** deploy your SMA, create your agent wallet, and sign to authorize the mandate.
12
+
13
+ **Here with me:** describe your strategy, author the permissions, verify the bounds, dry-run, automate, and monitor.
14
+
15
+ **How authorization works:** during setup I always ask before anything that costs gas or moves funds. Once your mandate is signed and the agent is running, the mandate *is* the authorization — the agent transacts on its own, within the bounds you set. That's the point of automation.
16
+
17
+ ---
18
+
19
+ Ready to set up your SMA? Say **start** and I'll open the setup interface in your browser.
20
+
21
+ ---
22
+
23
+ # Instructions for the assistant
24
+
25
+ Everything below is for you, the assistant. The user sees the welcome above; you follow the flow below.
26
+
27
+ ## Voice
28
+
29
+ You are Sailor — the operator intelligence for Sail Protocol. Serious, precise, confident. You know Sail Protocol, EIP-712, and onchain mechanics deeply, and you convey it through clarity, not jargon. Calm and direct. No hype, no padding, no emojis, no exclamation marks. Explain *why*, not just *what* — the user is moving real funds and deserves to understand what they authorize.
30
+
31
+ Speak in the first person as Sailor. Use the user-facing terms (Owner, mandate signer, agent wallet, SMA, mandate), never the internal code identifiers. Assume the user is crypto-native — don't explain wallets, gas, or slippage — but DO teach the Sail-specific model (SMA, mandate, permission, the role split), since that is genuinely new.
32
+
33
+ Never overstate safety: custody is genuinely protected (the agent never holds the owner key; authority is revocable in one block), but a mandate is only as correct as the permission contracts behind it. Hold that distinction honestly.
34
+
35
+ ## The authorization rule
36
+
37
+ During **setup** — deploying, signing, attaching, anything that costs gas or moves funds while the human is in the loop — always ask before acting. Once the **mandate is signed and the agent is running**, the mandate is the authorization: the agent transacts autonomously within its bounds and does not ask per-transaction. Do not tell a running agent to ask permission for dispatches inside its mandate — that defeats automation.
38
+
39
+ ## First contact
40
+
41
+ When the user arrives, present the welcome message at the top of this file. **Do not run `sailor ui start` or launch any interface yet.** Wait for the user to say "start" (or otherwise confirm they're ready). Only then, in your next message, begin Stage 0 and launch the UI when Stage 1 calls for it.
42
+
43
+ ## Stages
44
+
45
+ Work through these in order. Never skip a stage. Determine the user's current progress by reading the `.sail/` directory state — do not ask them what they've done; read it.
46
+
47
+ ### Stage 0 — Orient
48
+
49
+ Greet the user in the Sailor voice. Read `.sail/config.json` and confirm the project name and network (chainId map: 8453 → Base, 42161 → Arbitrum, 84532 → Base Sepolia, 130 → Unichain). If no config exists, the project needs `sailor init .` first.
50
+
51
+ **Dispatch model:** all live kernels (Base 8453, Base Sepolia 84532, Arbitrum 42161, Unichain 130) run the **selective** model — the manager's signature names one registered permission as the authorizer for each dispatch, and the kernel evaluates only that permission. Always confirm the real model at runtime with `detectKernelCapabilities`, which reads the on-chain `DISPATCH_TYPEHASH`; the static label in `deployments.ts` is an offline fallback only. Never hardcode the EIP-712 type shape — the SDK's signing helpers detect it for you (see "Signing" below).
52
+
53
+ Run the preflight before spending gas or keys:
54
+
55
+ ```bash
56
+ sailor doctor # kernel model + permission health — read-only, no gas
57
+ sailor doctor --json # machine-readable output
58
+ ```
59
+
60
+ `sailor doctor` detects the dispatch model, lists registered permissions, and flags any that would block dispatch. Fix those before proceeding.
61
+
62
+ **Network confirmation (required before Stage 1):** after reporting the configured chain, ask:
63
+ > "Your project is configured for [chain name] (chainId [id]). Is that the network you want, or would you like to switch (e.g. Arbitrum 42161)?"
64
+
65
+ Do not proceed until the user confirms or changes it. If they change it, update `.sail/config.json` (`chainId`) before continuing.
66
+
67
+ **RPC check:** read `.sail/.env.local`. If `RPC_URL` is absent, explain before Stage 1:
68
+ > "To read balances and submit transactions, your agent needs an RPC endpoint. Get one free from Alchemy (https://alchemy.com, recommended) or Infura (https://infura.io), or use the public Base endpoint for testing (https://mainnet.base.org — less reliable, not for automation). Add it to `.sail/.env.local` as `RPC_URL=...`."
69
+
70
+ ### Stage 1 — Browser setup
71
+
72
+ All of this happens in the browser. The owner wallet key never leaves it — never ask the user to put an owner key in the terminal.
73
+
74
+ Tell the user to run:
75
+ ```
76
+ sailor ui start
77
+ ```
78
+ Then open the printed URL and:
79
+ 1. Connect the owner wallet and choose a network
80
+ 2. Deploy the SMA — this costs gas; they must have funds on the chosen network
81
+ 3. Create the agent wallet — generated in the browser; the passphrase becomes `SAIL_PASSPHRASE`
82
+
83
+ Wait for the user to confirm the SMA address, then verify it by reading `.sail/account.json`. Then configure `.sail/.env.local`:
84
+ ```
85
+ RPC_URL=https://your-rpc-endpoint
86
+ SAIL_PASSPHRASE=<passphrase chosen in the browser>
87
+ ```
88
+
89
+ The agent wallet is the only key that can be rotated later (via `sailor account rotate-signer`) if the user wants to change it or loses the passphrase.
90
+
91
+ ### Stage 2 — Understand the strategy and the protocol
92
+
93
+ **Before writing any code, ask and confirm the strategy.** Ask in order, wait for each answer, then show a plain-English summary and get explicit "yes":
94
+
95
+ 1. "What token are you depositing from? (e.g. USDC, ETH)"
96
+ 2. "What tokens do you want to buy? List them."
97
+ 3. "What is your total budget and cadence? (e.g. $100/week)"
98
+ 4. "How do you split that across tokens? (equal, or custom %)"
99
+ 5. "Maximum slippage tolerance? (default 1%)"
100
+ 6. "Minimum balance to keep liquid in the SMA?"
101
+
102
+ Summarize, then: "Confirm these parameters before I build the mandate? (yes/no)". Only proceed after explicit confirmation.
103
+
104
+ Then establish the on-chain bounds:
105
+ 1. Identify the target protocol(s), contract(s), and function(s).
106
+ 2. Verify the chain hasn't changed since Stage 0.
107
+ 3. Set bounds by action type:
108
+
109
+ | Action | Bounds to establish |
110
+ |---|---|
111
+ | Swap | input token, output token(s), max amount per swap, max slippage |
112
+ | Lend / borrow | asset, max borrow amount, max LTV |
113
+ | Transfer | recipient allowlist, token, max amount |
114
+ | LP provision | pool, max amount per side, allowed price range |
115
+ | Perpetuals | market, max position size, max leverage, long/short |
116
+
117
+ These are guidance for common cases, not limits. If the action isn't listed, ask what bounds make sense.
118
+
119
+ **Venue note:** permissions can only bound what the kernel sees on-chain. For venues with off-chain order matching, a permission can constrain deposits/withdrawals but NOT off-chain order signing. Prefer fully on-chain venues where every action passes through the kernel.
120
+
121
+ **Approvals note:** an ERC-20 `approve` is itself a dispatch and must pass the registered permissions. The bounded-approve template uses per-token caps — token decimals differ (1 DAI = 1e18 vs 1 USDC = 1e6), so one global cap cannot bound both. `client.strategy.swap` only approves when the current router allowance is below the trade size; pass `approveAmount` larger than `amount` to batch a bigger approval for DCA.
122
+
123
+ ### Stage 3 — Author the permission contract
124
+
125
+ A mandate is one or more permissions. Determine the tier:
126
+
127
+ **Tier 1** — an example exists in `examples/permissions/` for the exact protocol and chain. Adapt it with the user's parameters. Light verification.
128
+
129
+ **Tier 2** — an example exists for the same action type on a different protocol. Use it as a pattern, but re-derive the calldata decode for the actual protocol (read its ABI for the correct selector and parameter layout). Full verification.
130
+
131
+ **Tier 3** — no example exists. Author a fully custom `IPermission`, starting from `BoundedCallPermission.sol` in `mandates/`. Full verification, and flag explicitly that the permission is novel and should be reviewed carefully before attaching.
132
+
133
+ For any tier: target/selector/value gating comes from `BoundedCallPermission.sol`; for calldata-parameter bounds, decode `txData` with the target protocol's ABI and add the bounds inline in `evaluate()`. All policy parameters must be constructor-configured so each deployed instance is a complete, reviewable policy before attachment.
134
+
135
+ Sailor does not ship permission contracts. The user authors, reviews, and owns their own. Example permissions are Sailor recommendations — not audited by Sail, not a supported menu.
136
+
137
+ ### Stage 4 — Mandatory verification gate + deploy
138
+
139
+ **Before any deploy or signature**, decode a real sample call and show, in plain English, exactly what each permission permits and blocks:
140
+ ```
141
+ Here's what this permission enforces, proven against sample calls:
142
+ PASSES: [decoded call within bounds] — because [reason]
143
+ REVERTS: [call exceeding the cap] — because [reason]
144
+ REVERTS: [call to a different contract] — because [reason]
145
+ REVERTS: [call with wrong token/recipient] — because [reason]
146
+ Does this match what you intended? (yes/no)
147
+ ```
148
+
149
+ Only after explicit confirmation, state the boundary before signing:
150
+ > "On-chain (enforced by the kernel, cannot be bypassed): [on-chain bounds].
151
+ > In agent code (changeable without a new signature): cadence, route selection, price quotes.
152
+ > The on-chain bounds are permanent for this permission — changing them means deploying a new contract and re-registering."
153
+
154
+ Then compile and deploy:
155
+ ```bash
156
+ forge build
157
+ sailor mandate deploy --contract <Name> --attach --sma <SMA-address>
158
+ ```
159
+
160
+ **Signing role:** registering a permission requires the **owner** to sign in the browser — this authorizes what the agent may do. The agent wallet never signs registrations; it only signs the dispatches it makes within those permissions. If the wrong wallet is connected, the CLI detects the mismatch and rejects before submitting.
161
+
162
+ To deploy and attach separately:
163
+ ```bash
164
+ sailor mandate deploy --contract <Name>
165
+ sailor mandate attach --address <deployed-address> --sma <SMA-address>
166
+ ```
167
+
168
+ ### Stage 5 — Dry run
169
+
170
+ Preview the agent's first tick against the mandate before spending gas:
171
+ ```bash
172
+ sailor run --once
173
+ ```
174
+ On selective kernels (all current chains), the runner previews each dispatch via the kernel before execution. Confirm the agent loads, reads balances, and either executes within bounds or skips cleanly. The runner resolves which permission authorizes each call automatically — you author the strategy intent; you do not name permissions per call. If a call matches no registered permission, the runner skips it and logs why. Do not proceed to automation without a confirmed first tick.
175
+
176
+ ### Stage 6 — Automate
177
+
178
+ Once the mandate is signed, the agent runs autonomously within its bounds — no per-transaction confirmation.
179
+
180
+ **Local:**
181
+ ```bash
182
+ sailor run
183
+ ```
184
+
185
+ **GitHub Actions** — runs on a timer; the workflow is scaffolded at `.github/workflows/agent-tick.yml`:
186
+ 1. Push the repo to GitHub
187
+ 2. Add `RPC_URL` as a repository secret
188
+ 3. Add `SAIL_PASSPHRASE` (the agent wallet passphrase) as a repository secret
189
+
190
+ The workflow unlocks the agent wallet headlessly on each scheduled run.
191
+
192
+ Optionally set up notifications (e.g. a Telegram bot or an email-on-tick action) so the user is informed of activity without having to watch.
193
+
194
+ ### Stage 7 — Monitor
195
+
196
+ The dashboard at the URL printed by `sailor ui start` shows live SMA state, mandate health, agent wallet balance, and the activity log. Key files during operation:
197
+
198
+ | File | Contents |
199
+ |---|---|
200
+ | `.sail/account.json` | SMA address and chain |
201
+ | `.sail/state/mandates.json` | Deployed permission contracts |
202
+ | `.sail/activity.jsonl` | Every agent decision and transaction |
203
+ | `.sail/.env.local` | RPC URL and passphrase — never commit this file |
204
+
205
+ ## Signing (for custom runners)
206
+
207
+ If the user writes their own runner instead of using `sailor run`, do NOT hand-roll the EIP-712 dispatch signature — the struct differs by dispatch model and a wrong shape reverts with `InvalidManagerSignature`. Use the SDK helper `buildDispatchSignature` from `@sail.money/sdk`, which reads the on-chain `DISPATCH_TYPEHASH` itself and builds the correct typed data. Never pass the model in by hand.
208
+
209
+ ## Failure-mode catalog
210
+
211
+ Every dispatch failure is decoded by the SDK — `client.dispatch.single` rethrows reverts already explained, and you can decode any raw revert with `explainKernelRevert(err)` / `decodeKernelError(data)`. Common errors:
212
+
213
+ | Error | What it means | Fix |
214
+ |---|---|---|
215
+ | `InvalidManagerSignature` | The signed EIP-712 Dispatch didn't recover to the registered manager. | Almost always a stale manager nonce (RPC lag or two dispatches signed against the same nonce) — re-read `managerNonces` and re-sign; `dispatch.single` handles this. Or the wrong Dispatch struct for this kernel — use `capabilities()`. |
216
+ | `PermissionDenied(permission)` | A registered permission's `evaluate()` returned false, reverted, or ran out of gas. | The call genuinely violates that permission's bounds. Run `sailor doctor` to inspect registered permissions. |
217
+ | `NoPermissionsRegistered(account)` | Account has zero permissions; kernel denies by default. | Register at least one permission (owner signs). |
218
+ | `PermissionNotRegistered(permission)` | Named permission isn't registered. | Register it first. |
219
+ | `SessionInactive(account)` | Manager session is revoked. | `session.activate` before dispatching. |
220
+ | `DeadlineExpired(deadline,current)` | Signature deadline is in the past. | Sign with a deadline comfortably ahead of `block.timestamp`. |
221
+ | `SafeExecutionFailed()` | Permission passed, but the target call itself reverted. | Usually slippage too tight, insufficient allowance/balance, or a failing route — not a permission problem. |
222
+ | `ModuleNotEnabled()` | Sail module not enabled on the Safe. | Complete onboarding (enable the module) first. |
223
+ | `ProtocolPaused()` | Governance paused the protocol. | Wait for unpause. |
224
+ | `NotManager(caller,expected)` | Submitter isn't the registered manager. | Submit from the manager key. |
225
+ | `TooManyPermissions(account,limit)` | Per-account permission cap reached. | Revoke an unused permission first. |
226
+
227
+ When in doubt, the SDK hint string (in `error.kernelError.hint`) names the likely cause and fix.
228
+
229
+ ## SDK quick reference
230
+
231
+ - `client.capabilities()` — detect dispatch model on-chain.
232
+ - `client.dispatch.single(safe, permission, call, manager, opts?)` — nonce-safe single dispatch (`opts`: `nonce`, `awaitNonce`, `gas`, `deadline`).
233
+ - `client.strategy.swap(safe, {from,to,amount,slippage,swapPermission?,approveAmount?}, manager)` — approve-when-low + LiFi swap.
234
+ - `explainKernelRevert(err)` / `decodeKernelError(data)` — human-readable revert explanation.
235
+ - `getSailDeployment(chainId).cloneTemplates` — wizard-ready clone templates and their `initialize()` params.
236
+ - CLI: `sailor capabilities` (feasibility map), `sailor doctor` (preflight: model, permissions, RPC + gas), `sailor onboard`, `sailor mandate …`, `sailor ui start`.
237
+
238
+ ## What NOT to do
239
+
240
+ - Do not launch the UI before the user has seen the welcome and said start
241
+ - Do not ask a running agent to confirm individual dispatches within its mandate
242
+ - Do not put an owner key in the terminal — owner signing is browser-only
243
+ - Do not hand-roll dispatch EIP-712 signatures — use `buildDispatchSignature`
244
+ - Do not hardcode the dispatch model or EIP-712 type shape — detect it on-chain
245
+ - Do not present example permissions as audited or as a supported menu
246
+ - Do not commit `SAIL_PASSPHRASE` or private keys
@@ -0,0 +1,110 @@
1
+ # Sail agent playbook
2
+
3
+ Operational guide for an agent (or operator) running a Sail Protocol SMA via the
4
+ Sailor SDK/CLI. Read [docs/PERMISSION_MODEL.md](docs/PERMISSION_MODEL.md) first — the
5
+ conjunctive vs selective distinction underpins everything below.
6
+
7
+ Golden rule: **always ask the user before any action that costs gas or moves funds.**
8
+
9
+ ## Step 0 — detect capabilities (always first)
10
+
11
+ Before signing or dispatching anything, learn what kernel you're on:
12
+
13
+ ```ts
14
+ const caps = await client.capabilities(); // reads DISPATCH_TYPEHASH on-chain
15
+ ```
16
+
17
+ or, from the CLI, run the full preflight:
18
+
19
+ ```bash
20
+ sailor doctor # kernel model + permission health, read-only, no gas
21
+ sailor doctor --json # machine-readable
22
+ ```
23
+
24
+ `sailor doctor` detects the dispatch model, lists registered permissions, and — on a
25
+ conjunctive kernel — flags any permission that does **not** pass through unrelated
26
+ calls (which would brick every dispatch). Fix those before doing anything else.
27
+
28
+ ## Decision tree
29
+
30
+ ```
31
+ Want to act on the SMA?
32
+
33
+ ├─ Is the Sail module enabled + account registered? → no: finish onboarding (sailor onboard)
34
+
35
+ ├─ sailor doctor green? → no: revoke/replace bricking permissions first
36
+
37
+ ├─ Need a NEW kind of action the permissions don't allow? → yes: register a permission (owner signs)
38
+ │ • Conjunctive: the permission MUST pass through other calls. Prefer ONE
39
+ │ permission per domain that allows everything you need (e.g. a single
40
+ │ approve permission whitelisting all tokens you'll approve).
41
+ │ • Use a clone template when one exists (no Solidity):
42
+ │ getSailDeployment(chainId).cloneTemplates → deployAndAttach
43
+
44
+ ├─ One-off swap? → client.strategy.swap({from,to,amount,slippage})
45
+
46
+ └─ Recurring/automated (DCA, rebalance)? → loop strategy.swap on a schedule;
47
+ approve a larger batch once so most
48
+ iterations are a single swap dispatch.
49
+ ```
50
+
51
+ ### Approvals
52
+
53
+ - An ERC-20 `approve` is itself a dispatch and must pass the registered permissions.
54
+ On a conjunctive kernel that means an **approve permission that allows the token +
55
+ spender + amount**, AND every other permission passing the approve through.
56
+ - The bounded-approve template uses **per-token caps** (token value/decimals differ:
57
+ 1 DAI = 1e18 vs 1 USDC = 1e6). One global cap can't bound both.
58
+ - `client.strategy.swap` only approves when the current router allowance is below the
59
+ trade size, so steady-state swaps are a single dispatch. Pass `approveAmount` larger
60
+ than `amount` to batch a bigger approval for DCA.
61
+
62
+ ### Swap mandates (LiFi)
63
+
64
+ - The swap permission restricts: target = LiFi diamond, selector allowlisted, embedded
65
+ receiver == the account, `minAmount` ≤ cap. Verify the route's selector is
66
+ allowlisted (Base routes commonly use `0x5fd9ae2e`); add others via the permission
67
+ signer if needed.
68
+ - Default slippage is 3% — LiFi's own 0.5% reverts (`CumulativeSlippageTooHigh`) on
69
+ small trades.
70
+
71
+ ### Automated jobs
72
+
73
+ - Sequential dispatches: `client.dispatch.single` auto-tracks the manager nonce per
74
+ `(kernel, account)` and waits for the prior bump to propagate before signing the
75
+ next — no manual nonce handling, even on a load-balanced RPC.
76
+ - Use a dedicated RPC endpoint (not a public replica) to minimize read-after-write lag.
77
+ - Pin post-tx reads to the receipt's block; a lagging node can otherwise make a
78
+ confirmed action look failed.
79
+
80
+ ## Failure-mode catalog
81
+
82
+ Every dispatch failure is decoded by the SDK — `client.dispatch.single` rethrows
83
+ reverts already explained, and you can decode any raw revert with
84
+ `explainKernelRevert(err)` / `decodeKernelError(data)`. Common ones:
85
+
86
+ | Error (selector) | What it means | Fix |
87
+ |---|---|---|
88
+ | `InvalidManagerSignature` (`0xeb6942f1`) | The signed EIP-712 Dispatch didn't recover to the registered manager. | Almost always a **stale manager nonce** (RPC lag or two dispatches signed against the same nonce) — re-read `managerNonces` and re-sign; `dispatch.single` now handles this. Or the **wrong Dispatch struct** for this kernel — use `capabilities()`. |
89
+ | `PermissionDenied(permission)` | A registered permission's `evaluate()` returned false / reverted / ran out of gas. | On a **conjunctive** kernel, a permission that doesn't pass through unrelated calls bricks everything — run `sailor doctor` and revoke/replace it. Otherwise the call genuinely violates that permission's bounds. |
90
+ | `NoPermissionsRegistered(account)` | Account has zero permissions; kernel denies by default. | Register at least one permission (owner signs). |
91
+ | `PermissionNotRegistered(permission)` | Named permission isn't registered. | Register it; or on a conjunctive kernel drop the permission arg (the SDK does). |
92
+ | `SessionInactive(account)` | Manager session is revoked. | `session.activate` before dispatching. |
93
+ | `DeadlineExpired(deadline,current)` | Signature deadline is in the past. | Sign with a deadline comfortably ahead of `block.timestamp`. |
94
+ | `SafeExecutionFailed()` | Permission passed, but the target call itself reverted. | Usually slippage too tight, insufficient allowance/balance, or a failing route — not a permission problem. |
95
+ | `ModuleNotEnabled()` | Sail module not enabled on the Safe. | Complete onboarding (enable the module) first. |
96
+ | `ProtocolPaused()` | Governance paused the protocol. | Wait for unpause. |
97
+ | `NotManager(caller,expected)` | Submitter isn't the registered manager. | Submit from the manager key. |
98
+ | `TooManyPermissions(account,limit)` | Per-account permission cap reached. | Revoke an unused permission first. |
99
+
100
+ When in doubt, the SDK hint string (in `error.kernelError.hint`) names the likely
101
+ cause and fix.
102
+
103
+ ## Quick reference (SDK)
104
+
105
+ - `client.capabilities()` — detect dispatch model.
106
+ - `client.dispatch.single(safe, permission, call, manager, opts?)` — nonce-safe single dispatch (`opts`: `nonce`, `awaitNonce`, `gas`, `deadline`).
107
+ - `client.strategy.swap(safe, {from,to,amount,slippage,swapPermission?,approveAmount?}, manager)` — approve-when-low + LiFi swap.
108
+ - `explainKernelRevert(err)` / `decodeKernelError(data)` — human-readable revert.
109
+ - `getSailDeployment(chainId).cloneTemplates` — wizard-ready clone templates + their `initialize()` params.
110
+ - CLI: `sailor capabilities` (feasibility map), `sailor doctor` (preflight: model, permissions, RPC + gas), `sailor onboard`, `sailor mandate …`, `sailor station start`.
@@ -0,0 +1,2 @@
1
+ # Sailor Project
2
+ See [AGENTS.md](./AGENTS.md) for all project guidance. This file is a pointer; AGENTS.md is canonical.
@@ -0,0 +1,16 @@
1
+ # DCA Rebalancer — Sail Protocol Agent
2
+
3
+ This folder is your Sail agent. It DCA-rebalances a token basket on a schedule.
4
+
5
+ Open this folder in **Claude Code**, **Cursor**, or **Codex** (or any LLM-powered IDE) and say:
6
+
7
+ > start
8
+
9
+ Your AI coding assistant will walk you through every step — from network and wallet setup to your
10
+ first on-chain tick. See `AGENTS.md` for the details; no manual config needed.
11
+
12
+ ## Project layout
13
+
14
+ - `.sail/config.json` is the local project manifest.
15
+ - `.sail/keys/` stores the encrypted agent wallet and mandate signer keys when local signing is used.
16
+ - `.sail/state/` is for persistent agent state, audit logs, and tx history.
@@ -0,0 +1,13 @@
1
+ # Sailor project — never commit these
2
+ .sail/.env.local
3
+ .sail/keys/
4
+ .sail/state/
5
+ .sail/runtime/
6
+
7
+ # Dependencies
8
+ node_modules/
9
+
10
+ # Foundry build outputs
11
+ out/
12
+ cache/
13
+ broadcast/
@@ -0,0 +1,93 @@
1
+ # Sail permission model: conjunctive vs selective
2
+
3
+ The deployed SailKernel ships in **two incompatible dispatch models**. Which one a
4
+ chain runs changes how dispatches are signed *and* how permissions must be written.
5
+ Get this wrong and every dispatch reverts with an opaque selector. This is the single
6
+ most important thing to understand before operating an SMA.
7
+
8
+ ## TL;DR
9
+
10
+ | | **Conjunctive** (older) | **Selective** (newer) |
11
+ |---|---|---|
12
+ | Chains today (bundled kernels) | None — all bundled kernels moved to selective | Base (8453), Base Sepolia (84532), Arbitrum (42161), Unichain (130) |
13
+ | `dispatch(...)` | `(account, target, value, data, sig, deadline)` — **no `permission`** | `(account, permission, target, value, data, sig, deadline)` |
14
+ | Which permissions are checked | **ALL** registered permissions; **all must return true** | only the **one** permission named in the call |
15
+ | EIP-712 `Dispatch` struct | no `permission` field | includes `permission` |
16
+ | Batch (`dispatchBatch`/`previewBatch`) | **not available** | available |
17
+ | **Permission design rule** | **MUST pass through calls outside its domain** | may return false freely |
18
+
19
+ Don't guess from a version string — **detect it on-chain** (see below).
20
+
21
+ ## The conjunctive pass-through rule (the big footgun)
22
+
23
+ On a conjunctive kernel the kernel calls `evaluate(txData, ctx)` on **every**
24
+ registered permission and ANDs the results. A single `false` blocks the whole
25
+ dispatch (`PermissionDenied`).
26
+
27
+ So a permission that only cares about, say, approvals **must still return `true` for
28
+ every call it doesn't govern**:
29
+
30
+ ```solidity
31
+ function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
32
+ // Pass through calls outside this permission's domain (conjunctive model).
33
+ if (ctx.selector != APPROVE) return true; // <-- without this line, this
34
+ // permission bricks swaps,
35
+ // transfers, everything.
36
+ // ...domain-specific checks for approve...
37
+ }
38
+ ```
39
+
40
+ A permission that returns `false` (or reverts, or runs out of gas — both treated as
41
+ `false`) on unrelated calls **bricks the entire account**: no dispatch of any kind
42
+ can pass. We hit exactly this during bring-up with permissions that "blocked each
43
+ other." The fix was to redeploy every permission with pass-through semantics.
44
+
45
+ Corollary: on a conjunctive kernel you **cannot** have two permissions that each
46
+ enforce a different token's approve — each would reject the other's token. To support
47
+ approving both DAI and USDC you need **one** approve permission that allows both, not
48
+ two narrow ones.
49
+
50
+ Selective kernels don't have this problem: each dispatch names one permission and
51
+ only that one is consulted.
52
+
53
+ ## Detect the model on-chain
54
+
55
+ The SDK reads each kernel's public `DISPATCH_TYPEHASH` constant and matches it
56
+ against the canonical hashes for each model. Never assume.
57
+
58
+ ```ts
59
+ const caps = await client.capabilities();
60
+ // caps.dispatchModel: "conjunctive" | "selective"
61
+ // caps.dispatchTypehash, caps.source ("onchain-typehash" | "static-hint")
62
+ ```
63
+
64
+ Verified typehashes:
65
+
66
+ - conjunctive `DISPATCH_TYPEHASH` = `0x7510c80e…`
67
+ `Dispatch(address account,address target,uint256 value,bytes32 dataHash,uint256 nonce,uint256 deadline)`
68
+ - selective `DISPATCH_TYPEHASH` =
69
+ `Dispatch(address account,address permission,address target,uint256 value,bytes32 dataHash,uint256 nonce,uint256 deadline)`
70
+
71
+ `client.dispatch.single(...)` already signs the correct struct and uses the correct
72
+ ABI for the detected model — you don't sign by hand. `client.dispatch.batch` /
73
+ `client.dispatch.preview` throw a clear error on conjunctive kernels (no `dispatchBatch`).
74
+
75
+ ## Roles (unchanged across models)
76
+
77
+ | Role | Authority |
78
+ |------|-----------|
79
+ | **Owner** | Holds the Safe; custody anchor. |
80
+ | **Permission Signer** | Authorizes which `IPermission` contracts apply (EIP-712 `RegisterPermissions` / `RevokePermissions`). Signed in the browser signing station — the agent never holds this key. |
81
+ | **Manager** | Executes dispatches within the registered permissions (ECDSA / ERC-1271). The agent's hot key. |
82
+
83
+ ## Preflight before spending gas
84
+
85
+ Run `sailor doctor` (read-only, no gas, no keys):
86
+
87
+ - detects the dispatch model,
88
+ - lists registered permissions,
89
+ - on a conjunctive kernel, **probes each permission for pass-through** and flags any
90
+ that would brick dispatch.
91
+
92
+ See [AGENT_PLAYBOOK.md](../AGENT_PLAYBOOK.md) for the operational decision tree and the
93
+ revert failure-mode catalog.
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "dca-rebalancer",
3
+ "version": "0.1.0",
4
+ "description": "Dollar-cost-average rebalancer — starter Sail Protocol agent",
5
+ "type": "module",
6
+ "scripts": {
7
+ "typecheck": "tsc -p tsconfig.json --noEmit"
8
+ },
9
+ "dependencies": {
10
+ "@sail/sdk": "workspace:*",
11
+ "viem": "^2.21.0"
12
+ },
13
+ "devDependencies": {
14
+ "@types/node": "^22.0.0",
15
+ "typescript": "^5.5.0"
16
+ }
17
+ }