@base-org/account
Version:
Base Account SDK
142 lines • 6.38 kB
JavaScript
import { Communicator } from '../../../core/communicator/Communicator.js';
import { CB_WALLET_RPC_URL } from '../../../core/constants.js';
import { standardErrorCodes } from '../../../core/error/constants.js';
import { standardErrors } from '../../../core/error/errors.js';
import { serializeError } from '../../../core/error/serialize.js';
import { ProviderEventEmitter, } from '../../../core/provider/interface.js';
import { logRequestError, logRequestResponded, logRequestStarted, } from '../../../core/telemetry/events/provider.js';
import { parseErrorMessageFromAny } from '../../../core/telemetry/utils.js';
import { hexStringFromNumber } from '../../../core/type/util.js';
import { Signer } from '../../../sign/base-account/Signer.js';
import { initSubAccountConfig } from '../../../sign/base-account/utils.js';
import { correlationIds } from '../../../store/correlation-ids/store.js';
import { store } from '../../../store/store.js';
import { checkErrorForInvalidRequestArgs, fetchRPCRequest } from '../../../util/provider.js';
export class BaseAccountProvider extends ProviderEventEmitter {
communicator;
signer;
constructor({ metadata, preference: { walletUrl, ...preference }, }) {
super();
this.communicator = new Communicator({
url: walletUrl,
metadata,
preference,
});
this.signer = new Signer({
metadata,
communicator: this.communicator,
callback: this.emit.bind(this),
});
}
async request(args) {
// correlation id across the entire request lifecycle
const correlationId = crypto.randomUUID();
correlationIds.set(args, correlationId);
logRequestStarted({ method: args.method, correlationId });
try {
const result = await this._request(args);
logRequestResponded({
method: args.method,
correlationId,
});
return result;
}
catch (error) {
logRequestError({
method: args.method,
correlationId,
errorMessage: parseErrorMessageFromAny(error),
});
throw error;
}
finally {
correlationIds.delete(args);
}
}
async _request(args) {
try {
checkErrorForInvalidRequestArgs(args);
if (!this.signer.isConnected) {
switch (args.method) {
case 'eth_requestAccounts': {
await this.signer.handshake({ method: 'handshake' });
// We are translating eth_requestAccounts to wallet_connect always
await initSubAccountConfig();
await this.signer.request({
method: 'wallet_connect',
params: [
{
version: '1',
capabilities: {
...(store.subAccountsConfig.get()?.capabilities ?? {}),
},
},
],
});
// wallet_connect will retrieve and save the account info in the store
// continue to requesting it again at L130 for emitting the connect event +
// returning the accounts
break;
}
case 'wallet_connect': {
await this.signer.handshake({ method: 'handshake' }); // exchange session keys
const result = await this.signer.request(args); // send diffie-hellman encrypted request
return result;
}
case 'wallet_switchEthereumChain': {
// wallet_switchEthereumChain does not need to be sent to the popup
// it is handled by the base account signer
// so we just return the result
const result = await this.signer.request(args);
return result;
}
case 'wallet_sendCalls':
case 'wallet_sign': {
try {
await this.signer.handshake({ method: 'handshake' }); // exchange session keys
const result = await this.signer.request(args); // send diffie-hellman encrypted request
return result;
}
finally {
await this.signer.cleanup(); // clean up (rotate) the ephemeral session keys
}
}
case 'wallet_getCallsStatus': {
const result = await fetchRPCRequest(args, CB_WALLET_RPC_URL);
return result;
}
case 'eth_accounts': {
return [];
}
case 'net_version': {
const result = 1; // default value
return result;
}
case 'eth_chainId': {
const result = hexStringFromNumber(1); // default value
return result;
}
default: {
throw standardErrors.provider.unauthorized("Must call 'eth_requestAccounts' before other methods");
}
}
}
const result = await this.signer.request(args);
return result;
}
catch (error) {
const { code } = error;
if (code === standardErrorCodes.provider.unauthorized) {
await this.disconnect();
}
return Promise.reject(serializeError(error));
}
}
async disconnect() {
await this.signer.cleanup();
correlationIds.clear();
this.emit('disconnect', standardErrors.provider.disconnected('User initiated disconnection'));
}
isBaseAccount = true;
}
//# sourceMappingURL=BaseAccountProvider.js.map