@celo/connect
Version:
Light Toolkit for connecting with the Celo network
287 lines • 12 kB
JavaScript
"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