Add script for adding gnosis safe delegates (#1032)
parent
edbf197d51
commit
e71ac4a5c3
@ -0,0 +1,70 @@ |
||||
import { LedgerSigner } from '@ethersproject/hardware-wallets'; |
||||
// Due to TS funkiness, the following needs to be imported in order for this
|
||||
// code to build, but needs to be removed in order for the code to run.
|
||||
import '@ethersproject/hardware-wallets/thirdparty'; |
||||
import { SafeDelegateConfig } from '@gnosis.pm/safe-service-client'; |
||||
import yargs from 'yargs'; |
||||
|
||||
import { AllChains } from '@abacus-network/sdk'; |
||||
|
||||
import { getSafeDelegates, getSafeService } from '../src/utils/safe'; |
||||
|
||||
import { getCoreEnvironmentConfig, getEnvironment } from './utils'; |
||||
|
||||
function getArgs() { |
||||
return yargs(process.argv.slice(2)) |
||||
.describe('chain', 'chain of the validator to inspect') |
||||
.choices('chain', AllChains) |
||||
.demandOption('chain') |
||||
.describe('action', 'add or remove') |
||||
.choices('action', ['add', 'remove']) |
||||
.demandOption('action') |
||||
.describe('delegate', 'address of the delegate') |
||||
.demandOption('delegate') |
||||
.string('delegate') |
||||
.describe('safe', 'address of the safe') |
||||
.demandOption('safe') |
||||
.string('safe').argv; |
||||
} |
||||
|
||||
async function delegate() { |
||||
const environment = await getEnvironment(); |
||||
const config = getCoreEnvironmentConfig(environment); |
||||
const { chain, delegate, safe, action } = await getArgs(); |
||||
|
||||
const multiProvider = await config.getMultiProvider(); |
||||
const connection = multiProvider.getChainConnection(chain); |
||||
|
||||
const safeService = getSafeService(chain, connection); |
||||
const delegates = await getSafeDelegates(safeService, safe); |
||||
|
||||
// Ledger Live derivation path, vary by changing the index i.e.
|
||||
// "m/44'/60'/{CHANGE_ME}'/0/0";
|
||||
const path = "m/44'/60'/0'/0/0"; |
||||
const signer = new LedgerSigner(undefined, 'hid', path); |
||||
console.log('Connected to signer with address:', await signer.getAddress()); |
||||
|
||||
const delegateConfig: SafeDelegateConfig = { |
||||
safe, |
||||
delegate, |
||||
signer, |
||||
label: 'delegate', |
||||
}; |
||||
|
||||
const baseDescription = `${delegate} as a delegate for ${chain} safe at address ${safe}`; |
||||
if (action === 'add') { |
||||
console.log(`Adding ${baseDescription}`); |
||||
if (delegates.includes(delegate)) |
||||
throw new Error(`${delegate} is already a delegate`); |
||||
await safeService.addSafeDelegate(delegateConfig); |
||||
} else if (action === 'remove') { |
||||
console.log(`Removing ${baseDescription}`); |
||||
if (!delegates.includes(delegate)) |
||||
throw new Error(`${delegate} is not a delegate`); |
||||
await safeService.removeSafeDelegate(delegateConfig); |
||||
} else { |
||||
throw new Error('unsupported action'); |
||||
} |
||||
} |
||||
|
||||
delegate().then(console.log).catch(console.error); |
@ -0,0 +1,53 @@ |
||||
import Safe from '@gnosis.pm/safe-core-sdk'; |
||||
import EthersAdapter from '@gnosis.pm/safe-ethers-lib'; |
||||
import SafeServiceClient from '@gnosis.pm/safe-service-client'; |
||||
import { ethers } from 'ethers'; |
||||
|
||||
import { ChainConnection, ChainName, chainMetadata } from '@abacus-network/sdk'; |
||||
|
||||
export function getSafeService( |
||||
chain: ChainName, |
||||
connection: ChainConnection, |
||||
): SafeServiceClient { |
||||
const signer = connection.signer; |
||||
if (!signer) throw new Error(`no signer found for ${chain}`); |
||||
const ethAdapter = new EthersAdapter({ ethers, signer }); |
||||
const txServiceUrl = chainMetadata[chain].gnosisSafeTransactionServiceUrl; |
||||
if (!txServiceUrl) |
||||
throw new Error(`must provide tx service url for ${chain}`); |
||||
return new SafeServiceClient({ txServiceUrl, ethAdapter }); |
||||
} |
||||
|
||||
export function getSafe( |
||||
connection: ChainConnection, |
||||
safeAddress: string, |
||||
): Promise<Safe> { |
||||
const signer = connection.signer; |
||||
if (!signer) throw new Error(`no signer found`); |
||||
const ethAdapter = new EthersAdapter({ ethers, signer }); |
||||
return Safe.create({ |
||||
ethAdapter, |
||||
safeAddress: safeAddress, |
||||
}); |
||||
} |
||||
|
||||
export async function getSafeDelegates( |
||||
service: SafeServiceClient, |
||||
safe: string, |
||||
) { |
||||
const delegateResponse = await service.getSafeDelegates(safe); |
||||
return delegateResponse.results.map((r) => r.delegate); |
||||
} |
||||
|
||||
export async function canProposeSafeTransactions( |
||||
proposer: string, |
||||
chain: ChainName, |
||||
connection: ChainConnection, |
||||
safeAddress: string, |
||||
): Promise<boolean> { |
||||
const safeService = getSafeService(chain, connection); |
||||
const safe = await getSafe(connection, safeAddress); |
||||
const delegates = await getSafeDelegates(safeService, safeAddress); |
||||
const owners = await safe.getOwners(); |
||||
return delegates.includes(proposer) || owners.includes(proposer); |
||||
} |
Loading…
Reference in new issue