dp-contract-proxy-kit
Version:
Enable batched transactions and contract account interactions using a unique deterministic Gnosis Safe.
476 lines • 23 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 __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _CPK_safeAppsSdkConnector, _CPK_ethLibAdapter, _CPK_transactionManager, _CPK_contractManager, _CPK_networks, _CPK_ownerAccount, _CPK_saltNonce, _CPK_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) {
_CPK_safeAppsSdkConnector.set(this, void 0);
_CPK_ethLibAdapter.set(this, void 0);
_CPK_transactionManager.set(this, void 0);
_CPK_contractManager.set(this, void 0);
_CPK_networks.set(this, void 0);
_CPK_ownerAccount.set(this, void 0);
_CPK_saltNonce.set(this, constants_1.predeterminedSaltNonce);
_CPK_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, _CPK_networks, Object.assign({}, networks_1.defaultNetworks), "f");
if (!opts) {
return;
}
const { ethLibAdapter, transactionManager, ownerAccount, networks, saltNonce, isSafeApp = true } = opts;
if (isSafeApp) {
__classPrivateFieldSet(this, _CPK_safeAppsSdkConnector, new safeAppsSdkConnector_1.default(), "f");
}
if (!ethLibAdapter) {
throw new Error('ethLibAdapter property missing from options');
}
__classPrivateFieldSet(this, _CPK_ethLibAdapter, ethLibAdapter, "f");
__classPrivateFieldSet(this, _CPK_transactionManager, transactionManager !== null && transactionManager !== void 0 ? transactionManager : new CpkTransactionManager_1.default(), "f");
__classPrivateFieldSet(this, _CPK_ownerAccount, ownerAccount, "f");
__classPrivateFieldSet(this, _CPK_networks, networks_1.normalizeNetworksConfig(networks_1.defaultNetworks, networks), "f");
if (saltNonce) {
__classPrivateFieldSet(this, _CPK_saltNonce, saltNonce, "f");
}
}
/**
* 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, _CPK_ethLibAdapter, "f")) {
throw new Error('CPK uninitialized ethLibAdapter');
}
const networkId = yield __classPrivateFieldGet(this, _CPK_ethLibAdapter, "f").getNetworkId();
const network = __classPrivateFieldGet(this, _CPK_networks, "f")[networkId];
if (!network) {
throw new Error(`Unrecognized network ID ${networkId}`);
}
const ownerAccount = yield this.getOwnerAccount();
__classPrivateFieldSet(this, _CPK_isConnectedToSafe, (yield checkConnectedToSafe_1.checkConnectedToSafe(__classPrivateFieldGet(this, _CPK_ethLibAdapter, "f").getProvider())) ||
((_a = __classPrivateFieldGet(this, _CPK_safeAppsSdkConnector, "f")) === null || _a === void 0 ? void 0 : _a.isSafeApp) === true, "f");
__classPrivateFieldSet(this, _CPK_contractManager, yield contractManager_1.default.create({
ethLibAdapter: __classPrivateFieldGet(this, _CPK_ethLibAdapter, "f"),
network,
ownerAccount,
saltNonce: __classPrivateFieldGet(this, _CPK_saltNonce, "f"),
isSafeApp: ((_b = __classPrivateFieldGet(this, _CPK_safeAppsSdkConnector, "f")) === null || _b === void 0 ? void 0 : _b.isSafeApp) === true,
isConnectedToSafe: __classPrivateFieldGet(this, _CPK_isConnectedToSafe, "f")
}), "f");
});
}
/**
* 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, _CPK_safeAppsSdkConnector, "f")) === null || _a === void 0 ? void 0 : _a.isSafeApp) {
return (yield __classPrivateFieldGet(this, _CPK_safeAppsSdkConnector, "f").getSafeInfo()).safeAddress;
}
if (__classPrivateFieldGet(this, _CPK_ownerAccount, "f")) {
return __classPrivateFieldGet(this, _CPK_ownerAccount, "f");
}
if (!__classPrivateFieldGet(this, _CPK_ethLibAdapter, "f")) {
throw new Error('CPK uninitialized ethLibAdapter');
}
return (_b = __classPrivateFieldGet(this, _CPK_ethLibAdapter, "f")) === 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, _CPK_ethLibAdapter, "f")) {
throw new Error('CPK ethLibAdapter uninitialized');
}
return (_a = __classPrivateFieldGet(this, _CPK_ethLibAdapter, "f")) === 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, _CPK_safeAppsSdkConnector, "f")) === null || _a === void 0 ? void 0 : _a.isSafeApp) {
const networkName = (yield __classPrivateFieldGet(this, _CPK_safeAppsSdkConnector, "f").getSafeInfo()).network;
return networks_2.getNetworkIdFromName(networkName);
}
if (!__classPrivateFieldGet(this, _CPK_ethLibAdapter, "f")) {
throw new Error('CPK ethLibAdapter uninitialized');
}
return __classPrivateFieldGet(this, _CPK_ethLibAdapter, "f").getNetworkId();
});
}
/**
* Returns the safeAppsSdkConnector used by the CPK.
*
* @returns The safeAppsSdkConnector used by the CPK
*/
get safeAppsSdkConnector() {
return __classPrivateFieldGet(this, _CPK_safeAppsSdkConnector, "f");
}
/**
* Returns the contractManager used by the CPK.
*
* @returns The contractManager used by the CPK
*/
get contractManager() {
return __classPrivateFieldGet(this, _CPK_contractManager, "f");
}
/**
* Returns the ethLibAdapter used by the CPK.
*
* @returns The ethLibAdapter used by the CPK
*/
get ethLibAdapter() {
return __classPrivateFieldGet(this, _CPK_ethLibAdapter, "f");
}
/**
* 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, _CPK_networks, "f");
}
/**
* 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, _CPK_isConnectedToSafe, "f");
}
/**
* 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, _CPK_saltNonce, "f");
}
/**
* 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, _CPK_safeAppsSdkConnector, "f")) === null || _a === void 0 ? void 0 : _a.safeAddress) {
return (_b = __classPrivateFieldGet(this, _CPK_safeAppsSdkConnector, "f")) === null || _b === void 0 ? void 0 : _b.safeAddress;
}
return (_d = (_c = __classPrivateFieldGet(this, _CPK_contractManager, "f")) === 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, _CPK_ethLibAdapter, ethLibAdapter, "f");
}
/**
* Sets the transactionManager used by the CPK.
*/
setTransactionManager(transactionManager) {
var _a;
if ((_a = __classPrivateFieldGet(this, _CPK_safeAppsSdkConnector, "f")) === 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, _CPK_transactionManager, transactionManager, "f");
}
/**
* Sets the network configuration used by the CPK.
*/
setNetworks(networks) {
__classPrivateFieldSet(this, _CPK_networks, networks_1.normalizeNetworksConfig(networks_1.defaultNetworks, networks), "f");
}
/**
* 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, _CPK_ethLibAdapter, "f")) {
throw new Error('CPK ethLibAdapter uninitialized');
}
const multiSend = ((_a = __classPrivateFieldGet(this, _CPK_contractManager, "f")) === null || _a === void 0 ? void 0 : _a.multiSend) || __classPrivateFieldGet(this, _CPK_ethLibAdapter, "f").getContract(MultiSendAbi_json_1.default);
const standardizedTxs = transactions.map(transactions_1.standardizeTransaction);
const ethLibAdapter = __classPrivateFieldGet(this, _CPK_ethLibAdapter, "f");
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, _CPK_safeAppsSdkConnector, "f")) === null || _a === void 0 ? void 0 : _a.isSafeApp) && transactions.length >= 1) {
return __classPrivateFieldGet(this, _CPK_safeAppsSdkConnector, "f").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, _CPK_contractManager, "f")) {
throw new Error('CPK contractManager uninitialized');
}
if (!__classPrivateFieldGet(this, _CPK_ethLibAdapter, "f")) {
throw new Error('CPK ethLibAdapter uninitialized');
}
if (!__classPrivateFieldGet(this, _CPK_transactionManager, "f")) {
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, _CPK_ethLibAdapter, "f").getCode(address);
const isDeployed = codeAtAddress !== '0x';
const txManager = !isDeployed ? new CpkTransactionManager_1.default() : __classPrivateFieldGet(this, _CPK_transactionManager, "f");
return txManager.execTransactions({
ownerAccount,
safeExecTxParams,
transactions: standardizedTxs,
ethLibAdapter: __classPrivateFieldGet(this, _CPK_ethLibAdapter, "f"),
contractManager: __classPrivateFieldGet(this, _CPK_contractManager, "f"),
saltNonce: __classPrivateFieldGet(this, _CPK_saltNonce, "f"),
isDeployed,
isConnectedToSafe: __classPrivateFieldGet(this, _CPK_isConnectedToSafe, "f"),
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, _CPK_contractManager, "f")) === null || _a === void 0 ? void 0 : _a.versionUtils)) {
throw new Error('CPK contractManager uninitialized');
}
return yield __classPrivateFieldGet(this, _CPK_contractManager, "f").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, _CPK_contractManager, "f")) === null || _a === void 0 ? void 0 : _a.versionUtils)) {
throw new Error('CPK contractManager uninitialized');
}
return yield __classPrivateFieldGet(this, _CPK_contractManager, "f").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, _CPK_contractManager, "f")) === null || _a === void 0 ? void 0 : _a.versionUtils)) {
throw new Error('CPK contractManager uninitialized');
}
return yield __classPrivateFieldGet(this, _CPK_contractManager, "f").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, _CPK_contractManager, "f")) === 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, _CPK_contractManager, "f").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, _CPK_contractManager, "f")) === 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, _CPK_contractManager, "f").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, _CPK_contractManager, "f")) === null || _a === void 0 ? void 0 : _a.multiSend)) {
throw new Error('CPK MultiSend uninitialized');
}
return {
to: (_b = __classPrivateFieldGet(this, _CPK_contractManager, "f")) === null || _b === void 0 ? void 0 : _b.multiSend.address,
value: '0',
data: this.encodeMultiSendCallData(transactions),
operation: CPK.DelegateCall
};
}
}
_CPK_safeAppsSdkConnector = new WeakMap(), _CPK_ethLibAdapter = new WeakMap(), _CPK_transactionManager = new WeakMap(), _CPK_contractManager = new WeakMap(), _CPK_networks = new WeakMap(), _CPK_ownerAccount = new WeakMap(), _CPK_saltNonce = new WeakMap(), _CPK_isConnectedToSafe = new WeakMap();
CPK.Call = transactions_1.OperationType.Call;
CPK.DelegateCall = transactions_1.OperationType.DelegateCall;
exports.default = CPK;
//# sourceMappingURL=CPK.js.map