UNPKG

contract-proxy-kit

Version:

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

478 lines 21.7 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 __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _safeAppsSdkConnector, _ethLibAdapter, _transactionManager, _contractManager, _networks, _ownerAccount, _saltNonce, _isConnectedToSafe; Object.defineProperty(exports, "__esModule", { value: true }); const MultiSendAbi_json_1 = __importDefault(require("./abis/MultiSendAbi.json")); const networks_1 = require("./config/networks"); const contractManager_1 = __importDefault(require("./contractManager")); const safeAppsSdkConnector_1 = __importDefault(require("./safeAppsSdkConnector")); const CpkTransactionManager_1 = __importDefault(require("./transactionManagers/CpkTransactionManager")); const checkConnectedToSafe_1 = require("./utils/checkConnectedToSafe"); const constants_1 = require("./utils/constants"); const hexData_1 = require("./utils/hexData"); const networks_2 = require("./utils/networks"); const transactions_1 = require("./utils/transactions"); class CPK { /** * Creates a non-initialized instance of the CPK with the selected configuration parameters. * * @param opts - CPK configuration * @returns The CPK instance */ constructor(opts) { _safeAppsSdkConnector.set(this, void 0); _ethLibAdapter.set(this, void 0); _transactionManager.set(this, void 0); _contractManager.set(this, void 0); _networks.set(this, void 0); _ownerAccount.set(this, void 0); _saltNonce.set(this, constants_1.predeterminedSaltNonce); _isConnectedToSafe.set(this, false /** * Creates and initializes an instance of the CPK with the selected configuration parameters. * * @param opts - CPK configuration * @returns The CPK instance */ ); __classPrivateFieldSet(this, _networks, Object.assign({}, networks_1.defaultNetworks)); if (!opts) { return; } const { ethLibAdapter, transactionManager, ownerAccount, networks, saltNonce, isSafeApp = true } = opts; if (isSafeApp) { __classPrivateFieldSet(this, _safeAppsSdkConnector, new safeAppsSdkConnector_1.default()); } if (!ethLibAdapter) { throw new Error('ethLibAdapter property missing from options'); } __classPrivateFieldSet(this, _ethLibAdapter, ethLibAdapter); __classPrivateFieldSet(this, _transactionManager, transactionManager !== null && transactionManager !== void 0 ? transactionManager : new CpkTransactionManager_1.default()); __classPrivateFieldSet(this, _ownerAccount, ownerAccount); __classPrivateFieldSet(this, _networks, networks_1.normalizeNetworksConfig(networks_1.defaultNetworks, networks)); if (saltNonce) { __classPrivateFieldSet(this, _saltNonce, saltNonce); } } /** * Creates and initializes an instance of the CPK with the selected configuration parameters. * * @param opts - CPK configuration * @returns The CPK instance */ static create(opts) { return __awaiter(this, void 0, void 0, function* () { const cpk = new CPK(opts); if (opts) { yield cpk.init(); } return cpk; }); } /** * Initializes the CPK instance. */ init() { var _a, _b; return __awaiter(this, void 0, void 0, function* () { if (!__classPrivateFieldGet(this, _ethLibAdapter)) { throw new Error('CPK uninitialized ethLibAdapter'); } const networkId = yield __classPrivateFieldGet(this, _ethLibAdapter).getNetworkId(); const network = __classPrivateFieldGet(this, _networks)[networkId]; if (!network) { throw new Error(`Unrecognized network ID ${networkId}`); } const ownerAccount = yield this.getOwnerAccount(); __classPrivateFieldSet(this, _isConnectedToSafe, (yield checkConnectedToSafe_1.checkConnectedToSafe(__classPrivateFieldGet(this, _ethLibAdapter).getProvider())) || ((_a = __classPrivateFieldGet(this, _safeAppsSdkConnector)) === null || _a === void 0 ? void 0 : _a.isSafeApp) === true); __classPrivateFieldSet(this, _contractManager, yield contractManager_1.default.create({ ethLibAdapter: __classPrivateFieldGet(this, _ethLibAdapter), network, ownerAccount, saltNonce: __classPrivateFieldGet(this, _saltNonce), isSafeApp: ((_b = __classPrivateFieldGet(this, _safeAppsSdkConnector)) === null || _b === void 0 ? void 0 : _b.isSafeApp) === true, isConnectedToSafe: __classPrivateFieldGet(this, _isConnectedToSafe) })); }); } /** * Checks if the Proxy contract is deployed or not. The deployment of the Proxy contract happens automatically when the first transaction is submitted. * * @returns TRUE when the Proxy contract is deployed */ isProxyDeployed() { return __awaiter(this, void 0, void 0, function* () { const address = yield this.address; if (!address) { throw new Error('CPK address uninitialized'); } if (!this.ethLibAdapter) { throw new Error('CPK ethLibAdapter uninitialized'); } const codeAtAddress = yield this.ethLibAdapter.getCode(address); const isDeployed = codeAtAddress !== '0x'; return isDeployed; }); } /** * Returns the address of the account connected to the CPK (Proxy contract owner). However, if the CPK is running as a Safe App or connected to a Safe, the Safe address will be returned. * * @returns The address of the account connected to the CPK */ getOwnerAccount() { var _a, _b; return __awaiter(this, void 0, void 0, function* () { if ((_a = __classPrivateFieldGet(this, _safeAppsSdkConnector)) === null || _a === void 0 ? void 0 : _a.isSafeApp) { return (yield __classPrivateFieldGet(this, _safeAppsSdkConnector).getSafeInfo()).safeAddress; } if (__classPrivateFieldGet(this, _ownerAccount)) { return __classPrivateFieldGet(this, _ownerAccount); } if (!__classPrivateFieldGet(this, _ethLibAdapter)) { throw new Error('CPK uninitialized ethLibAdapter'); } return (_b = __classPrivateFieldGet(this, _ethLibAdapter)) === null || _b === void 0 ? void 0 : _b.getAccount(); }); } /** * Returns the ETH balance of the Proxy contract. * * @returns The ETH balance of the Proxy contract */ getBalance() { var _a; return __awaiter(this, void 0, void 0, function* () { const address = yield this.address; if (!address) { throw new Error('CPK address uninitialized'); } if (!__classPrivateFieldGet(this, _ethLibAdapter)) { throw new Error('CPK ethLibAdapter uninitialized'); } return (_a = __classPrivateFieldGet(this, _ethLibAdapter)) === null || _a === void 0 ? void 0 : _a.getBalance(address); }); } /** * Returns the ID of the connected network. * * @returns The ID of the connected network */ getNetworkId() { var _a; return __awaiter(this, void 0, void 0, function* () { if ((_a = __classPrivateFieldGet(this, _safeAppsSdkConnector)) === null || _a === void 0 ? void 0 : _a.isSafeApp) { const networkName = (yield __classPrivateFieldGet(this, _safeAppsSdkConnector).getSafeInfo()).network; return networks_2.getNetworkIdFromName(networkName); } if (!__classPrivateFieldGet(this, _ethLibAdapter)) { throw new Error('CPK ethLibAdapter uninitialized'); } return __classPrivateFieldGet(this, _ethLibAdapter).getNetworkId(); }); } /** * Returns the safeAppsSdkConnector used by the CPK. * * @returns The safeAppsSdkConnector used by the CPK */ get safeAppsSdkConnector() { return __classPrivateFieldGet(this, _safeAppsSdkConnector); } /** * Returns the contractManager used by the CPK. * * @returns The contractManager used by the CPK */ get contractManager() { return __classPrivateFieldGet(this, _contractManager); } /** * Returns the ethLibAdapter used by the CPK. * * @returns The ethLibAdapter used by the CPK */ get ethLibAdapter() { return __classPrivateFieldGet(this, _ethLibAdapter); } /** * Returns a list of the contract addresses which drive the CPK per network by network ID. * * @returns The list of the contract addresses which drive the CPK per network by network ID */ get networks() { return __classPrivateFieldGet(this, _networks); } /** * Checks if the CPK is connected to a Safe account or not. * * @returns TRUE if the CPK is connected to a Safe account */ get isConnectedToSafe() { return __classPrivateFieldGet(this, _isConnectedToSafe); } /** * Returns the salt nonce used to deploy the Proxy Contract. * * @returns The salt nonce used to deploy the Proxy Contract */ get saltNonce() { return __classPrivateFieldGet(this, _saltNonce); } /** * Returns the address of the Proxy contract. * * @returns The address of the Proxy contract */ get address() { var _a, _b, _c, _d; if ((_a = __classPrivateFieldGet(this, _safeAppsSdkConnector)) === null || _a === void 0 ? void 0 : _a.safeAddress) { return (_b = __classPrivateFieldGet(this, _safeAppsSdkConnector)) === null || _b === void 0 ? void 0 : _b.safeAddress; } return (_d = (_c = __classPrivateFieldGet(this, _contractManager)) === null || _c === void 0 ? void 0 : _c.contract) === null || _d === void 0 ? void 0 : _d.address; } /** * Sets the ethLibAdapter used by the CPK. */ setEthLibAdapter(ethLibAdapter) { __classPrivateFieldSet(this, _ethLibAdapter, ethLibAdapter); } /** * Sets the transactionManager used by the CPK. */ setTransactionManager(transactionManager) { var _a; if ((_a = __classPrivateFieldGet(this, _safeAppsSdkConnector)) === null || _a === void 0 ? void 0 : _a.isSafeApp) { throw new Error('TransactionManagers are not allowed when the app is running as a Safe App'); } __classPrivateFieldSet(this, _transactionManager, transactionManager); } /** * Sets the network configuration used by the CPK. */ setNetworks(networks) { __classPrivateFieldSet(this, _networks, networks_1.normalizeNetworksConfig(networks_1.defaultNetworks, networks)); } /** * Returns the encoding of a list of transactions. * * @param transactions - The transaction list * @returns The encoding of a list of transactions */ encodeMultiSendCallData(transactions) { var _a; if (!__classPrivateFieldGet(this, _ethLibAdapter)) { throw new Error('CPK ethLibAdapter uninitialized'); } const multiSend = ((_a = __classPrivateFieldGet(this, _contractManager)) === null || _a === void 0 ? void 0 : _a.multiSend) || __classPrivateFieldGet(this, _ethLibAdapter).getContract(MultiSendAbi_json_1.default); const standardizedTxs = transactions.map(transactions_1.standardizeTransaction); const ethLibAdapter = __classPrivateFieldGet(this, _ethLibAdapter); return multiSend.encode('multiSend', [ hexData_1.joinHexData(standardizedTxs.map((tx) => ethLibAdapter.abiEncodePacked({ type: 'uint8', value: tx.operation }, { type: 'address', value: tx.to }, { type: 'uint256', value: tx.value }, { type: 'uint256', value: hexData_1.getHexDataLength(tx.data) }, { type: 'bytes', value: tx.data }))) ]); } /** * Executes a list of transactions. * * @param transactions - The transaction list to execute * @param options - Execution configuration options * @returns The transaction response */ execTransactions(transactions, options) { var _a; return __awaiter(this, void 0, void 0, function* () { const standardizedTxs = transactions.map(transactions_1.standardizeTransaction); if (((_a = __classPrivateFieldGet(this, _safeAppsSdkConnector)) === null || _a === void 0 ? void 0 : _a.isSafeApp) && transactions.length >= 1) { return __classPrivateFieldGet(this, _safeAppsSdkConnector).sendTransactions(standardizedTxs, { safeTxGas: options === null || options === void 0 ? void 0 : options.safeTxGas }); } const address = yield this.address; if (!address) { throw new Error('CPK address uninitialized'); } if (!__classPrivateFieldGet(this, _contractManager)) { throw new Error('CPK contractManager uninitialized'); } if (!__classPrivateFieldGet(this, _ethLibAdapter)) { throw new Error('CPK ethLibAdapter uninitialized'); } if (!__classPrivateFieldGet(this, _transactionManager)) { throw new Error('CPK transactionManager uninitialized'); } const ownerAccount = yield this.getOwnerAccount(); if (!ownerAccount) { throw new Error('CPK ownerAccount uninitialized'); } const safeExecTxParams = this.getSafeExecTxParams(transactions); const sendOptions = transactions_1.normalizeGasLimit(Object.assign(Object.assign({}, options), { from: ownerAccount })); const codeAtAddress = yield __classPrivateFieldGet(this, _ethLibAdapter).getCode(address); const isDeployed = codeAtAddress !== '0x'; const txManager = !isDeployed ? new CpkTransactionManager_1.default() : __classPrivateFieldGet(this, _transactionManager); return txManager.execTransactions({ ownerAccount, safeExecTxParams, transactions: standardizedTxs, ethLibAdapter: __classPrivateFieldGet(this, _ethLibAdapter), contractManager: __classPrivateFieldGet(this, _contractManager), saltNonce: __classPrivateFieldGet(this, _saltNonce), isDeployed, isConnectedToSafe: __classPrivateFieldGet(this, _isConnectedToSafe), sendOptions }); }); } /** * Returns the Master Copy contract version. * * @returns The Master Copy contract version */ getContractVersion() { var _a; return __awaiter(this, void 0, void 0, function* () { const isProxyDeployed = yield this.isProxyDeployed(); if (!isProxyDeployed) { throw new Error('CPK Proxy contract is not deployed'); } if (!((_a = __classPrivateFieldGet(this, _contractManager)) === null || _a === void 0 ? void 0 : _a.versionUtils)) { throw new Error('CPK contractManager uninitialized'); } return yield __classPrivateFieldGet(this, _contractManager).versionUtils.getContractVersion(); }); } /** * Returns the list of addresses of all the enabled Safe modules. * * @returns The list of addresses of all the enabled Safe modules */ getModules() { var _a; return __awaiter(this, void 0, void 0, function* () { const isProxyDeployed = yield this.isProxyDeployed(); if (!isProxyDeployed) { throw new Error('CPK Proxy contract is not deployed'); } if (!((_a = __classPrivateFieldGet(this, _contractManager)) === null || _a === void 0 ? void 0 : _a.versionUtils)) { throw new Error('CPK contractManager uninitialized'); } return yield __classPrivateFieldGet(this, _contractManager).versionUtils.getModules(); }); } /** * Checks if a specific Safe module is enabled or not. * * @param moduleAddress - The desired module address * @returns TRUE if the module is enabled */ isModuleEnabled(moduleAddress) { var _a; return __awaiter(this, void 0, void 0, function* () { const isProxyDeployed = yield this.isProxyDeployed(); if (!isProxyDeployed) { throw new Error('CPK Proxy contract is not deployed'); } if (!((_a = __classPrivateFieldGet(this, _contractManager)) === null || _a === void 0 ? void 0 : _a.versionUtils)) { throw new Error('CPK contractManager uninitialized'); } return yield __classPrivateFieldGet(this, _contractManager).versionUtils.isModuleEnabled(moduleAddress); }); } /** * Enables a Safe module * * @param moduleAddress - The desired module address * @returns The transaction response */ enableModule(moduleAddress) { var _a; return __awaiter(this, void 0, void 0, function* () { if (!((_a = __classPrivateFieldGet(this, _contractManager)) === null || _a === void 0 ? void 0 : _a.versionUtils)) { throw new Error('CPK contractManager uninitialized'); } const address = yield this.address; if (!address) { throw new Error('CPK address uninitialized'); } return yield this.execTransactions([ { to: address, data: yield __classPrivateFieldGet(this, _contractManager).versionUtils.encodeEnableModule(moduleAddress), operation: CPK.Call } ]); }); } /** * Disables a Safe module * * @param moduleAddress - The desired module address * @returns The transaction response */ disableModule(moduleAddress) { var _a; return __awaiter(this, void 0, void 0, function* () { const isProxyDeployed = yield this.isProxyDeployed(); if (!isProxyDeployed) { throw new Error('CPK Proxy contract is not deployed'); } if (!((_a = __classPrivateFieldGet(this, _contractManager)) === null || _a === void 0 ? void 0 : _a.versionUtils)) { throw new Error('CPK contractManager uninitialized'); } const address = yield this.address; if (!address) { throw new Error('CPK address uninitialized'); } return yield this.execTransactions([ { to: address, data: yield __classPrivateFieldGet(this, _contractManager).versionUtils.encodeDisableModule(moduleAddress), operation: CPK.Call } ]); }); } getSafeExecTxParams(transactions) { var _a, _b; if (transactions.length === 1) { return transactions_1.standardizeTransaction(transactions[0]); } if (!((_a = __classPrivateFieldGet(this, _contractManager)) === null || _a === void 0 ? void 0 : _a.multiSend)) { throw new Error('CPK MultiSend uninitialized'); } return { to: (_b = __classPrivateFieldGet(this, _contractManager)) === null || _b === void 0 ? void 0 : _b.multiSend.address, value: '0', data: this.encodeMultiSendCallData(transactions), operation: CPK.DelegateCall }; } } _safeAppsSdkConnector = new WeakMap(), _ethLibAdapter = new WeakMap(), _transactionManager = new WeakMap(), _contractManager = new WeakMap(), _networks = new WeakMap(), _ownerAccount = new WeakMap(), _saltNonce = new WeakMap(), _isConnectedToSafe = new WeakMap(); CPK.Call = transactions_1.OperationType.Call; CPK.DelegateCall = transactions_1.OperationType.DelegateCall; exports.default = CPK; //# sourceMappingURL=CPK.js.map