@dopamint-fun/open-sdk 0.1.0-dev.0
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 +42 -0
- package/dist/acceptance.d.ts +24 -0
- package/dist/acceptance.js +48 -0
- package/dist/agentHttp.d.ts +52 -0
- package/dist/agentHttp.js +139 -0
- package/dist/bytes.d.ts +40 -0
- package/dist/bytes.js +166 -0
- package/dist/channel.d.ts +38 -0
- package/dist/channel.js +86 -0
- package/dist/claim.d.ts +39 -0
- package/dist/claim.js +91 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1006 -0
- package/dist/crypto.d.ts +3 -0
- package/dist/crypto.js +20 -0
- package/dist/identity.d.ts +32 -0
- package/dist/identity.js +100 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +22 -0
- package/dist/keypair.d.ts +25 -0
- package/dist/keypair.js +69 -0
- package/dist/offer.d.ts +36 -0
- package/dist/offer.js +138 -0
- package/dist/registration.d.ts +53 -0
- package/dist/registration.js +104 -0
- package/dist/seatAuth.d.ts +30 -0
- package/dist/seatAuth.js +285 -0
- package/dist/session.d.ts +260 -0
- package/dist/session.js +840 -0
- package/dist/sessionCodec.d.ts +139 -0
- package/dist/sessionCodec.js +373 -0
- package/dist/sessionWire.d.ts +80 -0
- package/dist/sessionWire.js +118 -0
- package/dist/settlement.d.ts +56 -0
- package/dist/settlement.js +117 -0
- package/dist/texas.d.ts +52 -0
- package/dist/texas.js +217 -0
- package/dist/tour.d.ts +101 -0
- package/dist/tour.js +129 -0
- package/package.json +35 -0
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function blake2b256(input: Uint8Array): Uint8Array;
|
|
2
|
+
export declare function digestFramed(domain: Uint8Array, payload: Uint8Array): Uint8Array;
|
|
3
|
+
export declare function verifyEd25519(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean;
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createPublicKey, verify } from "node:crypto";
|
|
2
|
+
import { blake2b } from "@noble/hashes/blake2.js";
|
|
3
|
+
import { frameSigningBytes } from "./bytes.js";
|
|
4
|
+
const ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
|
|
5
|
+
export function blake2b256(input) {
|
|
6
|
+
return blake2b(input, { dkLen: 32 });
|
|
7
|
+
}
|
|
8
|
+
export function digestFramed(domain, payload) {
|
|
9
|
+
return blake2b256(frameSigningBytes(domain, payload));
|
|
10
|
+
}
|
|
11
|
+
export function verifyEd25519(publicKey, message, signature) {
|
|
12
|
+
if (publicKey.length !== 32 || signature.length !== 64)
|
|
13
|
+
return false;
|
|
14
|
+
const key = createPublicKey({
|
|
15
|
+
key: Buffer.concat([ED25519_SPKI_PREFIX, Buffer.from(publicKey)]),
|
|
16
|
+
format: "der",
|
|
17
|
+
type: "spki",
|
|
18
|
+
});
|
|
19
|
+
return verify(null, message, key, signature);
|
|
20
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type AgentKeypair } from "./keypair.js";
|
|
2
|
+
export interface AgentIdentityFields {
|
|
3
|
+
/** shown at a table and in a replay; up to 32 characters */
|
|
4
|
+
name?: string | null;
|
|
5
|
+
/** unique across the arena and used in a URL; 3-20 of a-z, 0-9, _ */
|
|
6
|
+
handle?: string | null;
|
|
7
|
+
/** one line on the agent's page; up to 50 characters */
|
|
8
|
+
bio?: string | null;
|
|
9
|
+
}
|
|
10
|
+
/** The form the product stores, which is the form the signature covers. */
|
|
11
|
+
export declare function parseIdentityFields(fields: AgentIdentityFields): Required<AgentIdentityFields>;
|
|
12
|
+
/** The exact bytes the owning address signs to name an agent. */
|
|
13
|
+
export declare function canonicalIdentityPayload(edit: {
|
|
14
|
+
agentId: string;
|
|
15
|
+
owner: string;
|
|
16
|
+
fields: AgentIdentityFields;
|
|
17
|
+
issuedAtMs: number;
|
|
18
|
+
expiresAtMs: number;
|
|
19
|
+
}): Uint8Array;
|
|
20
|
+
export interface NameAgentArgs {
|
|
21
|
+
productUrl: string;
|
|
22
|
+
agentId: string;
|
|
23
|
+
/** the address that owns the agent: this key's own, before a claim */
|
|
24
|
+
owner: string;
|
|
25
|
+
agent: AgentKeypair;
|
|
26
|
+
fields: AgentIdentityFields;
|
|
27
|
+
windowMs?: number;
|
|
28
|
+
nowMs?: number;
|
|
29
|
+
fetchImpl?: typeof fetch;
|
|
30
|
+
}
|
|
31
|
+
/** Name an agent, as the address that owns it. Answers what the arena stored. */
|
|
32
|
+
export declare function nameAgent(args: NameAgentArgs): Promise<Required<AgentIdentityFields>>;
|
package/dist/identity.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* Naming an agent: what it is called at a table, signed by the address that
|
|
2
|
+
* owns it.
|
|
3
|
+
*
|
|
4
|
+
* On the self-custody path that address is the agent's own key, so an agent
|
|
5
|
+
* can arrive named rather than playing as "seat 1" until a wallet turns up
|
|
6
|
+
* and names it. After a claim the same route belongs to the claiming wallet,
|
|
7
|
+
* and this key can no longer sign for it -- which is the point of a claim.
|
|
8
|
+
*
|
|
9
|
+
* The payload mirrors `AgentIdentityEdit::canonical_payload` in
|
|
10
|
+
* `backend/dopa-open/product/src/domain/custodial/key_rotation.rs`: every
|
|
11
|
+
* field is length-framed, so "ab"/"c" and "a"/"bc" cannot sign the same
|
|
12
|
+
* bytes. The product parses before it verifies -- it trims each field and
|
|
13
|
+
* lower-cases the handle -- so this signs the parsed form, or the signature
|
|
14
|
+
* is over bytes the store never holds. */
|
|
15
|
+
import { signOwnerAuthenticator } from "./keypair.js";
|
|
16
|
+
const IDENTITY_DOMAIN = "dopa_open::agent_identity::v1";
|
|
17
|
+
/** How long a naming request is good for, unless the caller says otherwise. */
|
|
18
|
+
const DEFAULT_WINDOW_MS = 5 * 60 * 1000;
|
|
19
|
+
/** The form the product stores, which is the form the signature covers. */
|
|
20
|
+
export function parseIdentityFields(fields) {
|
|
21
|
+
return {
|
|
22
|
+
name: fields.name?.trim() || null,
|
|
23
|
+
handle: fields.handle?.trim().toLowerCase() || null,
|
|
24
|
+
bio: fields.bio?.trim() || null,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function u64be(value) {
|
|
28
|
+
const out = new Uint8Array(8);
|
|
29
|
+
new DataView(out.buffer).setBigUint64(0, BigInt(value));
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
function fromHex(value) {
|
|
33
|
+
const hex = value.replace(/^0x/i, "");
|
|
34
|
+
const out = new Uint8Array(hex.length / 2);
|
|
35
|
+
for (let index = 0; index < out.length; index++)
|
|
36
|
+
out[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
/** The exact bytes the owning address signs to name an agent. */
|
|
40
|
+
export function canonicalIdentityPayload(edit) {
|
|
41
|
+
const encoder = new TextEncoder();
|
|
42
|
+
const domain = encoder.encode(IDENTITY_DOMAIN);
|
|
43
|
+
const parsed = parseIdentityFields(edit.fields);
|
|
44
|
+
const parts = [parsed.name ?? "", parsed.handle ?? "", parsed.bio ?? ""].map((field) => encoder.encode(field));
|
|
45
|
+
const chunks = [
|
|
46
|
+
u64be(domain.length),
|
|
47
|
+
domain,
|
|
48
|
+
fromHex(edit.agentId),
|
|
49
|
+
fromHex(edit.owner),
|
|
50
|
+
...parts.flatMap((field) => [u64be(field.length), field]),
|
|
51
|
+
u64be(edit.issuedAtMs),
|
|
52
|
+
u64be(edit.expiresAtMs),
|
|
53
|
+
];
|
|
54
|
+
const out = new Uint8Array(chunks.reduce((total, chunk) => total + chunk.length, 0));
|
|
55
|
+
let offset = 0;
|
|
56
|
+
for (const chunk of chunks) {
|
|
57
|
+
out.set(chunk, offset);
|
|
58
|
+
offset += chunk.length;
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/** Name an agent, as the address that owns it. Answers what the arena stored. */
|
|
63
|
+
export async function nameAgent(args) {
|
|
64
|
+
const fetchImpl = args.fetchImpl ?? fetch;
|
|
65
|
+
const issuedAtMs = args.nowMs ?? Date.now();
|
|
66
|
+
const expiresAtMs = issuedAtMs + (args.windowMs ?? DEFAULT_WINDOW_MS);
|
|
67
|
+
const fields = parseIdentityFields(args.fields);
|
|
68
|
+
const signature = await signOwnerAuthenticator(args.agent, canonicalIdentityPayload({
|
|
69
|
+
agentId: args.agentId,
|
|
70
|
+
owner: args.owner,
|
|
71
|
+
fields,
|
|
72
|
+
issuedAtMs,
|
|
73
|
+
expiresAtMs,
|
|
74
|
+
}));
|
|
75
|
+
const agentId = `0x${args.agentId.replace(/^0x/i, "")}`;
|
|
76
|
+
const response = await fetchImpl(`${args.productUrl.replace(/\/$/, "")}/open/v1/agents/${agentId}/identity`, {
|
|
77
|
+
method: "PUT",
|
|
78
|
+
headers: { "content-type": "application/json" },
|
|
79
|
+
body: JSON.stringify({
|
|
80
|
+
name: fields.name,
|
|
81
|
+
handle: fields.handle,
|
|
82
|
+
bio: fields.bio,
|
|
83
|
+
issuedAtMs,
|
|
84
|
+
expiresAtMs,
|
|
85
|
+
signature,
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
const detail = await response.text().catch(() => "");
|
|
90
|
+
/* Named plainly, because the one refusal a caller meets in practice is a
|
|
91
|
+
handle somebody else already holds, and "409" does not say to pick
|
|
92
|
+
another one. */
|
|
93
|
+
const taken = detail.includes("handle_taken");
|
|
94
|
+
throw new Error(taken
|
|
95
|
+
? `handle "${fields.handle}" belongs to another agent; choose another`
|
|
96
|
+
: `naming refused (${response.status}): ${detail}`);
|
|
97
|
+
}
|
|
98
|
+
const body = (await response.json());
|
|
99
|
+
return parseIdentityFields(body);
|
|
100
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { DEFAULT_KEY_FILE, generateKeypair, keypairFromSeed, loadKeypair, saveKeypair, signOwnerAuthenticator, signRaw, type AgentKeypair, } from "./keypair.js";
|
|
2
|
+
export { deriveAgentId, registerCanonicalPayload, registerPayloadDigest, type RegisterAgentPayload, } from "./registration.js";
|
|
3
|
+
export { canonicalIdentityPayload, nameAgent, parseIdentityFields, type AgentIdentityFields, type NameAgentArgs, } from "./identity.js";
|
|
4
|
+
export { actionSigningBytes, encodeActionFrame, encodeJoinFrame, encodeResumeFrame, joinSigningBytes, resumeSigningBytes, type ActionProposal, type ArtifactReference, type JoinRequest, type ResumeRequest, type SessionContext, } from "./sessionWire.js";
|
|
5
|
+
export { encodeAckFrame, SESSION_ERROR_NAMES, sessionErrorHint, sessionErrorName, } from "./sessionCodec.js";
|
|
6
|
+
export { type OpenTableView, type PlayReport, type SeatDecision, type SeatDecisionResult, type SeatPosition, SessionClient, SessionRefusal, chooseSeatAction, playSeat, } from "./session.js";
|
|
7
|
+
export { cardFromByte, decodeLegalActions, decodeParticipantView, encodeAction, pickAction, type Card, type Rank, type Suit, type TexasAction, type TexasLegalActions, type TexasSeatView, } from "./texas.js";
|
|
8
|
+
export { authorityOriginFromSessionBase, buildConsentRequest, digestForPrompt, recomputeSettlementDigest, settlementConsentPath, verifyConsentDisclosure, } from "./settlement.js";
|
|
9
|
+
export { PACKAGE_NAME, RELEASE_CHANNELS, channelDistTag, installCommand, installSpec, resolveChannel, versionMatchesChannel, type ReleaseChannel, } from "./channel.js";
|
|
10
|
+
export { fromHex, toHex } from "./bytes.js";
|
|
11
|
+
export { AGENT_HTTP_CAPABILITY_HEADER, AGENT_HTTP_CAPABILITY_NONCE_BYTES, MAX_AGENT_HTTP_CAPABILITY_WINDOW_MS, agentHttpCanonicalPayload, agentHttpSigningBytes, decodeAgentHttpHeader, encodeAgentHttpHeader, mintAgentHttpCapability, type AgentHttpBinding, type AgentHttpCapability, } from "./agentHttp.js";
|
|
12
|
+
export { act, enterTour, foldHeavy, playTour, queueUntilSeated, readPosition, type TableMove, type TourClient, type TourEntry, type TourKind, type TurnView, } from "./tour.js";
|
|
13
|
+
export { AGENT_CLAIM_INVITE_DOMAIN, AGENT_CLAIM_INVITE_MAX_WINDOW_MS, AGENT_CLAIM_INVITE_TOKEN_BYTES, claimInviteCanonicalPayload, claimInviteLink, claimInviteSigningBytes, decodeClaimInvite, encodeClaimInvite, mintClaimInvite, type ClaimInvite, } from "./claim.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* @dopamint-fun/open-sdk - the self-custody agent SDK for DOPA-OPEN.
|
|
2
|
+
*
|
|
3
|
+
* Generate and hold an ed25519 keypair (Sui format, `.dopa-keypair`), produce
|
|
4
|
+
* the canonical signatures, and drive the Participant Session against
|
|
5
|
+
* `session_base_url`. Byte parity with the Rust client is pinned by
|
|
6
|
+
* `libs/dopa-open-client-rs/vectors/ts-signer-parity.json`.
|
|
7
|
+
*/
|
|
8
|
+
export { DEFAULT_KEY_FILE, generateKeypair, keypairFromSeed, loadKeypair, saveKeypair, signOwnerAuthenticator, signRaw, } from "./keypair.js";
|
|
9
|
+
export { deriveAgentId, registerCanonicalPayload, registerPayloadDigest, } from "./registration.js";
|
|
10
|
+
export { canonicalIdentityPayload, nameAgent, parseIdentityFields, } from "./identity.js";
|
|
11
|
+
export { actionSigningBytes, encodeActionFrame, encodeJoinFrame, encodeResumeFrame, joinSigningBytes, resumeSigningBytes, } from "./sessionWire.js";
|
|
12
|
+
export { encodeAckFrame, SESSION_ERROR_NAMES, sessionErrorHint, sessionErrorName, } from "./sessionCodec.js";
|
|
13
|
+
export { SessionClient, SessionRefusal, chooseSeatAction, playSeat, } from "./session.js";
|
|
14
|
+
export { cardFromByte, decodeLegalActions, decodeParticipantView, encodeAction, pickAction, } from "./texas.js";
|
|
15
|
+
export { authorityOriginFromSessionBase, buildConsentRequest, digestForPrompt, recomputeSettlementDigest, settlementConsentPath, verifyConsentDisclosure, } from "./settlement.js";
|
|
16
|
+
export { PACKAGE_NAME, RELEASE_CHANNELS, channelDistTag, installCommand, installSpec, resolveChannel, versionMatchesChannel, } from "./channel.js";
|
|
17
|
+
export { fromHex, toHex } from "./bytes.js";
|
|
18
|
+
export { AGENT_HTTP_CAPABILITY_HEADER, AGENT_HTTP_CAPABILITY_NONCE_BYTES, MAX_AGENT_HTTP_CAPABILITY_WINDOW_MS, agentHttpCanonicalPayload, agentHttpSigningBytes, decodeAgentHttpHeader, encodeAgentHttpHeader, mintAgentHttpCapability, } from "./agentHttp.js";
|
|
19
|
+
export { act, enterTour, foldHeavy, playTour, queueUntilSeated, readPosition, } from "./tour.js";
|
|
20
|
+
/* The agent's half of a claim: an invitation its own key signs, carried as a
|
|
21
|
+
token in the claim link its operator hands the owner. */
|
|
22
|
+
export { AGENT_CLAIM_INVITE_DOMAIN, AGENT_CLAIM_INVITE_MAX_WINDOW_MS, AGENT_CLAIM_INVITE_TOKEN_BYTES, claimInviteCanonicalPayload, claimInviteLink, claimInviteSigningBytes, decodeClaimInvite, encodeClaimInvite, mintClaimInvite, } from "./claim.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
|
|
2
|
+
export declare const DEFAULT_KEY_FILE = ".dopa-keypair";
|
|
3
|
+
export interface AgentKeypair {
|
|
4
|
+
keypair: Ed25519Keypair;
|
|
5
|
+
/** the ed25519 verifying key, 32 bytes - `agent_public_key` at registration */
|
|
6
|
+
publicKey: Uint8Array;
|
|
7
|
+
/** the derived Sui address bytes, 32 bytes - `owner` under path A custody */
|
|
8
|
+
ownerAddress: Uint8Array;
|
|
9
|
+
/** the same address, 0x-prefixed, for anything that prints it */
|
|
10
|
+
ownerAddressHex: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function generateKeypair(): AgentKeypair;
|
|
13
|
+
/** For tests and vectors: the deterministic keypair for a 32-byte seed. */
|
|
14
|
+
export declare function keypairFromSeed(seed: Uint8Array): AgentKeypair;
|
|
15
|
+
/** Write the key file: one `suiprivkey...` line, owner-readable only. The
|
|
16
|
+
* format is Sui's own bech32, so every ecosystem tool that understands a Sui
|
|
17
|
+
* key understands this file. */
|
|
18
|
+
export declare function saveKeypair(agent: AgentKeypair, path?: string): void;
|
|
19
|
+
export declare function loadKeypair(path?: string): AgentKeypair;
|
|
20
|
+
/** Raw ed25519 over a canonical preimage - the session signatures. */
|
|
21
|
+
export declare function signRaw(agent: AgentKeypair, preimage: Uint8Array): Promise<Uint8Array>;
|
|
22
|
+
/** The registration authenticator: a Sui personal-message signature over the
|
|
23
|
+
* canonical payload, base64-serialized the way `UserSignature::from_base64`
|
|
24
|
+
* expects. The product checks the embedded public key derives `owner`. */
|
|
25
|
+
export declare function signOwnerAuthenticator(agent: AgentKeypair, canonicalPayload: Uint8Array): Promise<string>;
|
package/dist/keypair.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* The agent's own key: generate it, keep it, and sign with it.
|
|
2
|
+
*
|
|
3
|
+
* One Sui-format ed25519 keypair serves as both the allocating identity (its
|
|
4
|
+
* derived address is `owner`, and it signs the registration as a personal
|
|
5
|
+
* message) and the generation-1 action key (it signs session messages raw
|
|
6
|
+
* over the arena-session framings). Domain separation in the framings keeps
|
|
7
|
+
* the two roles apart. Note for rotation later: the original key remains the
|
|
8
|
+
* owner forever - `owner` is hashed into the agent id - even after the action
|
|
9
|
+
* key rotates to a new generation.
|
|
10
|
+
*
|
|
11
|
+
* The key file is `.dopa-keypair`, not `.dopa-credentials`. A bearer
|
|
12
|
+
* credential is per-deployment and server-revocable; a private key is
|
|
13
|
+
* portable and agent-owned. One file carrying both semantics is how one ends
|
|
14
|
+
* up pasted into the other's slot.
|
|
15
|
+
*/
|
|
16
|
+
import { chmodSync, readFileSync, writeFileSync } from "node:fs";
|
|
17
|
+
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
|
|
18
|
+
import { decodeSuiPrivateKey } from "@mysten/sui/cryptography";
|
|
19
|
+
import { fromHex } from "./bytes.js";
|
|
20
|
+
export const DEFAULT_KEY_FILE = ".dopa-keypair";
|
|
21
|
+
function describe(keypair) {
|
|
22
|
+
const address = keypair.getPublicKey().toSuiAddress();
|
|
23
|
+
return {
|
|
24
|
+
keypair,
|
|
25
|
+
publicKey: keypair.getPublicKey().toRawBytes(),
|
|
26
|
+
ownerAddress: fromHex(address.replace(/^0x/, "")),
|
|
27
|
+
ownerAddressHex: address,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function generateKeypair() {
|
|
31
|
+
return describe(new Ed25519Keypair());
|
|
32
|
+
}
|
|
33
|
+
/** For tests and vectors: the deterministic keypair for a 32-byte seed. */
|
|
34
|
+
export function keypairFromSeed(seed) {
|
|
35
|
+
return describe(Ed25519Keypair.fromSecretKey(seed));
|
|
36
|
+
}
|
|
37
|
+
/** Write the key file: one `suiprivkey...` line, owner-readable only. The
|
|
38
|
+
* format is Sui's own bech32, so every ecosystem tool that understands a Sui
|
|
39
|
+
* key understands this file. */
|
|
40
|
+
export function saveKeypair(agent, path = DEFAULT_KEY_FILE) {
|
|
41
|
+
writeFileSync(path, `${agent.keypair.getSecretKey()}\n`, { mode: 0o600 });
|
|
42
|
+
// mode on writeFileSync only applies at creation; an existing file keeps
|
|
43
|
+
// its bits, so tighten explicitly rather than trusting the happy path
|
|
44
|
+
chmodSync(path, 0o600);
|
|
45
|
+
}
|
|
46
|
+
export function loadKeypair(path = DEFAULT_KEY_FILE) {
|
|
47
|
+
const line = readFileSync(path, "utf8").trim();
|
|
48
|
+
if (line.startsWith("suiprivkey")) {
|
|
49
|
+
const decoded = decodeSuiPrivateKey(line);
|
|
50
|
+
if (decoded.scheme !== "ED25519")
|
|
51
|
+
throw new Error(`expected an ed25519 key in ${path}, found ${decoded.scheme}`);
|
|
52
|
+
return describe(Ed25519Keypair.fromSecretKey(decoded.secretKey));
|
|
53
|
+
}
|
|
54
|
+
const seed = fromHex(line.startsWith("0x") ? line.slice(2) : line);
|
|
55
|
+
if (seed.length !== 32)
|
|
56
|
+
throw new Error(`${path} must be a suiprivkey line or a 32-byte hex seed`);
|
|
57
|
+
return keypairFromSeed(seed);
|
|
58
|
+
}
|
|
59
|
+
/** Raw ed25519 over a canonical preimage - the session signatures. */
|
|
60
|
+
export async function signRaw(agent, preimage) {
|
|
61
|
+
return agent.keypair.sign(preimage);
|
|
62
|
+
}
|
|
63
|
+
/** The registration authenticator: a Sui personal-message signature over the
|
|
64
|
+
* canonical payload, base64-serialized the way `UserSignature::from_base64`
|
|
65
|
+
* expects. The product checks the embedded public key derives `owner`. */
|
|
66
|
+
export async function signOwnerAuthenticator(agent, canonicalPayload) {
|
|
67
|
+
const { signature } = await agent.keypair.signPersonalMessage(canonicalPayload);
|
|
68
|
+
return signature;
|
|
69
|
+
}
|
package/dist/offer.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AgentKeypair } from "./keypair.js";
|
|
2
|
+
export interface OfferSeat {
|
|
3
|
+
seat: number;
|
|
4
|
+
agentId: string;
|
|
5
|
+
keyGeneration: number;
|
|
6
|
+
agentPublicKey: string;
|
|
7
|
+
}
|
|
8
|
+
export interface OfferRecord {
|
|
9
|
+
state: string;
|
|
10
|
+
seats: OfferSeat[];
|
|
11
|
+
acceptedSeats: number[];
|
|
12
|
+
admission?: {
|
|
13
|
+
sessionBaseUrl: string;
|
|
14
|
+
coordinatorPublicKey: string;
|
|
15
|
+
timeAuthorityPublicKey?: string;
|
|
16
|
+
executionId: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export declare function readOffer(productUrl: string, offerId: string): Promise<OfferRecord>;
|
|
20
|
+
/** Sign and submit this seat's acceptance. Already-accepted is not an error:
|
|
21
|
+
* a retry after a lost response must not strand the seat. */
|
|
22
|
+
export declare function acceptOffer(productUrl: string, offerId: string, seat: OfferSeat, agent: AgentKeypair): Promise<void>;
|
|
23
|
+
export interface AdmittedSeat {
|
|
24
|
+
seat: number;
|
|
25
|
+
coordinatorKey: Uint8Array;
|
|
26
|
+
timeAuthorityKey: Uint8Array;
|
|
27
|
+
executionId: string;
|
|
28
|
+
}
|
|
29
|
+
export interface AwaitOptions {
|
|
30
|
+
pollMs?: number;
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
onWaiting?: (accepted: number, total: number) => void;
|
|
33
|
+
}
|
|
34
|
+
/** Accept this agent's seat, then wait for the offer to admit, admitting it
|
|
35
|
+
* as soon as every seat has accepted. */
|
|
36
|
+
export declare function acceptAndAwaitAdmission(productUrl: string, offerId: string, agentId: Uint8Array, agent: AgentKeypair, options?: AwaitOptions): Promise<AdmittedSeat>;
|
package/dist/offer.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/* Taking a composed playground offer to a seat this agent can play.
|
|
2
|
+
*
|
|
3
|
+
* The queue pairs strangers and composes the offer; it stops there, because
|
|
4
|
+
* the acceptance and every later session frame have to be signed by a key the
|
|
5
|
+
* platform does not hold. So the three steps below are the agent's, not the
|
|
6
|
+
* product's: read the offer, accept it, and admit it once every seat has.
|
|
7
|
+
*
|
|
8
|
+
* `admit` is deliberately shared rather than assigned to one seat. Whoever
|
|
9
|
+
* gets there first admits and everybody reads the same admission back, which
|
|
10
|
+
* means no seat is load-bearing for the others - an agent that accepted and
|
|
11
|
+
* then died does not strand the table before it starts. The POST carries a
|
|
12
|
+
* freshly minted `AgentHttpCapability`; knowing the offer id is not enough.
|
|
13
|
+
*/
|
|
14
|
+
import { signOfferAcceptance } from "./acceptance.js";
|
|
15
|
+
import { AGENT_HTTP_CAPABILITY_HEADER, mintAgentHttpCapability, } from "./agentHttp.js";
|
|
16
|
+
import { fromHex, toHex } from "./bytes.js";
|
|
17
|
+
import { randomBytes } from "node:crypto";
|
|
18
|
+
const hexBytes = (value) => fromHex(value.replace(/^0x/, ""));
|
|
19
|
+
async function readJson(url, init) {
|
|
20
|
+
const response = await fetch(url, init);
|
|
21
|
+
const text = await response.text();
|
|
22
|
+
return {
|
|
23
|
+
status: response.status,
|
|
24
|
+
json: text.length === 0 ? undefined : JSON.parse(text),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function record(raw) {
|
|
28
|
+
const seats = (raw?.offer?.seats ?? []).map((seat) => ({
|
|
29
|
+
seat: seat.seat,
|
|
30
|
+
agentId: seat.agent_id ?? seat.agentId,
|
|
31
|
+
keyGeneration: seat.key_generation ?? seat.keyGeneration,
|
|
32
|
+
agentPublicKey: seat.agent_public_key ?? seat.agentPublicKey,
|
|
33
|
+
}));
|
|
34
|
+
const admissionRaw = raw?.admission;
|
|
35
|
+
return {
|
|
36
|
+
state: raw?.state,
|
|
37
|
+
seats,
|
|
38
|
+
acceptedSeats: (raw?.acceptances ?? []).map((entry) => entry.seat),
|
|
39
|
+
admission: admissionRaw
|
|
40
|
+
? {
|
|
41
|
+
sessionBaseUrl: admissionRaw.session_base_url ?? admissionRaw.sessionBaseUrl,
|
|
42
|
+
coordinatorPublicKey: admissionRaw.coordinator_public_key ??
|
|
43
|
+
admissionRaw.coordinatorPublicKey,
|
|
44
|
+
timeAuthorityPublicKey: admissionRaw.time_authority_public_key ??
|
|
45
|
+
admissionRaw.timeAuthorityPublicKey ??
|
|
46
|
+
undefined,
|
|
47
|
+
executionId: admissionRaw.execution_id ?? admissionRaw.executionId,
|
|
48
|
+
}
|
|
49
|
+
: undefined,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export async function readOffer(productUrl, offerId) {
|
|
53
|
+
const { status, json } = await readJson(`${productUrl.replace(/\/$/, "")}/open/v1/playground/matches/${offerId}`);
|
|
54
|
+
if (status !== 200)
|
|
55
|
+
throw new Error(`offer read refused (${status}): ${JSON.stringify(json)}`);
|
|
56
|
+
return record(json);
|
|
57
|
+
}
|
|
58
|
+
/** Sign and submit this seat's acceptance. Already-accepted is not an error:
|
|
59
|
+
* a retry after a lost response must not strand the seat. */
|
|
60
|
+
export async function acceptOffer(productUrl, offerId, seat, agent) {
|
|
61
|
+
const acceptance = {
|
|
62
|
+
offerId: hexBytes(offerId),
|
|
63
|
+
seat: seat.seat,
|
|
64
|
+
agentId: hexBytes(seat.agentId),
|
|
65
|
+
keyGeneration: seat.keyGeneration,
|
|
66
|
+
agentPublicKey: hexBytes(seat.agentPublicKey),
|
|
67
|
+
accepted: true,
|
|
68
|
+
acceptanceNonce: new Uint8Array(randomBytes(32)),
|
|
69
|
+
};
|
|
70
|
+
const signed = await signOfferAcceptance(agent, acceptance);
|
|
71
|
+
const body = JSON.stringify({
|
|
72
|
+
offer_id: offerId,
|
|
73
|
+
seat: signed.seat,
|
|
74
|
+
agent_id: seat.agentId,
|
|
75
|
+
key_generation: signed.keyGeneration,
|
|
76
|
+
agent_public_key: seat.agentPublicKey,
|
|
77
|
+
accepted: true,
|
|
78
|
+
acceptance_nonce: Array.from(signed.acceptanceNonce),
|
|
79
|
+
signature: Array.from(signed.signature),
|
|
80
|
+
});
|
|
81
|
+
const { status, json } = await readJson(`${productUrl.replace(/\/$/, "")}/open/v1/playground/matches/${offerId}/acceptances`, { method: "POST", headers: { "content-type": "application/json" }, body });
|
|
82
|
+
if (status === 200 || status === 201)
|
|
83
|
+
return;
|
|
84
|
+
if (status === 409)
|
|
85
|
+
return;
|
|
86
|
+
throw new Error(`acceptance refused (${status}): ${JSON.stringify(json)}`);
|
|
87
|
+
}
|
|
88
|
+
async function admit(productUrl, offerId, agentId, agent) {
|
|
89
|
+
const target = `/open/v1/playground/matches/${offerId}/admit`;
|
|
90
|
+
const { header } = await mintAgentHttpCapability(agent, agentId, {
|
|
91
|
+
method: "POST",
|
|
92
|
+
requestTarget: target,
|
|
93
|
+
body: new Uint8Array(),
|
|
94
|
+
});
|
|
95
|
+
const { status, json } = await readJson(`${productUrl.replace(/\/$/, "")}${target}`, { method: "POST", headers: { [AGENT_HTTP_CAPABILITY_HEADER]: header } });
|
|
96
|
+
// A seat that raced another to admit is not in trouble; the offer is admitted
|
|
97
|
+
// either way, and the next read returns the same admission.
|
|
98
|
+
if (status === 200 || status === 201 || status === 409)
|
|
99
|
+
return;
|
|
100
|
+
throw new Error(`admit refused (${status}): ${JSON.stringify(json)}`);
|
|
101
|
+
}
|
|
102
|
+
/** Accept this agent's seat, then wait for the offer to admit, admitting it
|
|
103
|
+
* as soon as every seat has accepted. */
|
|
104
|
+
export async function acceptAndAwaitAdmission(productUrl, offerId, agentId, agent, options = {}) {
|
|
105
|
+
const pollMs = options.pollMs ?? 2_000;
|
|
106
|
+
const deadline = Date.now() + (options.timeoutMs ?? 300_000);
|
|
107
|
+
const wanted = `0x${toHex(agentId)}`;
|
|
108
|
+
let offer = await readOffer(productUrl, offerId);
|
|
109
|
+
const mine = offer.seats.find((seat) => seat.agentId.toLowerCase() === wanted.toLowerCase());
|
|
110
|
+
if (!mine)
|
|
111
|
+
throw new Error(`offer ${offerId} holds no seat for ${wanted}`);
|
|
112
|
+
if (!offer.acceptedSeats.includes(mine.seat))
|
|
113
|
+
await acceptOffer(productUrl, offerId, mine, agent);
|
|
114
|
+
for (;;) {
|
|
115
|
+
offer = await readOffer(productUrl, offerId);
|
|
116
|
+
if (offer.admission) {
|
|
117
|
+
const { coordinatorPublicKey, timeAuthorityPublicKey, executionId } = offer.admission;
|
|
118
|
+
if (!timeAuthorityPublicKey)
|
|
119
|
+
throw new Error("the admission carried no time-authority key; this seat cannot authenticate arrival evidence");
|
|
120
|
+
return {
|
|
121
|
+
seat: mine.seat,
|
|
122
|
+
coordinatorKey: hexBytes(coordinatorPublicKey),
|
|
123
|
+
timeAuthorityKey: hexBytes(timeAuthorityPublicKey),
|
|
124
|
+
executionId,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (offer.acceptedSeats.length >= offer.seats.length) {
|
|
128
|
+
await admit(productUrl, offerId, agentId, agent);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (offer.state === "cancelled" || offer.state === "declined")
|
|
132
|
+
throw new Error(`the offer is ${offer.state}`);
|
|
133
|
+
options.onWaiting?.(offer.acceptedSeats.length, offer.seats.length);
|
|
134
|
+
if (Date.now() >= deadline)
|
|
135
|
+
throw new Error(`offer ${offerId} did not admit; ${offer.acceptedSeats.length} of ${offer.seats.length} seats accepted`);
|
|
136
|
+
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Blake2b-256(domain, owner, nonce) - `AgentId::derive` in Rust. */
|
|
2
|
+
export declare function deriveAgentId(owner: Uint8Array, allocationNonce: Uint8Array): Uint8Array;
|
|
3
|
+
export interface RegisterAgentPayload {
|
|
4
|
+
/** 32 bytes; must equal deriveAgentId(owner, allocationNonce) */
|
|
5
|
+
agentId: Uint8Array;
|
|
6
|
+
/** 32 bytes */
|
|
7
|
+
allocationNonce: Uint8Array;
|
|
8
|
+
/** 32 bytes */
|
|
9
|
+
owner: Uint8Array;
|
|
10
|
+
/** 32 bytes - the ed25519 verifying key that will sign session messages */
|
|
11
|
+
agentPublicKey: Uint8Array;
|
|
12
|
+
/** each list strictly ascending, at least one entry */
|
|
13
|
+
productApiVersions: number[];
|
|
14
|
+
participantSessionVersions: number[];
|
|
15
|
+
protocolVersions: number[];
|
|
16
|
+
/** 32 bytes */
|
|
17
|
+
metadataCommitment: Uint8Array;
|
|
18
|
+
createdAtMs: number | bigint;
|
|
19
|
+
expiresAtMs?: number | bigint | null;
|
|
20
|
+
}
|
|
21
|
+
/** `RegisterAgentRequest::canonical_payload` - the bytes the owner signs as a
|
|
22
|
+
* Sui personal message. */
|
|
23
|
+
export declare function registerCanonicalPayload(payload: RegisterAgentPayload): Uint8Array;
|
|
24
|
+
/** Blake2b-256 of the canonical payload - `payload_digest` in Rust. */
|
|
25
|
+
export declare function registerPayloadDigest(payload: RegisterAgentPayload): Uint8Array;
|
|
26
|
+
/** What a rotation binds: the agent, the generation it replaces, and the key
|
|
27
|
+
* that takes over. */
|
|
28
|
+
export interface RotateAgentKeyPayload {
|
|
29
|
+
agentId: Uint8Array;
|
|
30
|
+
owner: Uint8Array;
|
|
31
|
+
/** the generation the caller believes is current, refused when it is not */
|
|
32
|
+
expectedCurrentGeneration: number;
|
|
33
|
+
predecessorAuthorizationDigest: Uint8Array;
|
|
34
|
+
nextAgentPublicKey: Uint8Array;
|
|
35
|
+
issuedAtMs: number | bigint;
|
|
36
|
+
expiresAtMs: number | bigint;
|
|
37
|
+
}
|
|
38
|
+
/** `RotateAgentKeyRequest::canonical_payload` — the bytes the key holder signs
|
|
39
|
+
* as a Sui personal message. */
|
|
40
|
+
export declare function rotateCanonicalPayload(payload: RotateAgentKeyPayload): Uint8Array;
|
|
41
|
+
/** What a retirement binds. No successor key: nothing follows a retirement. */
|
|
42
|
+
export interface RevokeAgentPayload {
|
|
43
|
+
agentId: Uint8Array;
|
|
44
|
+
owner: Uint8Array;
|
|
45
|
+
expectedCurrentGeneration: number;
|
|
46
|
+
predecessorAuthorizationDigest: Uint8Array;
|
|
47
|
+
issuedAtMs: number | bigint;
|
|
48
|
+
expiresAtMs: number | bigint;
|
|
49
|
+
}
|
|
50
|
+
/** `RevokeAgentRequest::canonical_payload`. Same shape as a rotation without
|
|
51
|
+
* the successor, and a different domain and operation tag -- so a signature
|
|
52
|
+
* taken for one cannot be replayed as the other. */
|
|
53
|
+
export declare function revokeCanonicalPayload(payload: RevokeAgentPayload): Uint8Array;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* The registration canonical payload and the agent identity it binds,
|
|
2
|
+
* byte-identical to `dopa_open_api`.
|
|
3
|
+
*
|
|
4
|
+
* Path A custody: the agent allocates itself. The address derived from its
|
|
5
|
+
* own key is the `owner`, so the same key both authorizes the registration
|
|
6
|
+
* (as a Sui personal-message signature the product verifies with
|
|
7
|
+
* `verify_owner_authenticator`) and later signs every session message. The
|
|
8
|
+
* agent id is a Blake2b-256 over the owner and an allocation nonce - `owner`
|
|
9
|
+
* is hashed into the identity, which is why it can never be rewritten and why
|
|
10
|
+
* claim-later binds a human separately.
|
|
11
|
+
*/
|
|
12
|
+
import { blake2b } from "@noble/hashes/blake2.js";
|
|
13
|
+
import { ByteWriter, textBytes } from "./bytes.js";
|
|
14
|
+
const AGENT_ID_DOMAIN = textBytes("dopa_open::agent_id::v1");
|
|
15
|
+
const REGISTER_DOMAIN = textBytes("dopa_open::registration::v1");
|
|
16
|
+
const CANONICAL_WIRE_VERSION = 1;
|
|
17
|
+
const REGISTER_OPERATION = 1;
|
|
18
|
+
const ROTATE_DOMAIN = textBytes("dopa_open::key_rotation::v1");
|
|
19
|
+
const ROTATE_OPERATION = 2;
|
|
20
|
+
const REVOKE_DOMAIN = textBytes("dopa_open::revocation::v1");
|
|
21
|
+
const REVOKE_OPERATION = 3;
|
|
22
|
+
/** Blake2b-256(domain, owner, nonce) - `AgentId::derive` in Rust. */
|
|
23
|
+
export function deriveAgentId(owner, allocationNonce) {
|
|
24
|
+
if (owner.length !== 32)
|
|
25
|
+
throw new Error("owner must be 32 bytes");
|
|
26
|
+
if (allocationNonce.length !== 32)
|
|
27
|
+
throw new Error("allocation nonce must be 32 bytes");
|
|
28
|
+
const input = new Uint8Array(AGENT_ID_DOMAIN.length + owner.length + allocationNonce.length);
|
|
29
|
+
input.set(AGENT_ID_DOMAIN, 0);
|
|
30
|
+
input.set(owner, AGENT_ID_DOMAIN.length);
|
|
31
|
+
input.set(allocationNonce, AGENT_ID_DOMAIN.length + owner.length);
|
|
32
|
+
return blake2b(input, { dkLen: 32 });
|
|
33
|
+
}
|
|
34
|
+
function pushVersions(writer, versions) {
|
|
35
|
+
if (versions.length === 0 || versions.length > 0xff)
|
|
36
|
+
throw new Error("version list must hold 1 to 255 entries");
|
|
37
|
+
writer.pushByte(versions.length);
|
|
38
|
+
for (const version of versions)
|
|
39
|
+
writer.pushU16(version);
|
|
40
|
+
}
|
|
41
|
+
/** `RegisterAgentRequest::canonical_payload` - the bytes the owner signs as a
|
|
42
|
+
* Sui personal message. */
|
|
43
|
+
export function registerCanonicalPayload(payload) {
|
|
44
|
+
const writer = new ByteWriter()
|
|
45
|
+
.pushBytes(REGISTER_DOMAIN)
|
|
46
|
+
.pushByte(0)
|
|
47
|
+
.pushByte(CANONICAL_WIRE_VERSION)
|
|
48
|
+
.pushByte(REGISTER_OPERATION)
|
|
49
|
+
.pushFixed(payload.agentId, 32, "agent id")
|
|
50
|
+
.pushFixed(payload.allocationNonce, 32, "allocation nonce")
|
|
51
|
+
.pushFixed(payload.owner, 32, "owner")
|
|
52
|
+
.pushFixed(payload.agentPublicKey, 32, "agent public key");
|
|
53
|
+
pushVersions(writer, payload.productApiVersions);
|
|
54
|
+
pushVersions(writer, payload.participantSessionVersions);
|
|
55
|
+
pushVersions(writer, payload.protocolVersions);
|
|
56
|
+
writer
|
|
57
|
+
.pushFixed(payload.metadataCommitment, 32, "metadata commitment")
|
|
58
|
+
.pushU64(payload.createdAtMs);
|
|
59
|
+
if (payload.expiresAtMs === undefined || payload.expiresAtMs === null) {
|
|
60
|
+
writer.pushByte(0);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
writer.pushByte(1).pushU64(payload.expiresAtMs);
|
|
64
|
+
}
|
|
65
|
+
return writer.bytes();
|
|
66
|
+
}
|
|
67
|
+
/** Blake2b-256 of the canonical payload - `payload_digest` in Rust. */
|
|
68
|
+
export function registerPayloadDigest(payload) {
|
|
69
|
+
return blake2b(registerCanonicalPayload(payload), { dkLen: 32 });
|
|
70
|
+
}
|
|
71
|
+
/** `RotateAgentKeyRequest::canonical_payload` — the bytes the key holder signs
|
|
72
|
+
* as a Sui personal message. */
|
|
73
|
+
export function rotateCanonicalPayload(payload) {
|
|
74
|
+
return new ByteWriter()
|
|
75
|
+
.pushBytes(ROTATE_DOMAIN)
|
|
76
|
+
.pushByte(0)
|
|
77
|
+
.pushByte(CANONICAL_WIRE_VERSION)
|
|
78
|
+
.pushByte(ROTATE_OPERATION)
|
|
79
|
+
.pushFixed(payload.agentId, 32, "agent id")
|
|
80
|
+
.pushFixed(payload.owner, 32, "owner")
|
|
81
|
+
.pushU32(payload.expectedCurrentGeneration)
|
|
82
|
+
.pushFixed(payload.predecessorAuthorizationDigest, 32, "predecessor authorization digest")
|
|
83
|
+
.pushFixed(payload.nextAgentPublicKey, 32, "next agent public key")
|
|
84
|
+
.pushU64(payload.issuedAtMs)
|
|
85
|
+
.pushU64(payload.expiresAtMs)
|
|
86
|
+
.bytes();
|
|
87
|
+
}
|
|
88
|
+
/** `RevokeAgentRequest::canonical_payload`. Same shape as a rotation without
|
|
89
|
+
* the successor, and a different domain and operation tag -- so a signature
|
|
90
|
+
* taken for one cannot be replayed as the other. */
|
|
91
|
+
export function revokeCanonicalPayload(payload) {
|
|
92
|
+
return new ByteWriter()
|
|
93
|
+
.pushBytes(REVOKE_DOMAIN)
|
|
94
|
+
.pushByte(0)
|
|
95
|
+
.pushByte(CANONICAL_WIRE_VERSION)
|
|
96
|
+
.pushByte(REVOKE_OPERATION)
|
|
97
|
+
.pushFixed(payload.agentId, 32, "agent id")
|
|
98
|
+
.pushFixed(payload.owner, 32, "owner")
|
|
99
|
+
.pushU32(payload.expectedCurrentGeneration)
|
|
100
|
+
.pushFixed(payload.predecessorAuthorizationDigest, 32, "predecessor authorization digest")
|
|
101
|
+
.pushU64(payload.issuedAtMs)
|
|
102
|
+
.pushU64(payload.expiresAtMs)
|
|
103
|
+
.bytes();
|
|
104
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ArtifactReference } from "./sessionWire.js";
|
|
2
|
+
export declare const DOPA_OPEN_COORDINATOR_ROLE: Uint8Array<ArrayBuffer>;
|
|
3
|
+
export declare const DOPA_OPEN_TIME_AUTHORITY_ROLE: Uint8Array<ArrayBuffer>;
|
|
4
|
+
export declare function seatGenerationDigest(generation?: number): Uint8Array;
|
|
5
|
+
export declare function roleGenerationDigest(role: Uint8Array): Uint8Array;
|
|
6
|
+
export declare function coordinatorGenerationDigest(): Uint8Array;
|
|
7
|
+
export declare function timeAuthorityGenerationDigest(): Uint8Array;
|
|
8
|
+
export declare function transitionProofSigningBytes(payload: Uint8Array, principal: Uint8Array, generation: Uint8Array, scheme?: number): Uint8Array;
|
|
9
|
+
export interface PendingProposal {
|
|
10
|
+
actionId: Uint8Array;
|
|
11
|
+
actionPayload: Uint8Array;
|
|
12
|
+
signingBytes: Uint8Array;
|
|
13
|
+
expectedStateNonce: bigint;
|
|
14
|
+
expectedStateCommitment: Uint8Array;
|
|
15
|
+
participantDeadlineMs: bigint;
|
|
16
|
+
payloadSchemaVersion: number;
|
|
17
|
+
executionId: Uint8Array;
|
|
18
|
+
protocolId: Uint8Array;
|
|
19
|
+
protocolVersion: number;
|
|
20
|
+
artifactReferences: ArtifactReference[];
|
|
21
|
+
}
|
|
22
|
+
export declare function authorizeSeatChallenge(args: {
|
|
23
|
+
seat: number;
|
|
24
|
+
coordinatorPublicKey: Uint8Array;
|
|
25
|
+
challengeCoordinatorKey: Uint8Array;
|
|
26
|
+
coordinatorProof: Uint8Array;
|
|
27
|
+
authorizationPayload: Uint8Array;
|
|
28
|
+
timeAuthorityPublicKey: Uint8Array;
|
|
29
|
+
pending: PendingProposal;
|
|
30
|
+
}): Uint8Array;
|