accounts
Version:
Tempo Accounts SDK
108 lines • 5.4 kB
JavaScript
import { Hex, Provider as core_Provider } from 'ox';
import { custom } from 'viem';
import { z } from 'zod/mini';
import * as Adapter from '../../Adapter.js';
import * as Rpc from '../../zod/rpc.js';
import * as u from '../../zod/utils.js';
/**
* Builds an adapter that forwards wallet RPC to a remote wallet through a
* single request function.
*
* Shared core for adapters whose wallet lives behind a request/response
* session (e.g. Wata mobile web auth or postMessage). Access keys are
* generated locally; every other wallet action round-trips through
* `request`.
*/
export function fromRequest(options) {
const { actions, bind, cleanup, close, icon, keystores, name, rdns, request: requestRemote, } = options;
return Adapter.define({ ...(icon ? { icon } : {}), name, rdns, schema: z.object({ address: u.address() }) }, ({ getAccount, getClient, store }) => {
// Late-bind the store so the request channel can reconcile local
// connection state (e.g. a wallet `accountsChanged` notification).
bind?.({ store });
const provider = core_Provider.from({
async request(request) {
const { accounts, activeAccount, chainId } = store.getState();
if (request.method === 'eth_chainId')
return Hex.fromNumber(chainId);
// Forward the active account + chain as request context so the wallet
// acts against the session the app believes it is using rather than
// whatever the wallet last selected for itself.
const account = accounts[activeAccount]?.address;
return await requestRemote({
method: request.method,
params: request.params,
context: { chainId, ...(account ? { account } : {}) },
});
},
});
// Connect capabilities are read from the first account only: the remote
// wallet connects a single account per exchange.
function toConnectReturn(result) {
const capabilities = result.accounts[0]?.capabilities;
return {
accounts: result.accounts.map((account) => ({ address: account.address })),
...(capabilities?.auth ? { auth: capabilities.auth } : {}),
...(capabilities?.identity ? { identity: capabilities.identity } : {}),
...(capabilities?.keyAuthorization
? { keyAuthorization: capabilities.keyAuthorization }
: {}),
...(capabilities?.personalSign ? { personalSign: capabilities.personalSign } : {}),
...(capabilities?.signature ? { signature: capabilities.signature } : {}),
...(capabilities?.username !== undefined ? { username: capabilities.username } : {}),
};
}
return {
forwardsAuth: true,
...(keystores ? { accessKey: { keystores } } : {}),
actions: {
async createAccount(_parameters, request) {
return toConnectReturn((await provider.request(request)));
},
async loadAccounts(_parameters, request) {
return toConnectReturn((await provider.request(request)));
},
async deposit(_parameters, request) {
return (await provider.request(request));
},
async depositZone(parameters, request) {
return (await provider.request({
...request,
params: [z.encode(Rpc.wallet_depositZone.parameters, parameters)],
}));
},
// `disconnect` (when `close` is set) only tears down the local
// wallet session — it is never forwarded. No `switchChain` action:
// chain selection is local state the provider handles itself, and
// forwarding it would open a wallet session for nothing.
...(close ? { disconnect: close } : {}),
async swap(_parameters, request) {
return (await provider.request(request));
},
async transfer(parameters, request) {
return (await provider.request({
...request,
params: [z.encode(Rpc.wallet_transfer.parameters, parameters)],
}));
},
async withdrawZone(parameters, request) {
return (await provider.request({
...request,
params: [z.encode(Rpc.wallet_withdrawZone.parameters, parameters)],
}));
},
...actions?.({ getClient, request: requestRemote, store }),
},
...(cleanup ? { cleanup } : close ? { cleanup: () => void close() } : {}),
getAccount(parameters = {}) {
return {
account: {
address: parameters.address ?? getAccount({ signable: false }).address,
type: 'json-rpc',
},
transport: custom(provider),
};
},
};
});
}
//# sourceMappingURL=fromRequest.js.map