@suisei-mcp/agent-signer 0.1.0 → 0.1.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.
- package/README.md +17 -17
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/keystore.js +1 -1
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ The non-custodial signer for a **Tier-1 Sui agent wallet**.
|
|
|
6
6
|
bytes and never holds a key. This package is the one piece that does: it
|
|
7
7
|
generates the agent's keypair, stores it **encrypted on your machine**, and
|
|
8
8
|
signs builder bytes. The plaintext key is created here, used here, and
|
|
9
|
-
**never crosses a process boundary**
|
|
9
|
+
**never crosses a process boundary** - it never travels through an MCP
|
|
10
10
|
response or into an LLM's context.
|
|
11
11
|
|
|
12
12
|
## What "Tier-1 agent wallet" means
|
|
13
13
|
|
|
14
14
|
A real Sui wallet the agent fully controls, funded with a small allowance.
|
|
15
|
-
The agent can stake, transfer, swap
|
|
15
|
+
The agent can stake, transfer, swap - anything - but only up to its
|
|
16
16
|
balance. Blast radius = what you fund. Refill to extend, sweep to revoke.
|
|
17
17
|
Your main wallet is never touched: the agent has its own freshly-generated
|
|
18
18
|
key, and your owner key stays in your real wallet.
|
|
@@ -30,7 +30,7 @@ Set a passphrase (encrypts the key at rest) and create the wallet:
|
|
|
30
30
|
```bash
|
|
31
31
|
export AGENT_WALLET_PASSPHRASE="something-long-and-private"
|
|
32
32
|
agent-signer create
|
|
33
|
-
# -> { "address": "0x
|
|
33
|
+
# -> { "address": "0x...", "path": "~/.suisei/agent-wallet.json" }
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
Then the loop with Claude + the MCP:
|
|
@@ -38,64 +38,64 @@ Then the loop with Claude + the MCP:
|
|
|
38
38
|
1. Ask the agent to fund it: it calls `agent_wallet_fund` (owner-signed) so
|
|
39
39
|
your real wallet sends SUI to the agent address.
|
|
40
40
|
2. Ask the agent to act, e.g. *"stake 1 SUI to the top validator from my
|
|
41
|
-
agent wallet"*
|
|
41
|
+
agent wallet"* - it builds the tx and gives you `tx_bytes_base64`.
|
|
42
42
|
3. Sign with the agent key:
|
|
43
43
|
```bash
|
|
44
44
|
agent-signer sign <tx_bytes_base64>
|
|
45
|
-
# -> { "signature": "
|
|
45
|
+
# -> { "signature": "..." }
|
|
46
46
|
```
|
|
47
47
|
4. Tell the agent to `sui_execute_signed_tx` with that signature.
|
|
48
48
|
|
|
49
49
|
To revoke, ask the agent for `agent_wallet_sweep` (drains the wallet back to
|
|
50
50
|
you), sign it, submit, and stop funding.
|
|
51
51
|
|
|
52
|
-
## You own the key
|
|
52
|
+
## You own the key - back it up or move it
|
|
53
53
|
|
|
54
54
|
The wallet isn't locked inside this tool. The private key is yours,
|
|
55
55
|
encrypted under your passphrase, and you can take it out anytime:
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
58
|
agent-signer export
|
|
59
|
-
# -> { "address": "0x
|
|
59
|
+
# -> { "address": "0x...", "secret_key": "suiprivkey1...", "warning": "..." }
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
That `suiprivkey1
|
|
63
|
-
**Suiet**, or the CLI (`sui keytool import "<suiprivkey1
|
|
64
|
-
you have the same wallet there. Back it up offline
|
|
62
|
+
That `suiprivkey1...` is a standard Sui secret. Import it into **Sui Wallet**,
|
|
63
|
+
**Suiet**, or the CLI (`sui keytool import "<suiprivkey1...>" ed25519`) and
|
|
64
|
+
you have the same wallet there. Back it up offline - anyone holding it
|
|
65
65
|
controls the wallet.
|
|
66
66
|
|
|
67
67
|
Bring your own key instead of generating one:
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
agent-signer import "suiprivkey1
|
|
70
|
+
agent-signer import "suiprivkey1..."
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Because the key is exportable, losing the keystore file isn't fatal **if
|
|
74
74
|
you backed up the export**. If you didn't and you lose the file or
|
|
75
|
-
passphrase, the agent wallet is gone
|
|
75
|
+
passphrase, the agent wallet is gone - but it only ever holds an allowance,
|
|
76
76
|
so create a fresh one and refund. Your owner wallet is untouched.
|
|
77
77
|
|
|
78
78
|
## Configuration
|
|
79
79
|
|
|
80
80
|
| Env / flag | Default | Meaning |
|
|
81
81
|
| --- | --- | --- |
|
|
82
|
-
| `AGENT_WALLET_PASSPHRASE` / `--passphrase` |
|
|
82
|
+
| `AGENT_WALLET_PASSPHRASE` / `--passphrase` | - (required) | Encrypts/decrypts the key |
|
|
83
83
|
| `AGENT_WALLET_PATH` / `--path` | `~/.suisei/agent-wallet.json` | Keystore location |
|
|
84
84
|
|
|
85
85
|
## Security model
|
|
86
86
|
|
|
87
87
|
- **Ed25519** key, sealed with **AES-256-GCM** under a **scrypt**-derived
|
|
88
88
|
key (N=32768). Keystore written `0600`.
|
|
89
|
-
- Wrong passphrase
|
|
89
|
+
- Wrong passphrase -> decryption fails closed (GCM auth tag).
|
|
90
90
|
- `create`/`address` emit only the public address; `sign` emits only a
|
|
91
91
|
signature. The raw secret is revealed only by an explicit `export` (with
|
|
92
|
-
a warning)
|
|
93
|
-
- Lose the keystore or passphrase and the agent wallet is gone
|
|
92
|
+
a warning) - never incidentally, and never to the MCP or an agent.
|
|
93
|
+
- Lose the keystore or passphrase and the agent wallet is gone - by design
|
|
94
94
|
it holds only an allowance, so create a fresh one and refund. Your owner
|
|
95
95
|
wallet (in your real wallet app) is unaffected.
|
|
96
96
|
|
|
97
97
|
This is **Tier 1** of the agent-wallet design. On-chain policy limits
|
|
98
|
-
(Tier 2) and a multisig co-signer (Tier 3) layer on top
|
|
98
|
+
(Tier 2) and a multisig co-signer (Tier 3) layer on top - see
|
|
99
99
|
[`docs/AGENT_WALLET_DESIGN.md`](../../docs/AGENT_WALLET_DESIGN.md).
|
|
100
100
|
|
|
101
101
|
## License
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createWallet, walletAddress, signTxBytes, exportSecret, importWallet, defaultPath, } from './index.js';
|
|
3
3
|
/**
|
|
4
|
-
* agent-signer CLI
|
|
4
|
+
* agent-signer CLI - the manual signing path for a Tier-1 agent wallet.
|
|
5
5
|
*
|
|
6
6
|
* agent-signer create [--overwrite] generate + encrypt a new agent key
|
|
7
7
|
* agent-signer import <suiprivkey> seal an existing key as the wallet
|
|
@@ -108,7 +108,7 @@ async function main() {
|
|
|
108
108
|
}
|
|
109
109
|
default:
|
|
110
110
|
process.stdout.write([
|
|
111
|
-
'agent-signer
|
|
111
|
+
'agent-signer - non-custodial signer for a Tier-1 Sui agent wallet',
|
|
112
112
|
'',
|
|
113
113
|
'Commands:',
|
|
114
114
|
' create [--overwrite] generate + encrypt a new agent key',
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
|
|
2
2
|
/**
|
|
3
|
-
* @suisei-mcp/agent-signer
|
|
3
|
+
* @suisei-mcp/agent-signer - the non-custodial signer for a Tier-1 Sui agent
|
|
4
4
|
* wallet.
|
|
5
5
|
*
|
|
6
6
|
* The MCP toolkit builds unsigned tx bytes and never holds a key. This is
|
|
7
7
|
* the only piece that does: it generates the agent keypair, stores it
|
|
8
8
|
* encrypted on the user's machine, and signs tx bytes. The plaintext key
|
|
9
9
|
* is created here, used here, and never returned across a process boundary
|
|
10
|
-
*
|
|
10
|
+
* - in particular it never travels through an MCP response or an LLM
|
|
11
11
|
* context.
|
|
12
12
|
*
|
|
13
13
|
* Pair the signature this produces with sui_execute_signed_tx to submit.
|
|
@@ -35,7 +35,7 @@ export declare function walletAddress(opts: {
|
|
|
35
35
|
/**
|
|
36
36
|
* Reveal the raw bech32 `suiprivkey...` secret so the user can back it up
|
|
37
37
|
* or import the agent wallet into a standard wallet (Sui Wallet, Suiet,
|
|
38
|
-
* `sui keytool import`). This is the user's escape hatch
|
|
38
|
+
* `sui keytool import`). This is the user's escape hatch - it proves they,
|
|
39
39
|
* not us, own the key. Handle the output carefully: anyone with this string
|
|
40
40
|
* controls the wallet.
|
|
41
41
|
*/
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ export function walletAddress(opts) {
|
|
|
25
25
|
/**
|
|
26
26
|
* Reveal the raw bech32 `suiprivkey...` secret so the user can back it up
|
|
27
27
|
* or import the agent wallet into a standard wallet (Sui Wallet, Suiet,
|
|
28
|
-
* `sui keytool import`). This is the user's escape hatch
|
|
28
|
+
* `sui keytool import`). This is the user's escape hatch - it proves they,
|
|
29
29
|
* not us, own the key. Handle the output carefully: anyone with this string
|
|
30
30
|
* controls the wallet.
|
|
31
31
|
*/
|
package/dist/keystore.js
CHANGED
|
@@ -61,7 +61,7 @@ export function loadSecret(opts) {
|
|
|
61
61
|
]).toString('utf8');
|
|
62
62
|
}
|
|
63
63
|
catch {
|
|
64
|
-
throw new Error('Decryption failed
|
|
64
|
+
throw new Error('Decryption failed - wrong passphrase or corrupted keystore.');
|
|
65
65
|
}
|
|
66
66
|
return { address: file.address, secretBech32 };
|
|
67
67
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suisei-mcp/agent-signer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Local, non-custodial signer for a Tier-1 Sui agent wallet. Generates and encrypts an agent keypair on the user's machine and signs tx bytes from @suisei-mcp/mcp. The key never leaves the host and never enters an agent's context.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"homepage": "https://github.com/eienel/suisei/tree/main/packages/agent-signer",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/eienel/suisei.git",
|
|
11
|
+
"directory": "packages/agent-signer"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/eienel/suisei/issues"
|
|
15
|
+
},
|
|
7
16
|
"main": "dist/index.js",
|
|
8
17
|
"exports": {
|
|
9
18
|
".": "./dist/index.js"
|