Mysten Incubation
Reference

Signing Flow

How It Works

sequenceDiagram
    participant dApp
    participant DevWallet
    participant UI
    participant Adapter

    dApp->>DevWallet: signTransaction(tx)
    DevWallet->>DevWallet: Check auto-approve policy

    alt Auto-approved
        DevWallet->>Adapter: Sign with signer
        Adapter-->>DevWallet: Signature
        DevWallet-->>dApp: Result
    else Manual approval required
        DevWallet->>UI: Show signing modal
        UI->>UI: User reviews transaction
        alt User approves
            UI->>DevWallet: approveRequest()
            DevWallet->>Adapter: Sign with signer
            Adapter-->>DevWallet: Signature
            DevWallet-->>dApp: Result
        else User rejects
            UI->>DevWallet: rejectRequest()
            DevWallet-->>dApp: Error
        end
    end

One Request at a Time

The wallet processes one signing request at a time. If a second request arrives while one is pending, it's immediately rejected with "A signing request is already pending."

dApps that send multiple transactions should serialize their signing calls — await each one before sending the next.

Request Types

TypeTriggered ByData
sign-transactionsui:signTransactionTransaction JSON string
sign-and-execute-transactionsui:signAndExecuteTransactionTransaction JSON string
sign-personal-messagesui:signPersonalMessageUint8Array message bytes

The Signing Modal

Signing modal showing approval required with message details

Try It

Click the button to trigger a signing request, then open the wallet panel to approve or reject it:

Loading demo...

Programmatic Approval

You can approve or reject requests without the UI — useful for testing:

// Enqueue a request (returns a Promise)
const resultPromise = wallet.features['sui:signPersonalMessage'].signPersonalMessage({
	message: new TextEncoder().encode('Hello'),
	account: wallet.accounts[0],
});

// Check the pending request
console.log(wallet.pendingRequest);
// { id: '...', type: 'sign-personal-message', account: ..., data: Uint8Array }

// Approve it
await wallet.approveRequest();

// The promise resolves
const result = await resultPromise;
console.log(result.signature);

Rejecting a Request

wallet.rejectRequest('User declined');
// The promise rejects with Error('User declined')

Subscribing to Request Changes

const unsubscribe = wallet.onRequestChange((request) => {
	if (request) {
		console.log('New request:', request.type, request.id);
	} else {
		console.log('Request resolved');
	}
});

// Later: unsubscribe()

Connect Approval

Connect requests follow the same pattern: auto-connect if autoConnect: true, otherwise queue a connect request so the user can select which accounts to expose.

Connect dialog showing wallet picker with Dev Wallet option

// Subscribe to connect requests
wallet.onConnectChange((request) => {
	if (request) {
		// Show account picker
	}
});

// Approve with selected addresses
wallet.approveConnect(['0xabc...', '0xdef...']);

// Or reject
wallet.rejectConnect('User cancelled');

Transaction Analysis

The signing modal analyzes transaction commands and displays:

  • MoveCall — package, module, function, and arguments
  • TransferObjects — recipient address and objects being transferred
  • SplitCoins — coin type and split amounts
  • MergeCoins — coins being merged

On this page