From b478220134704c79c2806310016bd69568d38929 Mon Sep 17 00:00:00 2001 From: Sam McCord Date: Wed, 26 Jun 2024 15:24:02 -0600 Subject: [PATCH] chore: add account to configuration to make some contract ops easier --- packages/sdk/src/BoostClient.ts | 293 +++++++++++----------- packages/sdk/src/Deployable/Contract.ts | 2 +- packages/sdk/src/Deployable/Deployable.ts | 41 ++- 3 files changed, 178 insertions(+), 158 deletions(-) diff --git a/packages/sdk/src/BoostClient.ts b/packages/sdk/src/BoostClient.ts index 3acd946a..9497d862 100644 --- a/packages/sdk/src/BoostClient.ts +++ b/packages/sdk/src/BoostClient.ts @@ -1,4 +1,4 @@ -import { type Config, getAccount } from '@wagmi/core'; +import { getAccount } from '@wagmi/core'; import { createWriteContract } from '@wagmi/core/codegen'; import { type Address, zeroAddress, zeroHash } from 'viem'; import { @@ -29,6 +29,7 @@ import { VestingBudget, type VestingBudgetPayload, } from './Budgets/VestingBudget'; +import type { Config } from './Deployable/Contract'; import type { Deployable, DeployableOptions } from './Deployable/Deployable'; import { AllowListIncentive, @@ -84,151 +85,151 @@ export class BoostClient { this.config = config; } - // TODO make this transactional? if any deployment fails what do we do with the previously deployed deployables? - // TODO revisit this, necessary? - public async *createBoostWithProgress({ - budget, - action, - validator, - allowList, - incentives, - protocolFee = 0n, - referralFee = 0n, - maxParticipants = 0n, - owner = zeroAddress, - }: Omit): AsyncGenerator< - CreateBoostProgress | CreateBoostCompletion, - Address - > { - const boostFactory = createWriteContract({ - abi: boostCoreAbi, - functionName: 'createBoost', - address: this.address, - }); - - if (!owner) { - owner = getAccount(this.config).address || zeroAddress; - if (owner === zeroAddress) { - // throw? TODO - console.warn('No owner supplied, falling back to zeroAddress'); - } - } - - // As we proceed, decrement total steps to indiciate progress to consumer - let remainingSteps = 4 + incentives.length; - - let budgetPayload: Pick = { - budget: budget.address || zeroAddress, - }; - - if (budget.address === zeroAddress) { - budget = await this.deploy(budget); - budgetPayload.budget = budget.address || zeroAddress; - // TODO validate and throw? - } - yield { - remaining: --remainingSteps, - deployed: budget, - }; - - let actionPayload: Pick = { - action: { - isBase: false, - instance: action.address || zeroAddress, - parameters: action.buildParameters(this.config).args.at(0) || zeroHash, - }, - }; - if (actionPayload.action.instance === zeroAddress) { - action = await this.deploy(action); - actionPayload.action.instance = action.address || zeroAddress; - // TODO validate and throw? - } - yield { - remaining: --remainingSteps, - deployed: action, - }; - - let validatorPayload: Pick = { - validator: { - isBase: false, - instance: validator.address || zeroAddress, - parameters: - validator.buildParameters(this.config).args.at(0) || zeroHash, - }, - }; - if (validatorPayload.validator.instance === zeroAddress) { - validator = await this.deploy(validator); - validatorPayload.validator.instance = validator.address || zeroAddress; - // TODO validate and throw? - } - yield { - remaining: --remainingSteps, - deployed: validator, - }; - - let allowListPayload: Pick = { - allowList: { - isBase: false, - instance: allowList.address || zeroAddress, - parameters: - allowList.buildParameters(this.config).args.at(0) || zeroHash, - }, - }; - if (allowListPayload.allowList.instance === zeroAddress) { - allowList = await this.deploy(allowList); - allowListPayload.allowList.instance = allowList.address || zeroAddress; - // TODO validate and throw? - } - yield { - remaining: --remainingSteps, - deployed: allowList, - }; - - let incentivesPayload: Pick = { - incentives: incentives.map((incentive) => ({ - isBase: false, - instance: incentive.address || zeroAddress, - parameters: - incentive.buildParameters(this.config).args.at(0) || zeroHash, - })), - }; - for (let i = 0; i < incentives.length; i++) { - let incentive = incentives.at(i)!; - const incentiveTarget = incentivesPayload.incentives.at(i)!; - - if (incentiveTarget.instance === zeroAddress) { - incentive = await this.deploy(incentive); - incentiveTarget.instance = incentive.address || zeroAddress; - // TODO validate and throw? - } - yield { - remaining: --remainingSteps, - deployed: incentive, - }; - } - - const boostPayload: OnChainBoostPayload = { - ...budgetPayload, - ...actionPayload, - ...validatorPayload, - ...allowListPayload, - ...incentivesPayload, - protocolFee, - referralFee, - maxParticipants, - owner, - }; - - const boost = await boostFactory(this.config, { - args: [prepareBoostPayload(boostPayload)], - }); - - yield { - address: boost, - }; - - return boost; - } + // // TODO make this transactional? if any deployment fails what do we do with the previously deployed deployables? + // // TODO revisit this, necessary? + // public async *createBoostWithProgress({ + // budget, + // action, + // validator, + // allowList, + // incentives, + // protocolFee = 0n, + // referralFee = 0n, + // maxParticipants = 0n, + // owner = zeroAddress, + // }: Omit): AsyncGenerator< + // CreateBoostProgress | CreateBoostCompletion, + // Address + // > { + // const boostFactory = createWriteContract({ + // abi: boostCoreAbi, + // functionName: 'createBoost', + // address: this.address, + // }); + + // if (!owner) { + // owner = getAccount(this.config).address || zeroAddress; + // if (owner === zeroAddress) { + // // throw? TODO + // console.warn('No owner supplied, falling back to zeroAddress'); + // } + // } + + // // As we proceed, decrement total steps to indiciate progress to consumer + // let remainingSteps = 4 + incentives.length; + + // let budgetPayload: Pick = { + // budget: budget.address || zeroAddress, + // }; + + // if (budget.address === zeroAddress) { + // budget = await this.deploy(budget); + // budgetPayload.budget = budget.address || zeroAddress; + // // TODO validate and throw? + // } + // yield { + // remaining: --remainingSteps, + // deployed: budget, + // }; + + // let actionPayload: Pick = { + // action: { + // isBase: false, + // instance: action.address || zeroAddress, + // parameters: action.buildParameters(this.config).args.at(0) || zeroHash, + // }, + // }; + // if (actionPayload.action.instance === zeroAddress) { + // action = await this.deploy(action); + // actionPayload.action.instance = action.address || zeroAddress; + // // TODO validate and throw? + // } + // yield { + // remaining: --remainingSteps, + // deployed: action, + // }; + + // let validatorPayload: Pick = { + // validator: { + // isBase: false, + // instance: validator.address || zeroAddress, + // parameters: + // validator.buildParameters(this.config).args.at(0) || zeroHash, + // }, + // }; + // if (validatorPayload.validator.instance === zeroAddress) { + // validator = await this.deploy(validator); + // validatorPayload.validator.instance = validator.address || zeroAddress; + // // TODO validate and throw? + // } + // yield { + // remaining: --remainingSteps, + // deployed: validator, + // }; + + // let allowListPayload: Pick = { + // allowList: { + // isBase: false, + // instance: allowList.address || zeroAddress, + // parameters: + // allowList.buildParameters(this.config).args.at(0) || zeroHash, + // }, + // }; + // if (allowListPayload.allowList.instance === zeroAddress) { + // allowList = await this.deploy(allowList); + // allowListPayload.allowList.instance = allowList.address || zeroAddress; + // // TODO validate and throw? + // } + // yield { + // remaining: --remainingSteps, + // deployed: allowList, + // }; + + // let incentivesPayload: Pick = { + // incentives: incentives.map((incentive) => ({ + // isBase: false, + // instance: incentive.address || zeroAddress, + // parameters: + // incentive.buildParameters(this.config).args.at(0) || zeroHash, + // })), + // }; + // for (let i = 0; i < incentives.length; i++) { + // let incentive = incentives.at(i)!; + // const incentiveTarget = incentivesPayload.incentives.at(i)!; + + // if (incentiveTarget.instance === zeroAddress) { + // incentive = await this.deploy(incentive); + // incentiveTarget.instance = incentive.address || zeroAddress; + // // TODO validate and throw? + // } + // yield { + // remaining: --remainingSteps, + // deployed: incentive, + // }; + // } + + // const boostPayload: OnChainBoostPayload = { + // ...budgetPayload, + // ...actionPayload, + // ...validatorPayload, + // ...allowListPayload, + // ...incentivesPayload, + // protocolFee, + // referralFee, + // maxParticipants, + // owner, + // }; + + // const boost = await boostFactory(this.config, { + // args: [prepareBoostPayload(boostPayload)], + // }); + + // yield { + // address: boost, + // }; + + // return boost; + // } // TODO make this transactional? if any deployment fails what do we do with the previously deployed deployables? public async createBoost({ diff --git a/packages/sdk/src/Deployable/Contract.ts b/packages/sdk/src/Deployable/Contract.ts index 9975994c..52a9a77d 100644 --- a/packages/sdk/src/Deployable/Contract.ts +++ b/packages/sdk/src/Deployable/Contract.ts @@ -1,5 +1,5 @@ import type { Config } from '@wagmi/core'; -import type { Address } from 'viem'; +import type { Account, Address } from 'viem'; import { ContractAddressRequiredError } from '../errors'; export class Contract { diff --git a/packages/sdk/src/Deployable/Deployable.ts b/packages/sdk/src/Deployable/Deployable.ts index 61466b1d..e8a14e47 100644 --- a/packages/sdk/src/Deployable/Deployable.ts +++ b/packages/sdk/src/Deployable/Deployable.ts @@ -1,5 +1,9 @@ -import { type Config, deployContract } from '@wagmi/core'; -import type { Address, Hex } from 'viem'; +import { + type Config as WagmiConfig, + deployContract, + getClient, +} from '@wagmi/core'; +import type { Account, Address, Hash, Hex } from 'viem'; import { DeployableAlreadyDeployedError, DeployableBuildParametersUnspecifiedError, @@ -17,16 +21,24 @@ export type GenericDeployableParams = Omit< export type DeployableOptions = Payload | Address; +export interface DeployableConfig extends WagmiConfig { + account?: Account; +} export class Deployable extends Contract { protected _payload: Payload | undefined; + protected _account?: Account; - constructor(config: Config, options: DeployableOptions) { + constructor( + { account, ...config }: DeployableConfig, + options: DeployableOptions, + ) { if (typeof options === 'string') { super(config, options as Address); } else { super(config, undefined); this._payload = options as Payload; } + if (account) this._account = account; } get payload() { @@ -38,28 +50,35 @@ export class Deployable extends Contract { return this; } - public async deploy(_payload?: Payload, _config?: Config): Promise
{ + public async deploy( + _payload?: Payload, + _config?: DeployableConfig, + ): Promise { if (this.address) throw new DeployableAlreadyDeployedError(this.address); const config = _config || this._config; const payload = _payload || this._payload; - return (this._address = await deployContract( - config, - this.buildParameters(payload), - )); + const account = _config?.account || this._account; + return await deployContract(config, { + ...this.buildParameters(payload), + ...(account ? { account } : {}), + }); } public buildParameters( _payload?: Payload, - _config?: Config, + _config?: DeployableConfig, ): GenericDeployableParams { throw new DeployableBuildParametersUnspecifiedError(); } - public validateDeploymentConfig(_payload?: Payload, _config?: Config) { + public validateDeploymentConfig( + _payload?: Payload, + _config?: DeployableConfig, + ) { const config = _config || this._config; if (!config) throw new DeployableWagmiConfigurationRequiredError(); const payload = _payload || this._payload; if (!payload) throw new DeployableMissingPayloadError(); - return [payload, config] as [Payload, Config]; + return [payload, config] as [Payload, WagmiConfig]; } }