署名
署名呼び出しは、認証済みウォレットを自動的に特定します。 アプリが複数のウォレットやチェーンを扱う場合は、対象を明示してください。 以下の実装例は進行状況のイベントを通知するため、署名処理の状態をUIに表示できます。
前提条件
設定済みのSeamsWebProviderと、サインイン済みのウォレットが必要です。 まだロック中の場合は、ウォレットの設定と認証を参照してください。
署名に個別のアンロック手順は必要ありません。 各リクエストでウォレットの確認画面が開き、ユーザーが取引を承認できます。 連続する署名のたびに確認を求めない製品では、unlockで署名セッションを用意します。
import type { UnlockFlowEvent } from '@seams/wallet';
import type { SeamsContextType } from '@seams/wallet/react';
export async function unlockWallet(unlock: SeamsContextType['unlock'], walletId: string) {
const result = await unlock(walletId, {
onEvent: (event: UnlockFlowEvent) => console.log(event.phase, event.status, event.message),
});
if (!result.success) {
throw new Error(result.error);
}
// Read `nearAccountId` only from the NEAR branch.
if (result.kind === 'near_wallet_unlocked') {
console.log('NEAR account ready', result.nearAccountId);
} else {
console.log('EVM-family wallet ready', result.walletId);
}
return result;
}NEARトランザクションを送信する
この実装例は、NEARテストネットのアカウントにset_greetingの関数呼び出しを送り、EXECUTED_OPTIMISTICを待ちます。
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>;
}ボタンの処理は、設定した実行状態に達してから完了します。 useSeams()は、サインアウト中にwallet: nullを返し、NEARアカウントの準備完了までwallet.near: nullを返します。 ボタンの前の型ガードにより、そのアカウントがない状態での署名を防ぎます。
NEP-413メッセージに署名する
購入の承認など、ドメインに紐づくオフチェーンのメッセージにはNEP-413を使います。
import { logWalletEvents, type SeamsWeb } from '@seams/wallet';
export async function signCheckoutMessage(seams: SeamsWeb) {
const result = await seams.near.signMessage({
// Omitting the subject targets the authenticated wallet and its NEAR
// account; pass `walletSession` (a wallet id is enough) or `nearAccount` to
// name an exact one.
params: {
message: 'Approve checkout quote #quote_123',
recipient: 'merchant.example',
state: 'quote_123',
},
options: { onEvent: logWalletEvents() },
});
if (!result.success) {
throw new Error(result.error);
}
return result;
}成功結果には、署名済みメッセージのデータが含まれます。 このヘルパーは、SDKがsuccess: falseを返した後だけ例外を送出します。 必要に応じて、呼び出し側で例外を画面内のエラー状態へ置き換えてください。
EVM系トランザクションを実行する
型付きのEIP-1559リクエストを作成し、対応するネットワークのチェーン対象を指定します。
既定のseamsTestnetConfigは、NEARとTempoを選択します。 Ethereum Sepoliaの実装例を実行するには、プロバイダーを作成する前に明示的に設定してください。
import { defineSeamsConfig } from '@seams/wallet/react';
const config = defineSeamsConfig({
walletOrigin: import.meta.env.VITE_WALLET_ORIGIN,
relayerUrl: import.meta.env.VITE_RELAYER_URL,
publishableKey: import.meta.env.VITE_SEAMS_PUBLISHABLE_KEY,
chains: [{ network: 'near-testnet' }, { network: 'ethereum-sepolia', chainId: 11_155_111 }],
});import { logWalletEvents, parseEther, type SeamsWeb } from '@seams/wallet';
// EIP-1559 on any configured EVM chain. `seams.tempo` mirrors this API for
// Tempo's EIP-2718 typed transactions; the two stay separate because the
// envelopes and the signed results differ.
export async function executeEvmTransaction(seams: SeamsWeb): Promise<string> {
const execution = await seams.evm.signAndSendTransaction({
// A configured network slug. The RPC endpoint comes from that chain, and
// `tx.chainId` is filled in from it. Omitting `walletSession` targets the
// authenticated wallet.
chainTarget: 'ethereum-sepolia',
request: {
chain: 'evm',
kind: 'eip1559',
senderSignatureAlgorithm: 'secp256k1',
tx: {
maxPriorityFeePerGas: 1n,
maxFeePerGas: 1n,
gasLimit: 21_000n,
to: '0x1234567890abcdef1234567890abcdef12345678',
value: parseEther('0'),
data: '0x',
},
},
options: { onEvent: logWalletEvents() },
});
console.log('transaction hash', execution.txHash);
return execution.txHash;
}この実装例はEthereum Sepoliaを対象とし、トランザクションハッシュを返します。 実際に送信する前に、宛先、手数料、チェーン対象をアプリのトランザクションビルダーの値へ置き換えてください。 tx.chainIdとRPCエンドポイントは、どちらもチェーン対象から取得するため、呼び出し時に再指定しません。
TempoのEIP-2718型付きトランザクションには、同じメソッド構成のseams.tempoを使います。
期待する結果
- NEAR署名は、指定したトランザクション実行状態に達してから完了します。
- NEP-413は、署名済みメッセージの成功結果を返します。
- EVM系の実行は、トランザクション送信後に
txHashを返します。
進行状況のコールバックは、SigningFlowEventを受け取ります。 状態表示に使い、照合用に最終的な操作識別情報を保持してください。
対処可能な失敗
- 承認のキャンセルやポリシーによる拒否は、現在のリクエストを終了します。操作意図の下書きを保持し、再確認と再試行を可能にしてください。
- ウォレットセッションが期限切れか利用枠を使い切った場合は、再試行の前に再度アンロックしてください。
- 署名やRPCの失敗は、試行中の操作に紐づけてください。最初のハッシュまたはノンスの状態を照合してから、2つ目の取引を送信してください。
- SDKを呼ぶ前に、アプリ側でチェーンID、宛先、手数料、アカウント参照を検証してください。
次に、ウォレットの高度な操作、イベントと進行状況、結果とエラーを参照してください。