UNPKG

dp-contract-proxy-kit

Version:

Enable batched transactions and contract account interactions using a unique deterministic Gnosis Safe.

155 lines 6.41 kB
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()); }); }; import BigNumber from 'bignumber.js'; import { zeroAddress } from '../../utils/constants'; import { HttpMethod, sendRequest } from '../../utils/httpRequests'; import { TransactionManagerNames } from '../TransactionManager'; BigNumber.set({ EXPONENTIAL_AT: [-7, 255] }); class SafeRelayTransactionManager { /** * Initializes an instance of the Safe Relay Transaction Manager. * * @param options - The URL pointing to the Safe Transaction Service * @returns The SafeRelayTransactionManager instance */ constructor(options) { const { url } = options; if (!url) { throw new Error('url property missing from options'); } this.url = url; } /** * Returns the configuration of the Safe Relay Transaction Manager. * * @returns The name of the TransactionManager in use and the URL of the service */ get config() { return { name: TransactionManagerNames.SafeTxRelayManager, url: this.url }; } /** * Executes a list of transactions via the Safe Transaction Relay. * * @param options * @returns The transaction response */ execTransactions({ ownerAccount, safeExecTxParams, contractManager, ethLibAdapter, isConnectedToSafe }) { return __awaiter(this, void 0, void 0, function* () { const { contract } = contractManager; if (!contract) { throw new Error('CPK Proxy contract uninitialized'); } if (isConnectedToSafe) { throw new Error('The use of the relay service is not supported when the CPK is connected to a Gnosis Safe'); } const relayEstimations = yield this.getTransactionEstimations({ safe: contract.address, to: safeExecTxParams.to, value: new BigNumber(safeExecTxParams.value).toString(10), data: safeExecTxParams.data, operation: safeExecTxParams.operation }); // TO-DO: dataGas will be obsolete. Check again when this endpoint is updated to v2 const tx = { to: safeExecTxParams.to, value: new BigNumber(safeExecTxParams.value).toString(10), data: safeExecTxParams.data, operation: safeExecTxParams.operation, safeTxGas: relayEstimations.safeTxGas, dataGas: relayEstimations.baseGas, gasPrice: relayEstimations.gasPrice, gasToken: relayEstimations.gasToken, refundReceiver: zeroAddress, nonce: relayEstimations.lastUsedNonce + 1 }; const txHash = yield contract.call('getTransactionHash', [ tx.to, tx.value, tx.data, tx.operation, tx.safeTxGas, tx.dataGas, tx.gasPrice, tx.gasToken, tx.refundReceiver, tx.nonce ]); const rsvSignature = yield this.signTransactionHash(ethLibAdapter, ownerAccount, txHash); return this.sendTransactionToRelay({ url: this.url, safe: contract.address, tx, signatures: [rsvSignature], ethLibAdapter }); }); } getTransactionEstimations({ safe, to, value, data, operation, gasToken }) { return __awaiter(this, void 0, void 0, function* () { const body = { safe, to, value, data, operation }; if (gasToken) { body.gasToken = gasToken; } const jsonResponse = yield sendRequest({ url: `${this.url}/api/v1/safes/${safe}/transactions/estimate/`, method: HttpMethod.POST, body: JSON.stringify(body), expectedHttpCodeResponse: 200 }); return jsonResponse; }); } sendTransactionToRelay({ tx, safe, signatures, ethLibAdapter }) { return __awaiter(this, void 0, void 0, function* () { const jsonResponse = yield sendRequest({ url: `${this.url}/api/v1/safes/${safe}/transactions/`, method: HttpMethod.POST, body: JSON.stringify(Object.assign(Object.assign({ safe }, tx), { signatures })), expectedHttpCodeResponse: 201 }); return ethLibAdapter.toSafeRelayTxResult(jsonResponse.txHash, jsonResponse.ethereumTx); }); } signTransactionHash(ethLibAdapter, ownerAccount, txHash) { return __awaiter(this, void 0, void 0, function* () { let sig = yield ethLibAdapter.signMessage(txHash, ownerAccount); let sigV = parseInt(sig.slice(-2), 16); switch (sigV) { case 0: case 1: sigV += 31; break; case 27: case 28: sigV += 4; break; default: throw new Error('Invalid signature'); } sig = sig.slice(0, -2) + sigV.toString(16); return { r: new BigNumber('0x' + sig.slice(2, 66)).toString(10), s: new BigNumber('0x' + sig.slice(66, 130)).toString(10), v: new BigNumber('0x' + sig.slice(130, 132)).toString(10) }; }); } } export default SafeRelayTransactionManager; //# sourceMappingURL=index.js.map