UNPKG

@celo/connect

Version:

Light Toolkit for connecting with the Celo network

287 lines 12 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CeloProvider = exports.assertIsCeloProvider = void 0; const lock_1 = require("@celo/base/lib/lock"); const debug_1 = __importDefault(require("debug")); const provider_utils_1 = require("./utils/provider-utils"); const rpc_caller_1 = require("./utils/rpc-caller"); const debug = (0, debug_1.default)('provider:connection'); const debugPayload = (0, debug_1.default)('provider:payload'); const debugTxToSend = (0, debug_1.default)('provider:tx-to-send'); const debugEncodedTx = (0, debug_1.default)('provider:encoded-tx'); const debugResponse = (0, debug_1.default)('provider:response'); var InterceptedMethods; (function (InterceptedMethods) { InterceptedMethods["accounts"] = "eth_accounts"; InterceptedMethods["sendTransaction"] = "eth_sendTransaction"; InterceptedMethods["signTransaction"] = "eth_signTransaction"; InterceptedMethods["sign"] = "eth_sign"; InterceptedMethods["personalSign"] = "personal_sign"; InterceptedMethods["signTypedData"] = "eth_signTypedData"; InterceptedMethods["signTypedDataV1"] = "eth_signTypedData_v1"; InterceptedMethods["signTypedDataV3"] = "eth_signTypedData_v3"; InterceptedMethods["signTypedDataV4"] = "eth_signTypedData_v4"; InterceptedMethods["signTypedDataV5"] = "eth_signTypedData_v5"; })(InterceptedMethods || (InterceptedMethods = {})); function assertIsCeloProvider(provider) { if (!(provider instanceof CeloProvider)) { throw new Error('A different Provider was manually added to the kit. The kit should have a CeloProvider'); } } exports.assertIsCeloProvider = assertIsCeloProvider; /* * CeloProvider wraps a web3.js provider for use with Celo */ class CeloProvider { constructor(existingProvider, connection) { this.existingProvider = existingProvider; this.connection = connection; this.alreadyStopped = false; // Transaction nonce is calculated as the max of an account's nonce on-chain, and any pending transactions in a node's // transaction pool. As a result, once a nonce is used, the transaction must be sent to the node before the nonce can // be calculated for another transaction. In particular the sign and send operation must be completed atomically with // relation to other sign and send operations. this.nonceLock = new lock_1.Lock(); this.addProviderDelegatedFunctions(); } // @deprecated Use the `addAccount` from the Connection addAccount(privateKey) { this.connection.addAccount(privateKey); } // @deprecated Use the `removeAccount` from the Connection removeAccount(address) { this.connection.removeAccount(address); } // @deprecated Use the `getAccounts` from the Connection getAccounts() { return __awaiter(this, void 0, void 0, function* () { return this.connection.getAccounts(); }); } isLocalAccount(address) { return this.connection.wallet != null && this.connection.wallet.hasAccount(address); } /** * Send method as expected by web3.js */ send(payload, callback) { let txParams; let address; debugPayload('%O', payload); const decoratedCallback = (error, result) => { debugResponse('%O', result); callback(error, result); }; if (this.alreadyStopped) { throw Error('CeloProvider already stopped'); } switch (payload.method) { case InterceptedMethods.accounts: { (0, rpc_caller_1.rpcCallHandler)(payload, this.handleAccounts.bind(this), decoratedCallback); return; } case InterceptedMethods.sendTransaction: { this.checkPayloadWithAtLeastNParams(payload, 1); txParams = payload.params[0]; if (this.connection.isLocalAccount(txParams.from)) { (0, rpc_caller_1.rpcCallHandler)(payload, this.handleSendTransaction.bind(this), decoratedCallback); } else { this.forwardSend(payload, callback); } return; } case InterceptedMethods.signTransaction: { this.checkPayloadWithAtLeastNParams(payload, 1); txParams = payload.params[0]; if (this.connection.isLocalAccount(txParams.from)) { (0, rpc_caller_1.rpcCallHandler)(payload, this.handleSignTransaction.bind(this), decoratedCallback); } else { this.forwardSend(payload, callback); } return; } case InterceptedMethods.sign: case InterceptedMethods.personalSign: { this.checkPayloadWithAtLeastNParams(payload, 2); address = payload.method === InterceptedMethods.sign ? payload.params[0] : payload.params[1]; if (this.connection.isLocalAccount(address)) { (0, rpc_caller_1.rpcCallHandler)(payload, this.handleSignPersonalMessage.bind(this), decoratedCallback); } else { this.forwardSend(payload, callback); } return; } case InterceptedMethods.signTypedData: case InterceptedMethods.signTypedDataV1: case InterceptedMethods.signTypedDataV3: case InterceptedMethods.signTypedDataV4: case InterceptedMethods.signTypedDataV5: { this.checkPayloadWithAtLeastNParams(payload, 1); address = payload.params[0]; if (this.connection.isLocalAccount(address)) { (0, rpc_caller_1.rpcCallHandler)(payload, this.handleSignTypedData.bind(this), decoratedCallback); } else { this.forwardSend(payload, callback); } return; } default: { this.forwardSend(payload, callback); return; } } } stop() { if (this.alreadyStopped) { return; } try { (0, provider_utils_1.stopProvider)(this.existingProvider); this.alreadyStopped = true; } catch (error) { debug(`Failed to close the connection: ${error}`); } } toEip1193Provider() { return { request: (args) => __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { this.send({ id: 0, jsonrpc: '2.0', method: args.method, params: args.params, }, (error, result) => { if (error) { reject(error); } else { resolve(result.result); } }); }); }), }; } handleAccounts(_payload) { return __awaiter(this, void 0, void 0, function* () { return this.connection.getAccounts(); }); } handleSignTypedData(payload) { return __awaiter(this, void 0, void 0, function* () { const [address, typedData] = payload.params; const signature = this.connection.wallet.signTypedData(address, typedData); return signature; }); } handleSignPersonalMessage(payload) { return __awaiter(this, void 0, void 0, function* () { const address = payload.method === 'eth_sign' ? payload.params[0] : payload.params[1]; const data = payload.method === 'eth_sign' ? payload.params[1] : payload.params[0]; const ecSignatureHex = this.connection.wallet.signPersonalMessage(address, data); return ecSignatureHex; }); } handleSignTransaction(payload) { return __awaiter(this, void 0, void 0, function* () { const txParams = payload.params[0]; const filledParams = yield this.connection.paramsPopulator.populate(txParams); debugTxToSend('%O', filledParams); const signedTx = yield this.connection.wallet.signTransaction(filledParams); debugEncodedTx('%O', signedTx); return signedTx; }); } handleSendTransaction(payload) { return __awaiter(this, void 0, void 0, function* () { yield this.nonceLock.acquire(); try { const signedTx = yield this.handleSignTransaction(payload); const response = yield this.connection.rpcCaller.call('eth_sendRawTransaction', [ signedTx.raw, ]); return response.result; } finally { this.nonceLock.release(); } }); } forwardSend(payload, callback) { this.connection.rpcCaller.send(payload, callback); } checkPayloadWithAtLeastNParams(payload, n) { if (!payload.params || payload.params.length < n) { throw Error('Invalid params'); } } // Functions required to act as a delefator for the existingProvider addProviderDelegatedFunctions() { if ((0, provider_utils_1.hasProperty)(this.existingProvider, 'on')) { // @ts-ignore this.on = this.defaultOn; } if ((0, provider_utils_1.hasProperty)(this.existingProvider, 'once')) { // @ts-ignore this.once = this.defaultOnce; } if ((0, provider_utils_1.hasProperty)(this.existingProvider, 'removeListener')) { // @ts-ignore this.removeListener = this.defaultRemoveListener; } if ((0, provider_utils_1.hasProperty)(this.existingProvider, 'removeAllListener')) { // @ts-ignore this.removeAllListener = this.defaultRemoveAllListeners; } if ((0, provider_utils_1.hasProperty)(this.existingProvider, 'reset')) { // @ts-ignore this.reset = this.defaultReset; } } get connected() { return this.existingProvider.connected; } supportsSubscriptions() { return this.existingProvider.supportsSubscriptions(); } defaultOn(type, callback) { ; this.existingProvider.on(type, callback); } defaultOnce(type, callback) { ; this.existingProvider.once(type, callback); } defaultRemoveListener(type, callback) { ; this.existingProvider.removeListener(type, callback); } defaultRemoveAllListeners(type) { ; this.existingProvider.removeAllListeners(type); } defaultReset() { ; this.existingProvider.reset(); } } exports.CeloProvider = CeloProvider; //# sourceMappingURL=celo-provider.js.map