Ed25519
Seams preserves the standard seed-derived Ed25519 identity so an explicitly exported key reproduces the registered public key:
d = LE32(y_client + y_server mod 2^256)
h = SHA-512(d)
a = clamp(h[0..32]) mod lThe lifecycle protocol computes this relation through Streaming Yao A/B. Deriver A and Deriver B receive separate client and server contributions. Neither role learns the joined d, a, client signing output, or server signing output.
Lifecycle and signing
Registration, recovery, signing-share refresh, SigningWorker activation, authorized export, and new-recipient share provisioning use the lifecycle protocol. Normal transaction, message, and delegate-action signing uses the already-activated threshold session:
Client -> Router -> SigningWorker -> Router -> ClientNormal signing performs zero Yao work and makes zero Deriver calls. A presign pool hit takes one client-to-Router request and response. A pool miss uses a prepare request followed by the final signing request.
Export invariant
Export is a distinct, freshly authorized ceremony. The client receives two seed shares encrypted to it. It reconstructs d and derives the Ed25519 public key. It must verify that this matches the registered public key before displaying the exported key in the wallet-origin viewer. The app receives only an export outcome.
Ordinary activation circuits have no seed-output branch. Recovery cannot reuse the export request shape.
Sign a NEAR transaction
Application code supplies the exact wallet session, NEAR account, receiver, and actions. The SDK routes the request through the active Ed25519 signing lane.
Runnable React and TypeScript example
import {
functionCall,
logWalletEvents,
TxExecutionStatus,
useSeams,
type BoundNearSigner,
} from '@seams/wallet/react';
async function signGreeting(near: BoundNearSigner): Promise<void> {
await near.signAndSendTransaction({
receiverId: 'guest-book.testnet',
actions: [functionCall({ method: 'set_greeting', args: { greeting: 'Hello from Seams' } })],
options: {
waitUntil: TxExecutionStatus.EXECUTED_OPTIMISTIC,
onEvent: logWalletEvents(),
},
});
}
export function SetGreetingButton() {
const { wallet } = useSeams();
if (wallet?.access !== 'wallet' || !wallet.near) return null;
// Each request opens wallet confirmation for this transaction.
return <button onClick={signGreeting.bind(null, wallet.near)}>Sign transaction</button>;
}