Skip to content

Commit

Permalink
Merge pull request #321 from tokamak-network/feat/set-safe-for-DAO
Browse files Browse the repository at this point in the history
  • Loading branch information
theo-learner authored Feb 28, 2025
2 parents 559d0ab + 3993544 commit bcae5f5
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/slither-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
# Install pnpm and dependencies
- name: Install pnpm and dependencies
run: |
npm install --global pnpm
npm install --global pnpm@9.7.1
- name: Restore PNPM Package Cache
uses: actions/cache@v4
Expand Down
2 changes: 2 additions & 0 deletions packages/tokamak/contracts-bedrock/scripts/start-deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ buildSource() {
make cannon-prestate
make op-node
cd $projectRoot/packages/tokamak/contracts-bedrock && pnpm build
cd $projectRoot/packages/tokamak/core-utils && pnpm build
cd $projectRoot/packages/tokamak/sdk && pnpm build
cd $currentPWD
}

Expand Down
1 change: 1 addition & 0 deletions packages/tokamak/sdk/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './misc-utils'
export * from './merkle-utils'
export * from './chain-constants'
export * from './message-utils'
export * from './owners'
38 changes: 38 additions & 0 deletions packages/tokamak/sdk/src/utils/owners.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export enum Chains {
Mainnet = 1,
Sepolia = 11155111,
LocalDevnet = 900,
}

/**
* Get DAO members with chain id
*
* @param chainid - Chain ID
* @returns [foundation, dao] Pre-defined owner addresses
* @throws Throw an error if the chain is not supported.
*/
export const getDAOMembers = (chainid: number): [string, string] => {
if (chainid === Chains.Mainnet) {
// Mainnet
return [
'0x0Fd5632f3b52458C31A2C3eE1F4b447001872Be9',
'0x61dc95E5f27266b94805ED23D95B4C9553A3D049',
// '0xDD9f0cCc044B0781289Ee318e5971b0139602C26', // TokamakDAO
]
} else if (chainid === Chains.Sepolia) {
// Sepolia
return [
'0x0Fd5632f3b52458C31A2C3eE1F4b447001872Be9',
'0x61dc95E5f27266b94805ED23D95B4C9553A3D049',
// '0xA2101482b28E3D99ff6ced517bA41EFf4971a386', // TokamakDAO
]
} else if (chainid === Chains.LocalDevnet) {
// LocalDevnet (for testing)
return [
'0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65', // devAccount-4
'0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc', // devAccount-5
]
} else {
throw new Error('It is not a supported chain')
}
}
1 change: 1 addition & 0 deletions packages/tokamak/sdk/tasks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ import './withdraw-fee'
import './portals'
import './verify-bytecode'
import './estimate-tx-cost'
import './set-safe-for-dao'
98 changes: 98 additions & 0 deletions packages/tokamak/sdk/tasks/set-safe-for-dao.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { ethers } from 'ethers'
import { task, types } from 'hardhat/config'
import { executeContractCallWithSigners } from '@tokamak-network/thanos-contracts/lib/safe-contracts/src/utils/execution'

import { getDAOMembers } from '../src/utils/owners'

/**
* Adds the specified owner to the Gnosis Safe and verifies that the owner has been added.
*
* @param safeContract - The Gnosis Safe contract instance (with signer connected)
* @param owner - The owner address to add
* @param threshold - The threshold value to apply
* @param signers - An array of signers (typically a single signer)
*/
export const addOwnerAndVerify = async (
safeContract: ethers.Contract,
owner: string,
threshold: number,
signers: ethers.Signer[]
): Promise<void> => {
// Execute addOwnerWithThreshold
const tx = await executeContractCallWithSigners(
safeContract,
safeContract,
'addOwnerWithThreshold',
[owner, threshold],
signers
)
console.log(`Tx Hash for adding owner ${owner}:`, tx.hash)
await tx.wait()

// Get Safe owner
const safeOwners = await safeContract.getOwners()
console.log(`Safe owners after adding owner ${owner}:`, safeOwners)
if (safeOwners.includes(owner)) {
console.log(`Successfully added owner: ${owner}`)
} else {
console.log(`Failed to add owner: ${owner}`)
}
}

// Task
task('set-safe-wallet', 'Set Safe Wallet for the TokamakDAO')
.addParam('rpc', 'L1 RPC endpoint', '', types.string)
.addParam('chainid', 'L1 chain id', '', types.int)
.addParam('privatekey', 'Admin Private key', '', types.string)
.addParam('address', 'Gnosis Safe contract address', '', types.string)
.setAction(async (args) => {
const l1Provider = new ethers.providers.StaticJsonRpcProvider(args.rpc)

// Create the signer
// TODO: Get the Admin's private key from the seed phrase (user's input)
const ownerAPrivateKey = args.privatekey
const signer = new ethers.Wallet(ownerAPrivateKey, l1Provider)

// Get predefined owners
const owners = getDAOMembers(args.chainid)

// ABIs of Gnosis Safe
const gnosisSafeAbi = [
'function getThreshold() view returns (uint256)',
'function addOwnerWithThreshold(address owner, uint256 _threshold) external',
'function changeThreshold(uint256 _threshold) external',
'function execTransaction(address to, uint256 value, bytes calldata data, uint8 operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes calldata signatures) external returns (bool success)',
'function nonce() view returns (uint256)',
'function getOwners() view returns (address[])',
]

// Create contract instance
const gnosisSafeContract = new ethers.Contract(
args.address,
gnosisSafeAbi,
signer
)
console.log('Gnosis Safe Contract:', gnosisSafeContract.address)

// Execute
try {
// Add 2 owners to Safe
await addOwnerAndVerify(gnosisSafeContract, owners[0], 1, [signer])
await addOwnerAndVerify(gnosisSafeContract, owners[1], 1, [signer])

// Change threshold to 3
const tx3 = await executeContractCallWithSigners(
gnosisSafeContract,
gnosisSafeContract,
'changeThreshold',
[3],
[signer]
)
console.log('Tx 3 Hash:', tx3.hash)
await tx3.wait()
const newSafeThreshold = await gnosisSafeContract.getThreshold()
console.log('New threshold:', String(newSafeThreshold))
} catch (error) {
console.error('Got the error running Safe contract:', error)
}
})

0 comments on commit bcae5f5

Please sign in to comment.