Skip to content

Commit

Permalink
remove useMemo
Browse files Browse the repository at this point in the history
  • Loading branch information
mjlescano committed Sep 15, 2024
1 parent 3325ac1 commit e45311d
Showing 1 changed file with 148 additions and 164 deletions.
312 changes: 148 additions & 164 deletions packages/website/src/hooks/cannon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
publishPackage,
} from '@usecannon/builder';
import _ from 'lodash';
import { useEffect, useMemo, useState } from 'react';
import { useEffect, useState } from 'react';
import { Abi, Address, createPublicClient, createTestClient, createWalletClient, custom, Hex, isAddressEqual } from 'viem';
import { useChainId } from 'wagmi';
// Needed to prepare mock run step with registerAction
Expand Down Expand Up @@ -95,206 +95,190 @@ export function useCannonBuild(safe: SafeDefinition | null, def?: ChainDefinitio
const { getChainById } = useCannonChains();
const createFork = useCreateFork();

return useMemo(() => {
const buildFn = async () => {
// Wait until finished loading
if (!safe || !def || !prevDeploy) {
throw new Error('Missing required parameters');
}

const chain = getChainById(safe.chainId);
const buildFn = async () => {
// Wait until finished loading
if (!safe || !def || !prevDeploy) {
throw new Error('Missing required parameters');
}

setBuildStatus('Creating fork...');
// eslint-disable-next-line no-console
console.log(`Creating fork with RPC: ${chain?.rpcUrls.default.http[0]}`);
const fork = await createFork({
chainId: safe.chainId,
impersonate: [safe.address],
url: chain?.rpcUrls.default.http[0],
}).catch((err) => {
err.message = `Could not create local fork for build: ${err.message}`;
throw err;
});
const chain = getChainById(safe.chainId);

const ipfsLoader = new IPFSBrowserLoader(settings.ipfsApiUrl || externalLinks.IPFS_CANNON);
setBuildStatus('Creating fork...');
// eslint-disable-next-line no-console
console.log(`Creating fork with RPC: ${chain?.rpcUrls.default.http[0]}`);
const fork = await createFork({
chainId: safe.chainId,
impersonate: [safe.address],
url: chain?.rpcUrls.default.http[0],
}).catch((err) => {
err.message = `Could not create local fork for build: ${err.message}`;
throw err;
});

setBuildStatus('Loading deployment data...');
const ipfsLoader = new IPFSBrowserLoader(settings.ipfsApiUrl || externalLinks.IPFS_CANNON);

addLog('info', `cannon.ts: upgrade from: ${prevDeploy?.def.name}:${prevDeploy?.def.version}`);
setBuildStatus('Loading deployment data...');

const transport = custom(fork);
addLog('info', `cannon.ts: upgrade from: ${prevDeploy?.def.name}:${prevDeploy?.def.version}`);

const provider = createPublicClient({
chain,
transport,
});
const transport = custom(fork);

const testProvider = createTestClient({
chain,
transport,
mode: 'ganache',
});
const provider = createPublicClient({
chain,
transport,
});

// todo: as usual viem provider types refuse to work
await loadPrecompiles(testProvider as any);
const testProvider = createTestClient({
chain,
transport,
mode: 'ganache',
});

const wallet = createWalletClient({
account: safe.address,
chain: getChainById(safe.chainId),
transport,
});
// todo: as usual viem provider types refuse to work
await loadPrecompiles(testProvider as any);

const getDefaultSigner = async () => ({ address: safe.address, wallet });
const wallet = createWalletClient({
account: safe.address,
chain: getChainById(safe.chainId),
transport,
});

const loaders = { mem: inMemoryLoader, ipfs: ipfsLoader };
const getDefaultSigner = async () => ({ address: safe.address, wallet });

const getSigner = async (addr: Address) => {
if (!isAddressEqual(addr, safe.address)) {
throw new Error(`Could not get signer for "${addr}"`);
}
const loaders = { mem: inMemoryLoader, ipfs: ipfsLoader };

return getDefaultSigner();
};

currentRuntime = new ChainBuilderRuntime(
{
provider: provider as any, // TODO: fix type
chainId: safe.chainId,
getSigner: getSigner as any, // TODO: fix type
getDefaultSigner: getDefaultSigner as any, // TODO: fix type
snapshots: false,
allowPartialDeploy: true,
},
fallbackRegistry,
loaders
);
const getSigner = async (addr: Address) => {
if (!isAddressEqual(addr, safe.address)) {
throw new Error(`Could not get signer for "${addr}"`);
}

const simulatedSteps: ChainArtifacts[] = [];
const skippedSteps: StepExecutionError[] = [];
return getDefaultSigner();
};

currentRuntime.on(
Events.PostStepExecute,
(stepType: string, stepLabel: string, stepConfig: any, stepCtx: ChainBuilderContext, stepOutput: ChainArtifacts) => {
const stepName = `${stepType}.${stepLabel}`;
currentRuntime = new ChainBuilderRuntime(
{
provider: provider as any, // TODO: fix type
chainId: safe.chainId,
getSigner: getSigner as any, // TODO: fix type
getDefaultSigner: getDefaultSigner as any, // TODO: fix type
snapshots: false,
allowPartialDeploy: true,
},
fallbackRegistry,
loaders
);

addLog('info', `cannon.ts: on Events.PostStepExecute operation ${stepName} output: ${JSON.stringify(stepOutput)}`);
const simulatedSteps: ChainArtifacts[] = [];
const skippedSteps: StepExecutionError[] = [];

simulatedSteps.push(_.cloneDeep(stepOutput));
currentRuntime.on(
Events.PostStepExecute,
(stepType: string, stepLabel: string, stepConfig: any, stepCtx: ChainBuilderContext, stepOutput: ChainArtifacts) => {
const stepName = `${stepType}.${stepLabel}`;

for (const txn in stepOutput.txns || {}) {
// clean out txn hash
stepOutput.txns![txn].hash = '';
}
addLog('info', `cannon.ts: on Events.PostStepExecute operation ${stepName} output: ${JSON.stringify(stepOutput)}`);

setBuildStatus(`Building ${stepName}...`);
simulatedSteps.push(_.cloneDeep(stepOutput));

// a step that deploys a contract is a step that has no txns deployed but contract(s) deployed
if (_.keys(stepOutput.txns).length === 0 && _.keys(stepOutput.contracts).length > 0) {
throw new Error(`Cannot deploy contract on a Safe transaction for step ${stepName}`);
}
for (const txn in stepOutput.txns || {}) {
// clean out txn hash
stepOutput.txns![txn].hash = '';
}
);

currentRuntime.on(Events.SkipDeploy, (stepName: string, err: Error) => {
addLog('error', `cannon.ts: on Events.SkipDeploy error ${err.toString()} happened on the operation ${stepName}`);
skippedSteps.push({ name: stepName, err });
});
setBuildStatus(`Building ${stepName}...`);

currentRuntime.on(Events.Notice, (stepName: string, msg: string) => {
addLog('warn', `${stepName}: ${msg}`);
});

if (prevDeploy) {
await currentRuntime.restoreMisc(prevDeploy.miscUrl);
// a step that deploys a contract is a step that has no txns deployed but contract(s) deployed
if (_.keys(stepOutput.txns).length === 0 && _.keys(stepOutput.contracts).length > 0) {
throw new Error(`Cannot deploy contract on a Safe transaction for step ${stepName}`);
}
}
);

const ctx = await createInitialContext(def, prevDeploy?.meta || {}, safe.chainId, prevDeploy?.options || {});
currentRuntime.on(Events.SkipDeploy, (stepName: string, err: Error) => {
addLog('error', `cannon.ts: on Events.SkipDeploy error ${err.toString()} happened on the operation ${stepName}`);
skippedSteps.push({ name: stepName, err });
});

const newState = await cannonBuild(currentRuntime, def, _.cloneDeep(prevDeploy?.state) ?? {}, ctx);
currentRuntime.on(Events.Notice, (stepName: string, msg: string) => {
addLog('warn', `${stepName}: ${msg}`);
});

setBuildSkippedSteps(skippedSteps);
if (prevDeploy) {
await currentRuntime.restoreMisc(prevDeploy.miscUrl);
}

const simulatedTxs = simulatedSteps
.map((s) => !!s?.txns && Object.values(s.txns))
.filter((tx) => !!tx)
.flat();
const ctx = await createInitialContext(def, prevDeploy?.meta || {}, safe.chainId, prevDeploy?.options || {});

if (simulatedTxs.length === 0) {
throw new Error('There are no transactions that can be executed on Safe.');
}
const newState = await cannonBuild(currentRuntime, def, _.cloneDeep(prevDeploy?.state) ?? {}, ctx);

const steps = await Promise.all(
simulatedTxs.map(async (executedTx) => {
if (!executedTx) throw new Error('Invalid operation');
const tx = await provider.getTransaction({ hash: executedTx.hash as Hex });
const rx = await provider.getTransactionReceipt({ hash: executedTx.hash as Hex });
return {
name: (executedTx as any).deployedOn,
gas: rx.gasUsed,
tx: {
to: tx.to,
value: tx.value.toString(),
data: tx.input,
} as BaseTransaction,
};
})
);
setBuildSkippedSteps(skippedSteps);

if (fork) await fork.disconnect();
const simulatedTxs = simulatedSteps
.map((s) => !!s?.txns && Object.values(s.txns))
.filter((tx) => !!tx)
.flat();

return {
runtime: currentRuntime,
state: newState,
steps,
};
};
if (simulatedTxs.length === 0) {
throw new Error('There are no transactions that can be executed on Safe.');
}

const steps = await Promise.all(
simulatedTxs.map(async (executedTx) => {
if (!executedTx) throw new Error('Invalid operation');
const tx = await provider.getTransaction({ hash: executedTx.hash as Hex });
const rx = await provider.getTransactionReceipt({ hash: executedTx.hash as Hex });
return {
name: (executedTx as any).deployedOn,
gas: rx.gasUsed,
tx: {
to: tx.to,
value: tx.value.toString(),
data: tx.input,
} as BaseTransaction,
};
})
);

if (fork) await fork.disconnect();

return {
finishedBuilding,
isBuilding,
buildStatus,
buildResult,
buildError,
buildSkippedSteps,
doBuild() {
setFinishedBuilding(false);
setBuildResult(null);
setBuildError(null);
setBuildSkippedSteps([]);
setIsBuilding(true);

buildFn()
.then((res) => {
setBuildResult(res);
})
.catch((err) => {
// eslint-disable-next-line no-console
console.error(err);
addLog('error', `cannon.ts: full build error ${err.toString()}`);
setBuildError(err.toString());
})
.finally(() => {
setFinishedBuilding(true);
setIsBuilding(false);
setBuildStatus('');
});
},
runtime: currentRuntime,
state: newState,
steps,
};
}, [
addLog,
buildError,
};

return {
finishedBuilding,
isBuilding,
buildStatus,
buildResult,
buildError,
buildSkippedSteps,
buildStatus,
createFork,
def,
fallbackRegistry,
getChainById,
isBuilding,
prevDeploy,
safe,
settings.ipfsApiUrl,
]);
doBuild() {
setFinishedBuilding(false);
setBuildResult(null);
setBuildError(null);
setBuildSkippedSteps([]);
setIsBuilding(true);

buildFn()
.then((res) => {
setBuildResult(res);
})
.catch((err) => {
// eslint-disable-next-line no-console
console.error(err);
addLog('error', `cannon.ts: full build error ${err.toString()}`);
setBuildError(err.toString());
})
.finally(() => {
setFinishedBuilding(true);
setIsBuilding(false);
setBuildStatus('');
});
},
};
}

export function useCannonWriteDeployToIpfs(
Expand Down

0 comments on commit e45311d

Please sign in to comment.