@dev.sail.money/sailor 1.2.0-76 → 1.2.0-78

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.
@@ -0,0 +1,105 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.26;
3
+
4
+ // ─────────────────────────────────────────────────────────────────────────────
5
+ // Protocol : Limitless Exchange
6
+ // Version : Polymarket-fork prediction market — OFF-CHAIN CLOB on Base
7
+ // Chain : Base mainnet
8
+ //
9
+ // ⚠ READ FIRST — you CANNOT bound the bet itself on-chain.
10
+ // Limitless is a Polymarket fork. Orders are EIP-712 structs signed OFF-CHAIN
11
+ // and POSTed to the Limitless API; the on-chain CTF Exchange only settles
12
+ // orders the API has already matched. There is no on-chain `buy(...)` call for
13
+ // a permission to gate — the kernel never sees the bet. A permission that
14
+ // pretends to bound bet placement bounds nothing.
15
+ //
16
+ // Worse, the SMA cannot even be the bettor. The Limitless API validates every
17
+ // order by ECDSA-recovering the signature and requiring
18
+ // `maker == signer == profile.account` — unconditionally, ignoring
19
+ // `signatureType` (so EIP-1271 / Gnosis-Safe signing never applies off-chain).
20
+ // A smart contract cannot produce an ECDSA signature, and `addOperator` is
21
+ // admin-only. Therefore the maker MUST be an EOA.
22
+ //
23
+ // THE WORKING MODEL — SMA as treasury, manager (agent EOA) as trader:
24
+ // • SMA holds the bulk USDC. This permission bounds ONLY the treasury → trader
25
+ // funding flow (a capped transfer to the manager + approvals to the venue).
26
+ // • The manager wallet is the on-chain maker: it holds a small USDC float,
27
+ // signs CLOB orders off-chain, holds the ConditionalTokens positions, and
28
+ // redeems winnings. The bet sizing/selection is off-chain agent logic.
29
+ // • Risk surface = the float on the manager, not the SMA balance.
30
+ //
31
+ // ENFORCES ON-CHAIN (kernel calls evaluate() on every dispatch; false ⇒ blocked):
32
+ // USDC.transfer(address to, uint256 amount) selector 0xa9059cbb
33
+ // • target must be USDC
34
+ // • to must be the MANAGER wallet (treasury can only fund the trader)
35
+ // • amount ≤ MAX_TRANSFER (per-dispatch float cap)
36
+ // USDC.approve(address spender, uint256 amount) selector 0x095ea7b3
37
+ // • target must be USDC
38
+ // • spender must be an ALLOWED_SPENDER (CTF Exchange / NegRisk Exchange / Adapter)
39
+ //
40
+ // AGENT-ENFORCED / NOT BOUNDED HERE (off-chain — the kernel cannot see these):
41
+ // • Bet placement, market/outcome selection, price, stake sizing (off-chain CLOB)
42
+ // • Redeeming winnings (a manager-EOA tx; the manager, not the SMA, holds the tokens)
43
+ // • Timing / frequency
44
+ //
45
+ // VERIFY BEFORE USE:
46
+ // • MANAGER is your agent wallet (the only address the treasury may fund).
47
+ // • USDC is native Base USDC (0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913).
48
+ // • ALLOWED_SPENDERS are the live Limitless CTF Exchange, NegRisk Exchange, and
49
+ // NegRisk Adapter addresses on Base (confirm on Basescan).
50
+ // ─────────────────────────────────────────────────────────────────────────────
51
+
52
+ import {IPermission, Context} from "@sail/interfaces/IPermission.sol";
53
+
54
+ contract BoundedLimitless_Base is IPermission {
55
+ bytes32 private constant DISCRIMINATOR = keccak256("BoundedLimitless_Base");
56
+
57
+ bytes4 private constant SEL_TRANSFER = bytes4(keccak256("transfer(address,uint256)")); // 0xa9059cbb
58
+ bytes4 private constant SEL_APPROVE = bytes4(keccak256("approve(address,uint256)")); // 0x095ea7b3
59
+
60
+ address public immutable USDC;
61
+ address public immutable MANAGER;
62
+ uint256 public immutable MAX_TRANSFER;
63
+ mapping(address => bool) public isAllowedSpender;
64
+
65
+ /// @param usdc USDC token address on Base (the only target this permission bounds)
66
+ /// @param manager The agent EOA — the only address the treasury may fund
67
+ /// @param maxTransfer Per-dispatch cap on the treasury → manager transfer (base units)
68
+ /// @param allowedSpenders Venue addresses USDC may be approved to (CTF Exchange / NegRisk / Adapter)
69
+ constructor(
70
+ address usdc,
71
+ address manager,
72
+ uint256 maxTransfer,
73
+ address[] memory allowedSpenders
74
+ ) {
75
+ USDC = usdc;
76
+ MANAGER = manager;
77
+ MAX_TRANSFER = maxTransfer;
78
+ for (uint256 i = 0; i < allowedSpenders.length; i++) {
79
+ isAllowedSpender[allowedSpenders[i]] = true;
80
+ }
81
+ }
82
+
83
+ function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
84
+ // Only USDC is in scope, and no native value may ride along.
85
+ if (ctx.target != USDC) return false;
86
+ if (ctx.value != 0) return false;
87
+ if (txData.length < 4 + 2 * 32) return false;
88
+
89
+ if (ctx.selector == SEL_TRANSFER) {
90
+ (address to, uint256 amount) = abi.decode(txData[4:], (address, uint256));
91
+ if (to != MANAGER) return false; // treasury funds the trader only
92
+ if (amount > MAX_TRANSFER) return false; // bounded float, not the whole SMA
93
+ return true;
94
+ }
95
+
96
+ if (ctx.selector == SEL_APPROVE) {
97
+ (address spender, ) = abi.decode(txData[4:], (address, uint256));
98
+ return isAllowedSpender[spender]; // approve only the venue contracts
99
+ }
100
+
101
+ return false;
102
+ }
103
+
104
+ function discriminator() external pure returns (bytes32) { return DISCRIMINATOR; }
105
+ }
@@ -10,10 +10,12 @@ write your own.
10
10
  ## Permissions are only as strong as the protocol is on-chain
11
11
 
12
12
  A permission is evaluated by the kernel on every dispatch — but it can only see what happens
13
- on-chain. For venues with off-chain order matching (e.g. Polymarket, Hyperliquid), a permission
14
- can constrain deposits, withdrawals, and sub-accounts, but NOT the orders your agent signs
15
- off-chain. Prefer fully on-chain venues — Uniswap, Aave, GMX, Synthetix, Limitless — where every
16
- action passes through the kernel and your bounds actually hold.
13
+ on-chain. For venues with off-chain order matching (e.g. Polymarket, Limitless, Hyperliquid), a
14
+ permission can constrain deposits, withdrawals, approvals, and treasury flows, but NOT the orders
15
+ your agent signs off-chain. Prefer fully on-chain venues — Uniswap, Aave, GMX, Synthetix — where
16
+ every action passes through the kernel and your bounds actually hold. For an off-chain-CLOB venue,
17
+ bound the funding flow instead and accept that the trade itself is agent-enforced — see
18
+ `BoundedLimitless_Base.sol`.
17
19
 
18
20
  ## Permissions are protocol- and version-specific
19
21
 
@@ -51,7 +53,7 @@ off-chain agent code — these do *not* hold on-chain). Read both before deployi
51
53
  | `BoundedStake_Venice_Base.sol` | Venice (VVV) staking | sVVV staking | Base | Full decode |
52
54
  | `BoundedTransfer_ERC20_Ethereum.sol` | ERC-20 Transfer | — | Ethereum (any EVM) | Full decode |
53
55
  | `BoundedPerp_GMXv2_Arbitrum.sol` | GMX Perpetuals | V2 ExchangeRouter | Arbitrum | Reference pattern — verify selector/struct/router against live GMX ABI (see header) |
54
- | `BoundedBet_Limitless_Base.sol` | Limitless Prediction | CTF Exchange | Base | UNVERIFIED ABI see header |
56
+ | `BoundedLimitless_Base.sol` | Limitless Prediction (off-chain CLOB) | Polymarket fork | Base | Bounds treasury→trader funding; bet is off-chain (see header) |
55
57
  | `BoundedApproveAndCallBatch.sol` | Atomic approve→call→reset | Sail `IBatchPermission` | Any selective kernel | Full decode — batch-only (see note below) |
56
58
 
57
59
  The `interfaces/` directory holds `IPermission.sol` (single-call permissions) and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev.sail.money/sailor",
3
- "version": "1.2.0-76",
3
+ "version": "1.2.0-78",
4
4
  "description": "Operator toolkit for Sail Protocol",
5
5
  "bin": {
6
6
  "sailor": "packages/cli/dist/index.cjs"
@@ -31,6 +31,7 @@
31
31
  "typecheck": "pnpm --filter @sail/sdk build && pnpm -r typecheck",
32
32
  "docs:check": "node scripts/check-docs.mjs",
33
33
  "init:check": "node scripts/check-init.mjs",
34
+ "update:check": "node scripts/check-update.mjs",
34
35
  "eval": "node evals/run.mjs",
35
36
  "lint": "biome check ."
36
37
  },
@@ -5,7 +5,7 @@
5
5
  * Do not edit manually — run `pnpm build` to regenerate.
6
6
  *
7
7
  * Spec version : 1.2.0
8
- * Generated at : 2026-06-18T11:23:35.421Z
8
+ * Generated at : 2026-06-18T13:17:07.561Z
9
9
  */
10
10
  export declare const SAIL_INTELLIGENCE_BASE_URL = "https://api.sail.money";
11
11
  export declare const SAIL_INTELLIGENCE_DOCS_URL = "https://api.sail.money/docs";
@@ -5,7 +5,7 @@
5
5
  * Do not edit manually — run `pnpm build` to regenerate.
6
6
  *
7
7
  * Spec version : 1.2.0
8
- * Generated at : 2026-06-18T11:23:35.421Z
8
+ * Generated at : 2026-06-18T13:17:07.561Z
9
9
  */
10
10
  export const SAIL_INTELLIGENCE_BASE_URL = "https://api.sail.money";
11
11
  export const SAIL_INTELLIGENCE_DOCS_URL = "https://api.sail.money/docs";
@@ -1,97 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity 0.8.26;
3
-
4
- // ─────────────────────────────────────────────────────────────────────────────
5
- // Protocol : Limitless
6
- // Version : CTF-based prediction market (on-chain settlement on Base)
7
- // NOT Polymarket (Polymarket's CLOB matches orders off-chain on Polygon —
8
- // a permission cannot bound the orders your agent signs off-chain.
9
- // Limitless settles bets on-chain on Base, so the kernel sees every action.)
10
- // Chain : Base mainnet
11
- //
12
- // ⚠ WARNING — ABI UNVERIFIED ⚠
13
- // The Limitless exchange contract address and bet-placement function signature
14
- // below are based on published CTF exchange patterns and public documentation.
15
- // They have NOT been independently verified against the deployed contracts.
16
- // YOU MUST verify these before deploying with real funds:
17
- // 1. Find the Limitless exchange contract address on Basescan.
18
- // 2. Read its verified ABI and confirm the buy/place function signature.
19
- // 3. Recompute the selector and update SEL_BUY.
20
- // 4. Confirm the parameter layout matches BetParams below.
21
- // Deploying this contract with an unverified ABI may silently PASS or FAIL
22
- // all dispatches depending on whether the selector matches.
23
- //
24
- // ENFORCES ON-CHAIN (kernel calls evaluate() on every dispatch; false ⇒ dispatch blocked)
25
- // — ASSUMING the unverified ABI above is correct:
26
- // buy(bytes32 conditionId,uint256 amount,uint256 outcomeIndex) selector = keccak256(sig)[0:4]
27
- // • target must be LIMITLESS_EXCHANGE
28
- // • conditionId must be in ALLOWED_CONDITIONS
29
- // • amount ≤ MAX_STAKE
30
- // • outcomeIndex must be in ALLOWED_OUTCOMES
31
- //
32
- // AGENT-ENFORCED / NOT BOUNDED HERE (off-chain — can change without redeploying this contract):
33
- // • Market price / odds (on-chain prediction market prices fluctuate)
34
- // • Timing / frequency of bets
35
- //
36
- // VERIFY BEFORE USE:
37
- // • Confirm Limitless exchange address on Base (Basescan).
38
- // • Confirm buy function signature and compute selector:
39
- // keccak256("buy(bytes32,uint256,uint256)")[0:4] == 0x??? — verify on-chain.
40
- // • Confirm conditionId encoding matches the deployed market IDs.
41
- // • Update this contract if the ABI or parameter order differs.
42
- // ─────────────────────────────────────────────────────────────────────────────
43
-
44
- import {IPermission, Context} from "@sail/interfaces/IPermission.sol";
45
-
46
- contract BoundedBet_Limitless_Base is IPermission {
47
- bytes32 private constant DISCRIMINATOR = keccak256("BoundedBet_Limitless_Base");
48
-
49
- /// @dev ⚠ UNVERIFIED — replace with verified Limitless exchange address on Base.
50
- address public immutable LIMITLESS_EXCHANGE;
51
- mapping(bytes32 => bool) public isAllowedCondition;
52
- uint256 public immutable MAX_STAKE;
53
- mapping(uint256 => bool) public isAllowedOutcome;
54
-
55
- /// @dev ⚠ UNVERIFIED selector. Compute keccak256("buy(bytes32,uint256,uint256)")[0:4]
56
- /// and confirm it matches the deployed Limitless exchange contract before use.
57
- bytes4 private constant SEL_BUY = bytes4(keccak256("buy(bytes32,uint256,uint256)"));
58
-
59
- /// @param limitlessExchange ⚠ VERIFY — Limitless CTF exchange address on Base
60
- /// @param allowedConditions conditionIds (bytes32) of markets the agent may bet on
61
- /// @param maxStake Per-bet stake cap in collateral base units
62
- /// @param allowedOutcomes Outcome indices the agent may select (e.g. [0] for YES only)
63
- constructor(
64
- address limitlessExchange,
65
- bytes32[] memory allowedConditions,
66
- uint256 maxStake,
67
- uint256[] memory allowedOutcomes
68
- ) {
69
- LIMITLESS_EXCHANGE = limitlessExchange;
70
- MAX_STAKE = maxStake;
71
- for (uint256 i = 0; i < allowedConditions.length; i++) {
72
- isAllowedCondition[allowedConditions[i]] = true;
73
- }
74
- for (uint256 i = 0; i < allowedOutcomes.length; i++) {
75
- isAllowedOutcome[allowedOutcomes[i]] = true;
76
- }
77
- }
78
-
79
- function evaluate(bytes calldata txData, Context calldata ctx) external view returns (bool) {
80
- if (ctx.target != LIMITLESS_EXCHANGE) return false;
81
- if (ctx.selector != SEL_BUY) return false;
82
- if (txData.length < 4 + 3 * 32) return false;
83
-
84
- // ⚠ Assumes: buy(bytes32 conditionId, uint256 amount, uint256 outcomeIndex)
85
- // Verify parameter order against deployed contract ABI before use.
86
- (bytes32 conditionId, uint256 amount, uint256 outcomeIndex) =
87
- abi.decode(txData[4:], (bytes32, uint256, uint256));
88
-
89
- if (!isAllowedCondition[conditionId]) return false;
90
- if (amount > MAX_STAKE) return false;
91
- if (!isAllowedOutcome[outcomeIndex]) return false;
92
-
93
- return true;
94
- }
95
-
96
- function discriminator() external pure returns (bytes32) { return DISCRIMINATOR; }
97
- }