Wallet Signatures
Which operations need a wallet signature, who signs, and how each wallet type encodes it.
Before You Start
Read the following guides before proceeding:
| Guide | Why |
|---|---|
| Authentication | The corporation token whose employee_address signs |
| Permissions | Permissions are checked before any signature |
Overview
Some corporate operations require the employee to sign a sentence with their wallet. Each operation's page
gives its sentence and its errors. This page covers what they share: who signs and how each wallet type
encodes the signature.
| Operation | Signature | Sentence and rules |
|---|---|---|
| Read PAN and expiry, CVV or PIN | Action confirmation, always | Action Confirmation Signatures |
| Card transfer | Transaction authorization, in Signature mode | Card Transfer |
| Corridor transfer | Transaction authorization, in Signature mode | Corridor Transfers |
| Bank transfer | Transaction authorization, in Signature mode | Bank Transfers |
| Create a recipient | Transaction authorization, optional | Creating a Recipient |
Transaction authorization — the mode, the transaction_authorization object, nonce and reuse rules, and
its errors — is described once in Transaction Authorization.
Estimates, confirmations, reads, card management and bulk transfers take no signature. A bulk transfer is
signed on-chain.
Who Signs
The signer is always the wallet in the corporation token's employee_address claim — the X-User-Wallet
sent to POST /api/v1/corporations/login.
- An employee signs with their own wallet. The corporation owner's signature does not authorize an
employee's request, even over the same sentence. - A smart account is a different signer from the EOA that controls it. If the employee logged in with
an EOA, the EOA signs. ERC-1271 applies only whenemployee_addressitself is the contract.
Encoding by Wallet Type
Wallet behind employee_address | Signature | Encoding |
|---|---|---|
| EVM EOA | EIP-191 personal_sign over the sentence. v as 27/28 or 0/1 | 0x hex, 65 bytes |
| EVM smart-contract wallet | Any bytes the wallet's ERC-1271 isValidSignature(hash, signature) accepts, where hash is the EIP-191 hash of the sentence | 0x hex, passed to the contract exactly as sent |
| Stellar | Ed25519 over the SHA-256 of the sentence | Standard base64 |
| XRPL | Signature over the sentence. Transaction authorization only | Hex, with the signer's public_key |
The sentence is signed character for character. Any difference — case, spacing, a different id or nonce —
produces a signature that is rejected.
Smart-Contract Wallets
- The contract must be deployed on the chain in the corporation token's
chain_idclaim — the
X-Chain-Idsent at login, or the default chain when none was sent. An undeployed (counterfactual)
account cannot sign. - Wirex calls
isValidSignatureonly when the signature does not recover toemployee_addressas an EOA
signature, so an EOA signature never depends on a node call. - The call has a 3-second timeout. A timeout, a revert, an unreachable node or any return value other than
0x1626ba7erejects the signature.
Signing the Sentence
The examples sign with an EOA key (EIP-191). With an embedded or browser wallet, pass the same sentence to
its personal_sign / signMessage.
import { privateKeyToAccount } from 'viem/accounts';
const account = privateKeyToAccount(employeePrivateKey); // the employee_address wallet
const signature = await account.signMessage({ message: sentence }); // 0x…, 65 bytesfrom eth_account import Account
from eth_account.messages import encode_defunct
signature = Account.sign_message(encode_defunct(text=sentence), employee_private_key).signature.hex()
if not signature.startswith("0x"):
signature = "0x" + signaturesig, _ := crypto.Sign(accounts.TextHash([]byte(sentence)), employeeKey)
sig[crypto.RecoveryIDOffset] += 27
signature := hexutil.Encode(sig)Updated about 2 hours ago

