-
Notifications
You must be signed in to change notification settings - Fork 226
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sdk-starter-kit): Add owner management methods (#949)
- Loading branch information
Showing
6 changed files
with
256 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import Safe, { | ||
AddOwnerTxParams, | ||
RemoveOwnerTxParams, | ||
SwapOwnerTxParams | ||
} from '@safe-global/protocol-kit' | ||
import SafeApiKit from '@safe-global/api-kit' | ||
import { TransactionBase } from '@safe-global/safe-core-sdk-types' | ||
|
||
import { ChangeThresholdTxParams } from './types' | ||
|
||
export class BaseClient { | ||
protocolKit: Safe | ||
apiKit: SafeApiKit | ||
|
||
constructor(protocolKit: Safe, apiKit: SafeApiKit) { | ||
this.protocolKit = protocolKit | ||
this.apiKit = apiKit | ||
} | ||
|
||
/** | ||
* Returns the Safe address. | ||
* | ||
* @returns {string} The Safe address | ||
*/ | ||
async getAddress(): Promise<string> { | ||
return this.protocolKit.getAddress() | ||
} | ||
|
||
/** | ||
* Checks if the current Safe is deployed. | ||
* | ||
* @returns {boolean} if the Safe contract is deployed | ||
*/ | ||
async isDeployed(): Promise<boolean> { | ||
return this.protocolKit.isSafeDeployed() | ||
} | ||
|
||
/** | ||
* Checks if a specific address is an owner of the current Safe. | ||
* | ||
* @param {string} ownerAddress - The account address | ||
* @returns {boolean} TRUE if the account is an owner | ||
*/ | ||
async isOwner(ownerAddress: string): Promise<boolean> { | ||
return this.protocolKit.isOwner(ownerAddress) | ||
} | ||
|
||
/** | ||
* Returns the list of Safe owner accounts. | ||
* | ||
* @returns The list of owners | ||
*/ | ||
async getOwners(): Promise<string[]> { | ||
return this.protocolKit.getOwners() | ||
} | ||
|
||
/** | ||
* Returns the Safe threshold. | ||
* | ||
* @returns {number} The Safe threshold | ||
*/ | ||
async getThreshold(): Promise<number> { | ||
return this.protocolKit.getThreshold() | ||
} | ||
|
||
/** | ||
* Returns the Safe nonce. | ||
* | ||
* @returns {number} The Safe nonce | ||
*/ | ||
async getNonce(): Promise<number> { | ||
return this.protocolKit.getNonce() | ||
} | ||
|
||
/** | ||
* Returns a list of owners who have approved a specific Safe transaction. | ||
* | ||
* @param {string} txHash - The Safe transaction hash | ||
* @returns {string[]} The list of owners | ||
*/ | ||
async getOwnersWhoApprovedTx(txHash: string): Promise<string[]> { | ||
return this.protocolKit.getOwnersWhoApprovedTx(txHash) | ||
} | ||
|
||
/** | ||
* Encodes the data for adding a new owner to the Safe. | ||
* | ||
* @param {AddOwnerTxParams} params - The parameters for adding a new owner | ||
* @param {string} params.ownerAddress - The address of the owner to add | ||
* @param {number} params.threshold - The threshold of the Safe | ||
* @returns {TransactionBase} The encoded data | ||
*/ | ||
async createAddOwnerTransaction({ | ||
ownerAddress, | ||
threshold | ||
}: AddOwnerTxParams): Promise<TransactionBase> { | ||
const ownerManager = this.protocolKit.getOwnerManager() | ||
|
||
return this.#buildTransaction( | ||
await ownerManager.encodeAddOwnerWithThresholdData(ownerAddress, threshold) | ||
) | ||
} | ||
|
||
/** | ||
* Encodes the data for removing an owner from the Safe. | ||
* | ||
* @param {RemoveOwnerTxParams} params - The parameters for removing an owner | ||
* @param {string} params.ownerAddress - The address of the owner to remove | ||
* @param {number} params.threshold - The threshold of the Safe | ||
* @returns {TransactionBase} The encoded data | ||
*/ | ||
async createRemoveOwnerTransaction({ | ||
ownerAddress, | ||
threshold | ||
}: RemoveOwnerTxParams): Promise<TransactionBase> { | ||
const ownerManager = this.protocolKit.getOwnerManager() | ||
|
||
return this.#buildTransaction(await ownerManager.encodeRemoveOwnerData(ownerAddress, threshold)) | ||
} | ||
|
||
/** | ||
* Encodes the data for swapping an owner in the Safe. | ||
* | ||
* @param {SwapOwnerTxParams} params - The parameters for swapping an owner | ||
* @param {string} params.oldOwnerAddress - The address of the old owner | ||
* @param {string} params.newOwnerAddress - The address of the new owner | ||
* @returns {TransactionBase} The encoded data | ||
*/ | ||
async createSwapOwnerTransaction({ | ||
oldOwnerAddress, | ||
newOwnerAddress | ||
}: SwapOwnerTxParams): Promise<TransactionBase> { | ||
const ownerManager = this.protocolKit.getOwnerManager() | ||
|
||
return this.#buildTransaction( | ||
await ownerManager.encodeSwapOwnerData(oldOwnerAddress, newOwnerAddress) | ||
) | ||
} | ||
|
||
/** | ||
* Encodes the data for changing the Safe threshold. | ||
* | ||
* @param {ChangeThresholdTxParams} params - The parameters for changing the Safe threshold | ||
* @param {number} params.threshold - The new threshold | ||
* @returns {TransactionBase} The encoded data | ||
*/ | ||
async createChangeThresholdTransaction({ | ||
threshold | ||
}: ChangeThresholdTxParams): Promise<TransactionBase> { | ||
const ownerManager = this.protocolKit.getOwnerManager() | ||
|
||
return this.#buildTransaction(await ownerManager.encodeChangeThresholdData(threshold)) | ||
} | ||
|
||
async #buildTransaction(encodedData: string): Promise<TransactionBase> { | ||
return { | ||
to: await this.protocolKit.getAddress(), | ||
value: '0', | ||
data: encodedData | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { createSafeClient } from '@safe-global/sdk-starter-kit' | ||
|
||
const OWNER_1_PRIVATE_KEY = '' | ||
const OWNER_2_PRIVATE_KEY = '' | ||
const OWNER_2_ADDRESS = '' | ||
|
||
const RPC_URL = 'https://sepolia.gateway.tenderly.co' | ||
const SAFE_ADDRESS = '' | ||
|
||
async function addOwner() { | ||
const safeClient = await createSafeClient({ | ||
provider: RPC_URL, | ||
signer: OWNER_1_PRIVATE_KEY, | ||
safeAddress: SAFE_ADDRESS | ||
}) | ||
|
||
const transaction = await safeClient.createAddOwnerTransaction({ | ||
ownerAddress: OWNER_2_ADDRESS, | ||
threshold: 2 | ||
}) | ||
|
||
const transactionResult = await safeClient.send({ transactions: [transaction] }) | ||
|
||
console.log('Add Owner Transaction Result', transactionResult) | ||
} | ||
|
||
async function removeOwner() { | ||
const safeClient1 = await createSafeClient({ | ||
provider: RPC_URL, | ||
signer: OWNER_1_PRIVATE_KEY, | ||
safeAddress: SAFE_ADDRESS | ||
}) | ||
|
||
const safeClient2 = await createSafeClient({ | ||
provider: RPC_URL, | ||
signer: OWNER_2_PRIVATE_KEY, | ||
safeAddress: SAFE_ADDRESS | ||
}) | ||
|
||
const transaction = await safeClient1.createRemoveOwnerTransaction({ | ||
ownerAddress: OWNER_2_ADDRESS, | ||
threshold: 1 | ||
}) | ||
const sendResult = await safeClient1.send({ transactions: [transaction] }) | ||
|
||
const transactionResult = await safeClient2.confirm({ | ||
safeTxHash: sendResult.transactions?.safeTxHash || '' | ||
}) | ||
console.log('Remove Owner Transaction Result', transactionResult) | ||
} | ||
|
||
async function safeInfo() { | ||
const safeClient = await createSafeClient({ | ||
provider: RPC_URL, | ||
signer: OWNER_1_PRIVATE_KEY, | ||
safeAddress: SAFE_ADDRESS | ||
}) | ||
|
||
console.log('Safe Address', await safeClient.protocolKit.getAddress()) | ||
console.log('Owners', await safeClient.getOwners()) | ||
console.log('Threshold', await safeClient.getThreshold()) | ||
console.log('Nonce', await safeClient.getNonce()) | ||
} | ||
|
||
async function main() { | ||
await safeInfo() | ||
await addOwner() | ||
|
||
console.log('Waiting for transaction to be indexed ...') | ||
setTimeout(async () => { | ||
await safeInfo() | ||
await removeOwner() | ||
}, 10000) | ||
} | ||
|
||
main() |