@mysten-incubation/sui-agent-pass 0.1.5 → 0.1.7
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.
- package/README.md +5 -1
- package/dist/cli.js +54 -4
- package/package.json +3 -2
- package/skills/agent-pass/SKILL.md +235 -0
package/README.md
CHANGED
|
@@ -61,7 +61,11 @@ npm install -g @mysten-incubation/sui-agent-pass
|
|
|
61
61
|
agent-pass connect # pick the agents on this machine; nothing stays running
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
That is the only command.
|
|
64
|
+
That is the only command. For each agent you pick it registers the MCP server and links the
|
|
65
|
+
`agent-pass` skill, the playbook built into the package, into the agent's skills folder (Claude
|
|
66
|
+
Code, Codex, Cursor and Hermes), so the agent has the tools and the guidance for them. A link
|
|
67
|
+
follows upgrades; rerun `connect` if you installed through `npx`. Then open the agent and tell
|
|
68
|
+
it what to do with your money. It
|
|
65
69
|
proposes a pass (`propose_authorization`) and opens the review page with the proposal in its URL.
|
|
66
70
|
Connect a wallet, check the rules the agent quoted to you, and sign once; the session key stays
|
|
67
71
|
local, and the agent sees your signature land on chain and acts within the rules. Claude Code
|
package/dist/cli.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { spawn } from 'node:child_process';
|
|
5
5
|
import { realpathSync } from 'node:fs';
|
|
6
|
-
import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
6
|
+
import { access, cp, lstat, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises';
|
|
7
7
|
import { homedir } from 'node:os';
|
|
8
|
-
import { dirname, join, resolve } from 'node:path';
|
|
8
|
+
import { dirname, join, resolve, sep } from 'node:path';
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
10
|
import { select } from '@inquirer/prompts';
|
|
11
11
|
import { Command } from 'commander';
|
|
@@ -111,7 +111,16 @@ async function mergeJsonConfig(path, entry) {
|
|
|
111
111
|
await writeFile(path, JSON.stringify(current, null, 2) + '\n', { mode: 0o600 });
|
|
112
112
|
console.log(`Wrote agent-pass into ${path}. Restart the client to load it.`);
|
|
113
113
|
}
|
|
114
|
+
/** Registers agent-pass with Claude Code, replacing an earlier entry in the same scope. */
|
|
114
115
|
async function claudeMcpAdd(args) {
|
|
116
|
+
const scope = args[args.indexOf('--scope') + 1];
|
|
117
|
+
await new Promise((done) => {
|
|
118
|
+
const remove = spawn('claude', ['mcp', 'remove', '--scope', scope, 'agent-pass'], {
|
|
119
|
+
stdio: 'ignore',
|
|
120
|
+
});
|
|
121
|
+
remove.once('error', () => done());
|
|
122
|
+
remove.once('exit', () => done());
|
|
123
|
+
});
|
|
115
124
|
const child = spawn('claude', ['mcp', 'add', ...args], { stdio: 'inherit' });
|
|
116
125
|
await new Promise((resolve, reject) => {
|
|
117
126
|
child.once('error', reject);
|
|
@@ -174,6 +183,45 @@ async function registerClient(client, http) {
|
|
|
174
183
|
console.log(JSON.stringify({ mcpServers: { 'agent-pass': http ?? stdio } }, null, 2));
|
|
175
184
|
}
|
|
176
185
|
}
|
|
186
|
+
/** Where each agent loads personal skills from, under the home directory. */
|
|
187
|
+
const SKILL_DIRS = {
|
|
188
|
+
'claude-code': '.claude/skills',
|
|
189
|
+
codex: '.codex/skills',
|
|
190
|
+
cursor: '.cursor/skills',
|
|
191
|
+
hermes: '.hermes/skills',
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Puts the agent-pass skill, the playbook built into this package, where the client loads
|
|
195
|
+
* skills. A link follows upgrades of the package; an npx cache is temporary, so it gets a copy.
|
|
196
|
+
*/
|
|
197
|
+
async function installSkill(client) {
|
|
198
|
+
const source = fileURLToPath(new URL('../skills/agent-pass', import.meta.url));
|
|
199
|
+
if (!(await access(join(source, 'SKILL.md')).then(() => true, () => false)))
|
|
200
|
+
throw new Error(`The skill is missing from ${source}; run npm run build`);
|
|
201
|
+
const dir = SKILL_DIRS[client];
|
|
202
|
+
if (!dir) {
|
|
203
|
+
console.log(client === 'claude-desktop'
|
|
204
|
+
? `Claude Desktop takes skills from its own settings; add ${join(source, 'SKILL.md')} there to give it the playbook.`
|
|
205
|
+
: `If the agent loads SKILL.md skills, link ${source} into its skills folder to give it the playbook.`);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const target = join(homedir(), dir, 'agent-pass');
|
|
209
|
+
const existing = await lstat(target).catch(() => null);
|
|
210
|
+
if (existing && !existing.isSymbolicLink()) {
|
|
211
|
+
const ours = await readFile(join(target, 'SKILL.md'), 'utf8').then((t) => /^name: agent-pass$/m.test(t), () => false);
|
|
212
|
+
if (!ours)
|
|
213
|
+
throw new Error(`${target} exists and is not the agent-pass skill; move it away first`);
|
|
214
|
+
}
|
|
215
|
+
if (existing)
|
|
216
|
+
await rm(target, { recursive: true, force: true });
|
|
217
|
+
await mkdir(dirname(target), { recursive: true });
|
|
218
|
+
const temporary = source.includes(`${sep}_npx${sep}`);
|
|
219
|
+
if (temporary)
|
|
220
|
+
await cp(source, target, { recursive: true });
|
|
221
|
+
else
|
|
222
|
+
await symlink(source, target, 'dir');
|
|
223
|
+
console.log(`${temporary ? 'Copied' : 'Linked'} the agent-pass skill into ${target}.`);
|
|
224
|
+
}
|
|
177
225
|
/** The agents on this machine, as far as their usual files show; nothing is preselected. */
|
|
178
226
|
async function chooseClients() {
|
|
179
227
|
const home = homedir();
|
|
@@ -234,10 +282,12 @@ program
|
|
|
234
282
|
http = { url: mcpUrl, headers: { Authorization: `Bearer ${await store.mcpToken()}` } };
|
|
235
283
|
}
|
|
236
284
|
const clients = o.client ? [o.client] : await chooseClients();
|
|
237
|
-
for (const client of clients)
|
|
285
|
+
for (const client of clients) {
|
|
238
286
|
await registerClient(client, http);
|
|
287
|
+
await installSkill(client);
|
|
288
|
+
}
|
|
239
289
|
if (!http)
|
|
240
|
-
console.log('\nDone. Open the agent and tell it what to do with your money; it proposes the pass, you review and sign in your wallet, and it acts within the rules. Restart the agent after upgrading this package so it loads the new server.');
|
|
290
|
+
console.log('\nDone. Open the agent and tell it what to do with your money; it proposes the pass, you review and sign in your wallet, and it acts within the rules. Restart the agent after upgrading this package so it loads the new server and skill.');
|
|
241
291
|
});
|
|
242
292
|
// Run only when this file is the entry: directly, through tsx in development, or through the
|
|
243
293
|
// package's `agent-pass` bin, which is a symlink to it.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mysten-incubation/sui-agent-pass",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI builds transactions. A session signer signs. Your pass enforces the rules.",
|
|
6
6
|
"repository": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"deployments",
|
|
27
27
|
"docs/AGENT.md",
|
|
28
28
|
"docs/PLAYBOOK.md",
|
|
29
|
+
"skills",
|
|
29
30
|
"README.md",
|
|
30
31
|
"LICENSE"
|
|
31
32
|
],
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
"node": ">=22"
|
|
38
39
|
},
|
|
39
40
|
"scripts": {
|
|
40
|
-
"build": "tsc && vite build",
|
|
41
|
+
"build": "tsc && vite build && node scripts/skill.mjs",
|
|
41
42
|
"prepublishOnly": "npm run build",
|
|
42
43
|
"check": "tsc -p tsconfig.tools.json && tsc -p tsconfig.web.json",
|
|
43
44
|
"test": "node --import tsx --test tests/*.test.ts",
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-pass
|
|
3
|
+
description: "Set up and use a Sui Agent Pass: turn a request such as \"sell up to 0.5 SUI a day for USDC at no less than 0.95, for a week\" into on-chain rules the owner signs once in their wallet, then trade, transfer, stake, lend and borrow within them through the agent-pass MCP server. Use for giving an agent money to manage on Sui, any Sui swap, transfer, staking or NAVI lending request, including coins not listed by default, checking or changing a pass, or ending one."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Agent playbook
|
|
7
|
+
|
|
8
|
+
How an agent sets up a pass from an owner's request, acts within its rules, reports on it,
|
|
9
|
+
changes it and ends it. Every MCP client gets this text as the `agent-pass://playbook` resource;
|
|
10
|
+
the SDK and the contract interface are in `agent-pass://guide` ([`docs/AGENT.md`](AGENT.md)).
|
|
11
|
+
|
|
12
|
+
## How a pass works
|
|
13
|
+
|
|
14
|
+
The owner's coins stay in the owner's address. The owner signs once in their own wallet, and
|
|
15
|
+
that one transaction creates a pass holding the rules, issues allowances over the owner's
|
|
16
|
+
balance that only the pass can spend, and gives the agent key its gas. You act with that agent
|
|
17
|
+
key, which the signer holds and you never see. Each action is a transaction that draws on an
|
|
18
|
+
allowance and that the chain checks against the rules; proceeds go back to the owner's address,
|
|
19
|
+
never to you. A position you open (a NAVI account, a stake) sits in the pass, and only the owner
|
|
20
|
+
can take it out.
|
|
21
|
+
|
|
22
|
+
A signature from the signer is not permission. Only a successful on-chain execution is.
|
|
23
|
+
|
|
24
|
+
Respond in English. Amounts are exact decimals in each coin's own units; `list_passes` and
|
|
25
|
+
`session_info` give every coin's decimals. Dates are UTC, and a day is a UTC calendar day. Off
|
|
26
|
+
mainnet the stablecoin is a test token and the markets are stand-ins; transfers and staking are
|
|
27
|
+
real everywhere.
|
|
28
|
+
|
|
29
|
+
## 1. Turn the request into rules
|
|
30
|
+
|
|
31
|
+
Map what the owner asks for onto the rule sets below. Anything they did not ask for is not
|
|
32
|
+
allowed: leave it out. One rule per coin, per swap direction and per lending coin; a coin without
|
|
33
|
+
a rule cannot be touched.
|
|
34
|
+
|
|
35
|
+
Three things only the owner can supply. Ask for them; never fill them in:
|
|
36
|
+
|
|
37
|
+
- **Recipients.** Every transfer goes to a named address the owner gave you.
|
|
38
|
+
- **Prices.** Every swap rule needs the owner's price limit. When they have not said one, show
|
|
39
|
+
them the pool's current price from `list_passes` and ask what they accept.
|
|
40
|
+
- **Amounts.** When a limit is missing, ask, or propose a conservative one and say that you did.
|
|
41
|
+
|
|
42
|
+
Every limit must be above zero; there is no "no limit".
|
|
43
|
+
|
|
44
|
+
| Rule set | Fields | What the chain enforces |
|
|
45
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
46
|
+
| `transfers` | `coin`, named recipients (name and address), per transfer, per day | only those recipients ever receive that coin |
|
|
47
|
+
| `swaps` | `sell`, `buy`, optional `venues` (`deepbook`, `cetus`; every listed pool for the pair when omitted), per trade, per day, `limitPrice` | only listed pools; limits on the sold coin; every fill at the price limit or better |
|
|
48
|
+
| `lending` | `coin`, `allowBorrow`, per action, per day, `minHealthFactor` (or null) | NAVI only; supply and withdraw, plus borrow and repay when allowed; a withdraw or borrow that would take the health factor under the floor is refused |
|
|
49
|
+
| `staking` | validators (empty for any active one), SUI per stake, per day | only those validators; at least 1 SUI per stake; the stake stays in the pass |
|
|
50
|
+
|
|
51
|
+
**Prices.** When one coin of a pair is a stablecoin, `limitPrice` is in that stablecoin per one
|
|
52
|
+
of the other coin: the most the agent pays when buying, the least it accepts when selling. For
|
|
53
|
+
other pairs it is the bought coin per one sold coin, the least accepted. The limit is fixed when
|
|
54
|
+
the owner signs, so a limit close to the market refuses every trade once the price moves past
|
|
55
|
+
it; say so when the owner picks one.
|
|
56
|
+
|
|
57
|
+
**Venues.** DeepBook fills nothing under a pool's minimum order (1 SUI on the mainnet SUI/USDC
|
|
58
|
+
pool), so list Cetus as well when trades will be small. A network may list no pools or no NAVI
|
|
59
|
+
reserves; `list_passes` says so, and swap or lending rules are refused there.
|
|
60
|
+
|
|
61
|
+
**Coins and pools.** The coins and pools `list_passes` shows for a network are the ones this
|
|
62
|
+
package lists, not the only ones it can use. Name a listed coin by symbol. Name any other coin
|
|
63
|
+
the owner holds by its full type, and for a swap give the id of a DeepBook or Cetus pool holding
|
|
64
|
+
exactly that pair in `pools`. To find the type and the balance, ask the owner for their address
|
|
65
|
+
and call `list_passes` with `owner`: it adds every coin that address holds per network. For the
|
|
66
|
+
pool, ask the owner or look the pair up on the venue's own site. The server and the review page
|
|
67
|
+
read such a coin's symbol and decimals and such a pool's venue from chain, never from you, and
|
|
68
|
+
the page shows an unlisted coin with its type so the owner can tell a look-alike from the real
|
|
69
|
+
one. Lending is limited to the coins the network lists as NAVI reserves.
|
|
70
|
+
|
|
71
|
+
**Lifetime caps.** `caps` gives, per coin, the total the key may ever withdraw, for exactly the
|
|
72
|
+
coins the rules spend (staking spends SUI). A daily limit may not exceed its coin's cap. Size
|
|
73
|
+
each cap to cover the days of the term, a little above the sum of the daily limits: the chain
|
|
74
|
+
checks the cap before the daily limit, so a cap equal to one day's limit turns a "daily limit"
|
|
75
|
+
refusal into a "lifetime cap" one.
|
|
76
|
+
|
|
77
|
+
**What counts against a limit.** Limits meter what leaves the owner's balance, not net exposure.
|
|
78
|
+
A supply or a stake counts in full, and withdrawing or unstaking returns the funds without giving
|
|
79
|
+
the allowance back. A supply-and-withdraw or stake-and-unstake cycle costs the allowance once, so
|
|
80
|
+
size lending and staking limits for the cycles the agent will run, and tell the owner when they
|
|
81
|
+
ask for something like "restake with a better validator".
|
|
82
|
+
|
|
83
|
+
**Term and gas.** `days` is the agent's term, 1 to 30. `gasSui` (default 0.05) is a stipend sent
|
|
84
|
+
to the agent key, outside the rules. `gasCapSui` (default 0.1) is a separate allowance the key
|
|
85
|
+
draws on to top up its gas, and `gasDailySui` (default a fifth of `gasCapSui`) its daily limit.
|
|
86
|
+
|
|
87
|
+
**What the owner needs.** Allowances draw only from the owner's address balance, never from coin
|
|
88
|
+
objects. The review page reads both, and the signature converts coin objects into the address
|
|
89
|
+
balance as far as each cap (plus `gasCapSui` for SUI) needs; the converted coins stay theirs. The
|
|
90
|
+
owner needs that much in total, address balance and coin objects together, plus `gasSui` and fees.
|
|
91
|
+
|
|
92
|
+
Before you call anything, show the owner the rules you intend to propose as one short list and
|
|
93
|
+
ask for a yes, unless they already stated every rule explicitly.
|
|
94
|
+
|
|
95
|
+
## 2. Propose the pass and wait for the signature
|
|
96
|
+
|
|
97
|
+
`propose_authorization`, `propose_change`, `list_passes`, `revoke_pass` and `forget_pass` live on
|
|
98
|
+
the stdio server (`agent-pass mcp`), which keeps every session on the machine. A per-session HTTP
|
|
99
|
+
signer has only `session_info` and `sign_transaction`.
|
|
100
|
+
|
|
101
|
+
The pass goes on the network the owner names (`network`, one of `list_passes.networks`), else on
|
|
102
|
+
the first network listed. A private publish of one's own takes a `deployment` path instead.
|
|
103
|
+
|
|
104
|
+
Call `propose_authorization` with the rules. It returns `rules`, the exact text the review page
|
|
105
|
+
shows, plus `reviewUrl` and `sessionAddress`, and opens the page in the browser. Paste `rules` to
|
|
106
|
+
the owner word for word and never restate the amounts yourself. Tell them to connect their wallet,
|
|
107
|
+
check the page against that text and sign once. The page shows what their wallet holds against
|
|
108
|
+
what the pass needs. If the browser did not open, give them `reviewUrl`.
|
|
109
|
+
|
|
110
|
+
Then call `session_info` with the pass and `wait: 120`, again while the status is
|
|
111
|
+
`awaiting_authorization`. At `active` the signer has read the pass, the allowances and the
|
|
112
|
+
policies back from chain and checked them against the proposal. Report the pass id, the
|
|
113
|
+
authorization digest, the owner's balances and what the key may still withdraw.
|
|
114
|
+
|
|
115
|
+
## 3. Act within the rules
|
|
116
|
+
|
|
117
|
+
Start with `session_info`. It returns:
|
|
118
|
+
|
|
119
|
+
- `control`: the installed policies with today's usage, the held stakes and NAVI position;
|
|
120
|
+
- `allowances`: what the key may still withdraw under each;
|
|
121
|
+
- `ownerBalances`: per coin, `addressBalance` (what allowances draw from) and `coinBalance` (coin
|
|
122
|
+
objects only the owner can move), so a low address balance next to coin objects is not an owner
|
|
123
|
+
out of money;
|
|
124
|
+
- `gas`: the agent key's own SUI;
|
|
125
|
+
- `coins` and `venues`: each coin's type and decimals, and each pool with its pair, both
|
|
126
|
+
directions' entry functions and DeepBook's minimum order;
|
|
127
|
+
- `directory`, `sdk` and `server`: the session directory, how to install and import the SDK,
|
|
128
|
+
and this server's version (after an upgrade the client must restart the server).
|
|
129
|
+
|
|
130
|
+
Act by writing a Node script against the SDK. Run `sdk.install` once in your working directory,
|
|
131
|
+
then:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import {
|
|
135
|
+
Agent,
|
|
136
|
+
borrow,
|
|
137
|
+
pickValidator,
|
|
138
|
+
quote,
|
|
139
|
+
repay,
|
|
140
|
+
send,
|
|
141
|
+
stake,
|
|
142
|
+
supply,
|
|
143
|
+
swap,
|
|
144
|
+
unstake,
|
|
145
|
+
withdraw,
|
|
146
|
+
} from '@mysten-incubation/sui-agent-pass/agent';
|
|
147
|
+
import { units } from '@mysten-incubation/sui-agent-pass/domain';
|
|
148
|
+
|
|
149
|
+
const agent = await Agent.open(directory);
|
|
150
|
+
const usdc = agent.identity.deployment.coins.find((c) => c.symbol === 'USDC')!;
|
|
151
|
+
const out = await agent.submit(send(agent.identity, usdc.type, units('5', usdc.decimals), 'alice'));
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Swaps.** Before every swap, `quote(identity, pair, amountIn)` prices it on the venue without
|
|
155
|
+
touching an allowance: `amountIn` is what the pool would take and `amountOut` what comes back.
|
|
156
|
+
Set `minOut` a little under `amountOut`, never from a mid price; the owner's price limit still
|
|
157
|
+
applies underneath. DeepBook takes its fee from the input and rounds down to its lot size, so
|
|
158
|
+
sell at least one lot over its minimum.
|
|
159
|
+
|
|
160
|
+
**Repayments.** Size a repayment from the live debt: an over-payment returns to the owner but
|
|
161
|
+
still counts against the allowance.
|
|
162
|
+
|
|
163
|
+
**Outcomes.** `submit` signs through this server, executes on Sui and returns what the chain
|
|
164
|
+
recorded. `success: true` means done. `success: false` means the chain executed the transaction
|
|
165
|
+
and refused it; `reason` is the owner's rule that stopped it, and you quote it. A thrown error
|
|
166
|
+
means nothing executed (a dry run or client error), which you never describe as on-chain
|
|
167
|
+
enforcement. `submit` tops up your gas from the gas allowance when it runs low.
|
|
168
|
+
|
|
169
|
+
**Hand-built transactions.** For anything the builders do not cover, build the PTB with
|
|
170
|
+
`@mysten/sui` following the guide, sign it with `sign_transaction` and execute it yourself. Every
|
|
171
|
+
spend takes the allowance object and a withdrawal input right after the pass. On this path gas is
|
|
172
|
+
yours: when the key holds under 0.01 SUI, draw on the gas allowance as the guide shows. That
|
|
173
|
+
allowance has its own cap and daily limit and never touches the asset caps.
|
|
174
|
+
|
|
175
|
+
## 4. Report the state
|
|
176
|
+
|
|
177
|
+
Call `list_passes`, then `session_info` for each pass the owner asks about (all of them when
|
|
178
|
+
unclear). Report the status (`awaiting_authorization`, `active`, `changing`, `expired`, `revoked`
|
|
179
|
+
or `closed`), the owner's address balances, what the key may still withdraw, its gas, any NAVI
|
|
180
|
+
position or stakes in the pass, and for each policy its limit and today's usage
|
|
181
|
+
(`control.policies[*].usage.usedToday`). Quote the `rules` text as returned; do not recompute
|
|
182
|
+
amounts.
|
|
183
|
+
|
|
184
|
+
## 5. Change the rules
|
|
185
|
+
|
|
186
|
+
When a limit, a recipient, a pool, a price or the term no longer fits, change the pass instead of
|
|
187
|
+
proposing a new one. Call `propose_change` with the pass and the complete new rule set (every
|
|
188
|
+
rule, not just the changed ones), in the same shape as `propose_authorization` without the name
|
|
189
|
+
and the stipend. It opens the review page with the current rules beside the new ones; paste its
|
|
190
|
+
`changes` text to the owner. One signature replaces the policies and reissues only the
|
|
191
|
+
allowances whose cap or term changed. The agent key, its gas and what the pass holds stay;
|
|
192
|
+
replaced policies start the day's usage at zero, and kept allowances keep their lifetime spend.
|
|
193
|
+
|
|
194
|
+
Until the owner signs, the old rules apply and `session_info` reports `changing`. Poll it with
|
|
195
|
+
`wait` until it is `active` again, then read the rules back before acting.
|
|
196
|
+
|
|
197
|
+
## 6. End it
|
|
198
|
+
|
|
199
|
+
There are two endings, both on the pass page, which `revoke_pass` opens for the pass the owner
|
|
200
|
+
names. Without a pass it opens the owner page, which lists all of the owner's passes and ends any
|
|
201
|
+
number of them with one signature; use that when several are to go.
|
|
202
|
+
|
|
203
|
+
- **Stop the agent now** revokes the key and deletes the allowances, and keeps the pass and its
|
|
204
|
+
history on chain. It is the instant answer when something is wrong.
|
|
205
|
+
- **Close the pass** does the same, then returns everything the pass holds to the owner's wallet
|
|
206
|
+
and deletes the pass, which refunds its storage deposit. A NAVI position that owes nothing is
|
|
207
|
+
withdrawn into the owner's wallet first, since NAVI's own app cannot operate a pass's position.
|
|
208
|
+
A position with debt is handed over as it is, and the owner page lists it with its balances.
|
|
209
|
+
This is the normal ending when the owner is done.
|
|
210
|
+
|
|
211
|
+
Tell the owner both exist and that closing refunds the storage cost. They connect the wallet that
|
|
212
|
+
created the pass, pick an ending and sign. Opening the page revokes nothing; only the signed
|
|
213
|
+
transaction does. Then call `session_info` with `wait: 60` until the status is `revoked` or
|
|
214
|
+
`closed`, and confirm that the chain now refuses the key. On a stopped pass, each held object has
|
|
215
|
+
its own **Reclaim** button: a NAVI position comes back with its account cap (collateral first
|
|
216
|
+
when it owes nothing), and a stake as an ordinary `StakedSui`.
|
|
217
|
+
|
|
218
|
+
Once a pass is closed, the signer returns the key's unspent gas to the owner the next time it
|
|
219
|
+
runs. Then call `forget_pass` for the session: it refuses while the pass is live, returns any gas
|
|
220
|
+
still there, and deletes the session directory with its key. Offer it for every pass
|
|
221
|
+
`list_passes` reports as closed or stopped, and for proposals the owner never signed.
|
|
222
|
+
|
|
223
|
+
`list_passes` may also report `unreadable` sessions from an earlier version of this package.
|
|
224
|
+
Their passes may still be live: tell the owner to stop or close each one from its pass page on
|
|
225
|
+
the site, which reads the chain and needs no session file.
|
|
226
|
+
|
|
227
|
+
## Rules of conduct
|
|
228
|
+
|
|
229
|
+
- Confirm with the owner before the first transaction of a session and before any action they
|
|
230
|
+
did not explicitly ask for. Recurring work they asked for, such as a daily purchase, needs no
|
|
231
|
+
confirmation each time.
|
|
232
|
+
- Save the digest of every submission. If a response times out, look the digest up before
|
|
233
|
+
retrying; never resubmit an action while the original could still execute.
|
|
234
|
+
- Never search for, read or copy key files. `sign_transaction` is the only way to sign.
|
|
235
|
+
- Report outcomes from chain state (`session_info`, the digest), never from a signature.
|