Skip to content

Commit

Permalink
add txServiceUrl in safe config
Browse files Browse the repository at this point in the history
  • Loading branch information
RnkSngh committed Nov 13, 2024
1 parent 4970243 commit 8e57e56
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 47 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@open-ibc/vibc-core-smart-contracts",
"version": "4.0.9",
"version": "4.0.10",
"main": "dist/index.js",
"bin": {
"verify-vibc-core-smart-contracts": "./dist/scripts/verify-contract-script.js",
Expand Down
3 changes: 3 additions & 0 deletions src/evm/schemas/multisig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const uninitializedMultisigConfig = z
privateKey: z.string().min(1),
owners: z.array(z.string().min(1)),
threshold: z.number(),
txServiceUrl: z.string().optional()
})
.strict();

Expand All @@ -18,6 +19,7 @@ export const initializedMultisigConfig = z
chainId: z.number(),
privateKey: z.string().min(1),
safeAddress: z.string().min(1),
txServiceUrl: z.string().optional(),
})
.strict();

Expand All @@ -37,6 +39,7 @@ export const initializedMultisig = z.object({
privateKey: z.string().min(1),
safeAddress: z.string().min(1),
wallet: wallet,
txServiceUrl: z.string().optional(),
});

export type UninitializedMultisigConfig = z.infer<
Expand Down
112 changes: 75 additions & 37 deletions src/multisig/safe.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import SafeApiKit from "@safe-global/api-kit";
import Safe, { SafeFactory } from "@safe-global/protocol-kit";
import {
MetaTransactionData,
OperationType,
SafeTransactionDataPartial,
TransactionResult,
} from "@safe-global/safe-core-sdk-types";
import { ethers } from "ethers";
import { InitializedMultisig } from "../evm/schemas/multisig";

/*
* Init a safe owner from a given private key to a give RPC's network
Expand Down Expand Up @@ -37,36 +37,31 @@ export const newSafeFromOwner = async (
* @param data Propose a transaction from a signer account
*/
export async function proposeTransaction(
safeAddress: string,
initializedMultisig: InitializedMultisig,
toAddress: string,
txData: string,
proposerPrivateKey: string,
chainId: bigint,
rpcUrl: string,
nonce: number,
value = "0",
operation = OperationType.Call
) {
const apiKit = new SafeApiKit({ chainId });
console.log(
`proposing transaction from \n \n @safe ${initializedMultisig.safeAddress} to ${toAddress} with value: ${value} and data: ${txData}, and nonce : ${nonce}`
);

const txProposer = await Safe.init({
provider: rpcUrl,
signer: proposerPrivateKey,
safeAddress: safeAddress,
signer: initializedMultisig.wallet.privateKey,
safeAddress: initializedMultisig.safeAddress,
});

console.log(
`proposing transaction from ${txProposer} @safe ${safeAddress} to ${toAddress} with value: ${value} and data: ${txData}, and nonce : ${nonce}`
);

const txProposerAddress = new ethers.Wallet(proposerPrivateKey).address;
const txProposerAddress = initializedMultisig.wallet.address;

const safeTransactionData: SafeTransactionDataPartial = {
const safeTransactionData: MetaTransactionData = {
to: toAddress,
value,
data: txData,
operation: operation,
nonce,
};

const safeTransaction = await txProposer.createTransaction({
Expand All @@ -76,43 +71,86 @@ export async function proposeTransaction(
const safeTxHash = await txProposer.getTransactionHash(safeTransaction);

const proposerSignature = await txProposer.signHash(safeTxHash);

// Propose transaction to the service
await apiKit.proposeTransaction({
safeAddress,
safeTransactionData: safeTransaction.data,
safeTxHash,
senderAddress: txProposerAddress,
senderSignature: proposerSignature.data,
});

console.log(
`Transaction has been proposed with hash: ${safeTxHash} from address ${txProposerAddress}`
);
return await apiKit.getTransaction(safeTxHash);
if (initializedMultisig.txServiceUrl) {
// For custom tx services, we have to submit our own http request since it seems like the safeApiKit.proposeTransaction method isn't compatible with some tx service urls

const url = `${initializedMultisig.txServiceUrl}/v1/chains/${initializedMultisig.chainId}/transactions/${initializedMultisig.safeAddress}/propose`;
const body = JSON.stringify({
...safeTransaction.data,
nonce: nonce.toString(),
signature: proposerSignature.data,
sender: txProposerAddress,
safeTxHash,
});

console.log(`proposing transaction to tx service:${url} \n `);
console.log(`with body${body}`);
try {
const res = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body,
});

const json = await res.json();

if (!res.ok) {
console.log(
`received non 200 response from tx service ${res.status} ${json.message}`
);
}
return json;
} catch (e) {
console.log(
`error sending pending multisig tx to tx service ${initializedMultisig.txServiceUrl}`,
e
);

return;
}
} else {
const apiKit = new SafeApiKit({
chainId: BigInt(initializedMultisig.chainId),
});
// Propose transaction to the service
await apiKit.proposeTransaction({
safeAddress: initializedMultisig.safeAddress,
safeTransactionData: safeTransaction.data,
safeTxHash,
senderAddress: txProposerAddress,
senderSignature: proposerSignature.data,
});
console.log(
`Transaction has been proposed with hash: ${safeTxHash} from address ${txProposerAddress}`
);
return await apiKit.getTransaction(safeTxHash);
}
}

/**
* Execute a multisig tx from an account generated from proposeTransaction
*/
export const executeMultisigTx = async (
safeAddress: string,
executorPrivateKey: string,
chainId: bigint,
initializedMultisig: InitializedMultisig,
rpcUrl: string,
pendingTransactionIndex: number
):Promise<TransactionResult> => {
): Promise<TransactionResult> => {
const apiKit = new SafeApiKit({
chainId,
chainId: BigInt(initializedMultisig.chainId),
txServiceUrl: initializedMultisig.txServiceUrl,
});

const executor = await Safe.init({
provider: rpcUrl,
signer: executorPrivateKey,
safeAddress,
signer: initializedMultisig.wallet.privateKey,
safeAddress: initializedMultisig.safeAddress,
});

const transactions = await apiKit.getPendingTransactions(safeAddress);
const transactions = await apiKit.getPendingTransactions(
initializedMultisig.safeAddress
);

if (transactions.results.length <= pendingTransactionIndex) {
throw new Error(
Expand Down
6 changes: 1 addition & 5 deletions src/scripts/execute-multisig-tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,8 @@ async function main() {
throw new Error("Can only execute transactions on a multisig wallet");
}

const privateKey = accounts.getSinglePrivateKeyFromAccount(executor);

executeMultisigTx(
multisigAccount.safeAddress,
privateKey,
BigInt(multisigAccount.chainId),
multisigAccount,
rpcUrl,
txIndex
);
Expand Down
4 changes: 1 addition & 3 deletions src/tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,9 @@ export async function sendTx(
);

proposeTransaction(
account.safeAddress,
account,
deployedContractAddress,
callData,
account.wallet.privateKey,
BigInt(chain.chainId),
chain.rpc,
updatedNonces[account.safeAddress]
);
Expand Down
2 changes: 1 addition & 1 deletion src/utils/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,6 @@ export const saveMultisigAddressToAccountsSpec = async (
accountsSpecPath: string,
chainId: number,
ownerName: string // Used to find which owner to write to,

) => {
// TODO: Currently this yaml lib doesn't include comments - we need to figure out a way to preserve comments / whitespaces, etc
const yamlFile = readYamlFile(accountsSpecPath);
Expand All @@ -532,6 +531,7 @@ export const saveMultisigAddressToAccountsSpec = async (
chainId,
safeAddress: newSafeAddress,
privateKey: account.privateKey,
txServiceUrl: account.txServiceUrl
};
});

Expand Down

0 comments on commit 8e57e56

Please sign in to comment.