diff --git a/packages/agent/chain.ts b/packages/agent/chain.ts index 88ed783ca9..06493bae75 100644 --- a/packages/agent/chain.ts +++ b/packages/agent/chain.ts @@ -61,8 +61,11 @@ export abstract class Backend extends Logged { abstract connect (): Promise - abstract connect (parameter?: string|Partial): - Promise + abstract connect (name: string): + Promise + abstract connect (identity: Partial): + Promise + abstract getIdentity (name: string): Promise<{ address?: Address, mnemonic?: string }> } diff --git a/packages/agent/deploy.ts b/packages/agent/deploy.ts index dff5c75558..e2eb62bfab 100644 --- a/packages/agent/deploy.ts +++ b/packages/agent/deploy.ts @@ -284,8 +284,8 @@ export class ContractInstance extends DeploymentUnit { } /** Returns a client to this contract instance. */ - connect ( - agent?: Connection): Contract + connect (agent?: Connection): + Contract connect ( connection?: Connection, $C: C = Contract as C ) { diff --git a/packages/agent/stub.ts b/packages/agent/stub.ts index 67ce7deb81..c4d1b637a3 100644 --- a/packages/agent/stub.ts +++ b/packages/agent/stub.ts @@ -34,8 +34,8 @@ export class StubConnection extends Connection { this.backend ??= new StubBackend() } - batch (): Batch { - return new StubBatch({ connection: this }) as unknown as Batch + batch (): Batch { + return new StubBatch({ connection: this }) as unknown as Batch } protected override fetchHeightImpl () { @@ -46,13 +46,19 @@ export class StubConnection extends Connection { return Promise.resolve(new StubBlock({ height: + new Date() })) } - protected override fetchBalanceImpl (token?: string, address?: string): Promise { - token ??= this.defaultDenom - const balance = (this.backend.balances.get(address!)||{})[token] ?? 0 - return Promise.resolve(String(balance)) + protected override fetchBalanceImpl ( + ...args: Parameters + ): Promise { + throw new Error('unimplemented!') + //token ??= this.defaultDenom + //const balance = (this.backend.balances.get(address!)||{})[token] ?? 0 + //return Promise.resolve(String(balance)) + return Promise.resolve('') } - protected override fetchCodeInfoImpl ({ ids }: { ids: CodeId[]|undefined }): + protected override fetchCodeInfoImpl ( + ...args: Parameters + ): Promise> { if (!ids) { @@ -70,12 +76,18 @@ export class StubConnection extends Connection { } } - protected override fetchCodeInstancesImpl (id: CodeId) { - return Promise.resolve([...this.backend.uploads.get(id)!.instances] - .map(address=>({address}))) + protected override async fetchCodeInstancesImpl ( + ...args: Parameters + ) { + throw new Error('unimplemented!') + return {} + //return Promise.resolve([...this.backend.uploads.get(id)!.instances] + //.map(address=>({address}))) } - protected override fetchContractInfoImpl ({ addresses }: { addresses: Address[] }): + protected override fetchContractInfoImpl ( + ...args: Parameters + ): Promise> { const results = {} @@ -97,8 +109,10 @@ export class StubConnection extends Connection { return Promise.resolve(results) } - protected override queryImpl (contract: { address: Address }, message: Message): Promise { - return Promise.resolve({} as Q) + protected override queryImpl ( + ...args: Parameters + ): Promise { + return Promise.resolve({} as T) } authenticate (identity: Identity): StubAgent { @@ -107,8 +121,10 @@ export class StubConnection extends Connection { } export class StubAgent extends Agent { + declare connection: StubConnection - protected sendImpl (recipient: Address, sums: Token.ICoin[], opts?: never): Promise { + + protected sendImpl (...args: Parameters): Promise { if (!this.address) { throw new Error('not authenticated') } @@ -134,14 +150,15 @@ export class StubAgent extends Agent { backend.balances.set(recipient, recipientBalances) return Promise.resolve() } - protected sendManyImpl (outputs: [Address, Token.ICoin[]][], opts?: never): Promise { - return Promise.resolve() - } - protected async uploadImpl (codeData: Uint8Array): Promise { + + protected async uploadImpl ( + ...args: Parameters + ): Promise { return new UploadedCode(await this.connection.backend.upload(codeData)) } + protected async instantiateImpl ( - codeId: CodeId, options: Parameters[1] + ...args: Parameters ): Promise { return new ContractInstance(await this.connection.backend.instantiate( this.address!, codeId, options @@ -149,12 +166,11 @@ export class StubAgent extends Agent { address: Address } } - protected executeImpl ( - contract: { address: Address, codeHash: CodeHash }, - message: Message, - options?: Parameters[2] - ): Promise { - return Promise.resolve({}) + + protected executeImpl ( + ...args: Parameters + ): Promise { + return Promise.resolve({} as T) } } @@ -214,23 +230,31 @@ export class StubBackend extends Backend { } } - async connect (): - Promise - async connect (parameter: string|Partial): - Promise - async connect (parameter: string|Partial = {}): Promise { - if (typeof parameter === 'string') { - parameter = await this.getIdentity(parameter) - } - if (parameter.mnemonic && !parameter.address) { - parameter.address = `${this.prefix}${parameter.name}` - } - return new StubConnection({ + connect (): + Promise + connect (name: string): + Promise + connect (identity: Partial): + Promise + async connect (...args: unknown[]): Promise { + const connection = new StubConnection({ chainId: this.chainId, url: 'stub', alive: this.alive, backend: this, - }).authenticate(new Identity(parameter)) + }) + if (!args[0]) { + return connection + } + if (typeof args[0] === 'string') { + return connection.authenticate(new Identity(await this.getIdentity(args[0]))) + } + const parameter = args[0] as Partial & { mnemonic?: string } + if (parameter.mnemonic && !parameter.address) { + parameter.address = `${this.prefix}${parameter.name}` + return connection.authenticate(new Identity(parameter)) + } + throw new Error('invalid argument') } getIdentity (name: string): Promise { @@ -268,19 +292,18 @@ export class StubBackend extends Backend { return upload } - async instantiate ( - creator: Address, codeId: CodeId, options: unknown - ): Promise & { - address: Address - }> { + async instantiate (args: { creator: Address, codeId: CodeId }): + Promise + { + const { codeId, creator } = args const address = randomBech32(this.prefix) const code = this.uploads.get(codeId) if (!code) { - throw new Error(`invalid code id ${codeId}`) + throw new Error(`invalid code id ${args.codeId}`) } code.instances.add(address) this.instances.set(address, { address, codeId, creator }) - return { address, codeId } + return new ContractInstance({ address, codeId }) as ContractInstance & { address: Address } } async execute (...args: unknown[]): Promise { diff --git a/packages/cw/cw-bank.ts b/packages/cw/cw-bank.ts index ad8bf780f4..adb98d9458 100644 --- a/packages/cw/cw-bank.ts +++ b/packages/cw/cw-bank.ts @@ -6,10 +6,9 @@ type Connection = { api: CosmWasmClient|Promise } -export async function getBalance ( - { api }: Connection, - token: string, - address: Address +export async function fetchBalance ( + { api }: Connection, + balances: Parameters[0] ) { api = await Promise.resolve(api) if (!address) { diff --git a/packages/cw/cw-compute.ts b/packages/cw/cw-compute.ts index 0c31c0a7d6..47416846a2 100644 --- a/packages/cw/cw-compute.ts +++ b/packages/cw/cw-compute.ts @@ -1,7 +1,8 @@ import type { CosmWasmClient, SigningCosmWasmClient } from '@hackbg/cosmjs-esm' -import { Deploy } from '@fadroma/agent' -import type { Address, CodeId, Chain, Message, Token, Core } from '@fadroma/agent' +import { Chain, Deploy } from '@fadroma/agent' +import type { Address, CodeId, Message, Token, Core } from '@fadroma/agent' import { Amino } from '@hackbg/cosmjs-esm' +import type { CWConnection, CWAgent } from './cw-connection' type Connection = { chainId?: string, @@ -16,6 +17,65 @@ export type SigningConnection = { api: SigningCosmWasmClient|Promise } +export async function fetchCodeInfo ( + conn: CWConnection, + args: Parameters[0] +): + Promise> +{ + throw new Error('unimplemented!') + return {} + //const { ids = [] } = parameters || {} + //if (!ids || ids.length === 0) { + //return Compute.getCodes(this) + //} else if (ids.length === 1) { + //return Compute.getCodes(this, ids) + //} else { + //throw new Error('CWConnection.fetchCodeInfo({ ids: [multiple] }): unimplemented!') + //} + //protected override fetchCodesImpl () { + //return Compute.getCodes(this) + //} + //protected override fetchCodeIdImpl (address: Address): Promise { + //return getCodeId(this, address) + //} + //protected override fetchCodeHashOfCodeIdImpl (codeId: CodeId): Promise { + //return Compute.getCodeHashOfCodeId(this, codeId) + //} +} + +export async function fetchCodeInstances ( + conn: CWConnection, + args: Parameters[0] +): + Promise>> +{ + throw new Error('unimplemented!') + return {} + //protected override fetchContractsByCodeIdImpl (id: CodeId): Promise> { + //return Compute.getContractsByCodeId(this, id) + //} +} + +export async function fetchContractInfo ( + conn: CWConnection, + args: Parameters[0] +): + Promise<{ + [address in keyof typeof args["contracts"]]: InstanceType + }> +{ + throw new Error('unimplemented!') + return {} + //return Compute.getCodeId(this, address) + //protected override fetchCodeHashOfAddressImpl (address: Address): Promise { + //return Compute.getCodeHashOfAddress(this, address) + //} + //protected override fetchLabelImpl (address: Address): Promise { + //return Compute.getLabel(this, address) + //} +} + export async function getCodes ( { chainId, api }: Connection ) { @@ -141,7 +201,7 @@ export async function instantiate ( options.initFee as Amino.StdFee || 'auto', { admin: address, funds: options.initSend, memo: options.initMemo } ) - return { + return new Deploy.ContractInstance({ codeId: options.codeId, codeHash: options.codeHash, label: options.label, @@ -154,7 +214,7 @@ export async function instantiate ( initFee: options.initFee || 'auto', initSend: options.initSend, initMemo: options.initMemo - } + }) as Deploy.ContractInstance & { address: Address } } export async function execute ( diff --git a/packages/cw/cw-connection.ts b/packages/cw/cw-connection.ts index dfc54a8ca2..b85d47a180 100644 --- a/packages/cw/cw-connection.ts +++ b/packages/cw/cw-connection.ts @@ -107,48 +107,35 @@ export class CWConnection extends Chain.Connection { } /** Query native token balance. */ - protected override fetchBalanceImpl (parameters) { - return Bank.getBalance(this, parameters) + protected override fetchBalanceImpl ( + ...args: Parameters + ) { + return Bank.fetchBalance(this, ...args) } - protected override fetchCodeInfoImpl (parameters) { - const { ids = [] } = parameters || {} - if (!ids || ids.length === 0) { - return Compute.getCodes(this) - } else if (ids.length === 1) { - return Compute.getCodes(this, ids) - } else { - throw new Error('CWConnection.fetchCodeInfo({ ids: [multiple] }): unimplemented!') - } - //protected override fetchCodesImpl () { - //return Compute.getCodes(this) - //} - //protected override fetchCodeIdImpl (address: Address): Promise { - //return getCodeId(this, address) - //} - //protected override fetchCodeHashOfCodeIdImpl (codeId: CodeId): Promise { - //return Compute.getCodeHashOfCodeId(this, codeId) - //} + protected override fetchCodeInfoImpl ( + ...args: Parameters + ) { + return Compute.fetchCodeInfo(this, ...args) } - protected override fetchCodeInstancesImpl (parameters) { - //protected override fetchContractsByCodeIdImpl (id: CodeId): Promise> { - //return Compute.getContractsByCodeId(this, id) - //} + protected override fetchCodeInstancesImpl ( + ...args: Parameters + ) { + return Compute.fetchCodeInstances(this, ...args) + } - protected override fetchContractInfoImpl (parameters) { - //return Compute.getCodeId(this, address) - //protected override fetchCodeHashOfAddressImpl (address: Address): Promise { - //return Compute.getCodeHashOfAddress(this, address) - //} - //protected override fetchLabelImpl (address: Address): Promise { - //return Compute.getLabel(this, address) - //} + protected override fetchContractInfoImpl ( + ...args: Parameters + ) { + return Compute.fetchContractInfo(this, ...args) } - protected override async queryImpl (parameters) { - return await Compute.query(this, parameters) as T + protected override async queryImpl ( + ...args: Parameters + ) { + return await Compute.query(this, ...args) as T } fetchValidators ({ details = false }: { @@ -169,16 +156,19 @@ export class CWAgent extends Chain.Agent { /** API connects asynchronously, so API handle is a promise. */ declare api: Promise - protected override async sendImpl (parameters) { - return Bank.send(this as Compute.SigningConnection, parameters) + protected async sendImpl (...args: Parameters) { + return await Bank.send(this, ...args) } - protected override async uploadImpl (parameters) { - return Compute.upload(this as Compute.SigningConnection, parameters) + + protected async uploadImpl (...args: Parameters) { + return await Compute.upload(this, ...args) } - protected override async instantiateImpl (parameters) { - return Compute.instantiate(this as Compute.SigningConnection, parameters) + + protected async instantiateImpl (...args: Parameters) { + return await Compute.instantiate(this, ...args) } - protected override async executeImpl (parameters) { - return Compute.execute(this as Compute.SigningConnection, parameters) + + protected async executeImpl (...args: Parameters): Promise { + return await Compute.execute(this, ...args) as T } } diff --git a/packages/cw/okp4/okp4.ts b/packages/cw/okp4/okp4.ts index f1b79d1f30..5bc6f9ebf0 100644 --- a/packages/cw/okp4/okp4.ts +++ b/packages/cw/okp4/okp4.ts @@ -35,27 +35,6 @@ class OKP4Connection extends CWConnection { super({ ...defaults, ...options } as Partial) } - getContractsById (id: CodeId): - Promise - getContractsById (id: CodeId): - Promise> - { - return Promise.resolve(new Chain.Contract({ - instance: { address: '' }, - connection: this - }) as InstanceType) - } - - getContractsByIds (ids: CodeId[]): - Promise> - getContractsByIds (ids: Record): - Promise> - getContractsByIds (ids: unknown): - Promise> - { - return Promise.resolve(new Map()) - } - /** Get clients for all Cognitarium instances, keyed by address. */ //async cognitaria ({ map = true } = {}) { //const ids = Object.values(cognitariumCodeIds) diff --git a/packages/namada/namada.ts b/packages/namada/namada.ts index 52fdd9142b..15d9562a96 100644 --- a/packages/namada/namada.ts +++ b/packages/namada/namada.ts @@ -424,7 +424,7 @@ export default class NamadaCLI extends CLI { height = Number(height) } const connection = new NamadaConnection({ url }) - const block = await connection.getBlock(height) + const block = await connection.fetchBlock({ height }) this.log.log() .log('Block:', Core.bold(block.height)) .log('ID: ', Core.bold(block.hash)) @@ -447,7 +447,7 @@ export default class NamadaCLI extends CLI { const connection = new NamadaConnection({ url }) let block do { - block = await connection.getBlock(Number(height)) + block = await connection.fetchBlock({ height: Number(height) }) height = block.header.height this.log.log() .log('Block:', Core.bold(block.header.height)) diff --git a/packages/scrt/scrt-compute.ts b/packages/scrt/scrt-compute.ts index 1487d98887..58566712c7 100644 --- a/packages/scrt/scrt-compute.ts +++ b/packages/scrt/scrt-compute.ts @@ -164,7 +164,7 @@ export async function upload ( throw new Error('upload failed') } const { codeHash } = await this.conn.fetchCodeInfo(codeId) - return new Deploy.ContractTemplate({ + return new Deploy.UploadedCode({ chainId: this.conn.chainId, codeId, codeHash, diff --git a/packages/scrt/scrt-connection.ts b/packages/scrt/scrt-connection.ts index ab34269a8b..cbe26bca75 100644 --- a/packages/scrt/scrt-connection.ts +++ b/packages/scrt/scrt-connection.ts @@ -20,11 +20,12 @@ export type { TxResponse } /** Represents a Secret Network API endpoint. */ export class ScrtConnection extends Chain.Connection { + /** Smallest unit of native token. */ static gasToken = new Token.Native('uscrt') + /** Underlying API client. */ - declare api: - SecretNetworkClient + declare api: SecretNetworkClient constructor (properties?: Partial) { super(properties as Partial) @@ -38,12 +39,15 @@ export class ScrtConnection extends Chain.Connection { } this.api = new SecretNetworkClient({ chainId, url }) } + authenticate (identity: ScrtIdentity): ScrtAgent { return new ScrtAgent({ connection: this, identity }) } + batch (): Batch { return new ScrtBatch({ connection: this }) as unknown as Batch } + protected override async fetchBlockImpl (parameter?): Promise { if (!parameter) { const { @@ -56,25 +60,40 @@ export class ScrtConnection extends Chain.Connection { }) } } + protected override async fetchHeightImpl () { const { height } = await this.fetchBlockImpl() return height } - protected override async fetchBalanceImpl (parameters) { - return await Bank.fetchBalance(this, parameters) + + protected override async fetchBalanceImpl ( + ...args: Parameters + ) { + return await Bank.fetchBalance(this, ...args) } - protected override async fetchCodeInfoImpl (parameters) { - return await Compute.fetchCodeInfo(this, parameters) + + protected override async fetchCodeInfoImpl ( + ...args: Parameters + ) { + return await Compute.fetchCodeInfo(this, ...args) } - protected override async fetchCodeInstancesImpl (parameters) { - return await Compute.fetchCodeInstances(this, parameters) + + protected override async fetchCodeInstancesImpl ( + ...args: Parameters + ) { + return await Compute.fetchCodeInstances(this, ...args) } - protected override async fetchContractInfoImpl (parameters) { - return await Compute.fetchContractInfo(this, parameters) + + protected override async fetchContractInfoImpl ( + ...args: Parameters + ) { + return await Compute.fetchContractInfo(this, ...args) } + protected override async queryImpl (parameters): Promise { return await Compute.query(this, parameters) as T } + async fetchLimits (): Promise<{ gas: number }> { const params = { subspace: "baseapp", key: "BlockParams" } const { param } = await this.api.query.params.params(params) @@ -141,6 +160,7 @@ export class ScrtAgent extends Chain.Agent { const { account_number, sequence } = result.account return { accountNumber: Number(account_number), sequence: Number(sequence) } } + async encrypt (codeHash: CodeHash, msg: Message) { if (!codeHash) { throw new Error("can't encrypt message without code hash") @@ -153,12 +173,15 @@ export class ScrtAgent extends Chain.Agent { protected async sendImpl (...args: Parameters) { return await Bank.send(this, ...args) } + protected async uploadImpl (...args: Parameters) { return await Compute.upload(this, ...args) } + protected async instantiateImpl (...args: Parameters) { return await Compute.instantiate(this, ...args) } + protected async executeImpl (...args: Parameters): Promise { return await Compute.execute(this, ...args) as T } @@ -262,7 +285,7 @@ export class ScrtBatch extends Batch { code_id: String(init.codeId), init_funds: init.funds, label: init.label, - init_msg: await this.connection!.encrypt(init.codeHash, init.msg), + init_msg: await this.agent!.encrypt(init.codeHash, init.msg), } } @@ -274,7 +297,7 @@ export class ScrtBatch extends Batch { sender: this.agent!.address, contract: exec.contract, sent_funds: exec.funds, - msg: await this.connection!.encrypt(exec.codeHash, exec.msg), + msg: await this.agent!.encrypt(exec.codeHash, exec.msg), } } @@ -286,7 +309,7 @@ export class ScrtBatch extends Batch { const api = await Promise.resolve(this.connection!.api) const chainId = this.connection!.chainId! const messages = this.messages - const limit = Number(this.connection!.fees.exec?.amount[0].amount) || undefined + const limit = Number(this.agent!.fees.exec?.amount[0].amount) || undefined const gas = messages.length * (limit || 0) const results: ScrtBatchResult[] = [] @@ -354,7 +377,7 @@ export class ScrtBatch extends Batch { // Number of batch, just for identification in console name ??= name || `TX.${+new Date()}` // Get signer's account number and sequence via the canonical API - const { accountNumber, sequence } = await this.connection!.getNonce()//this.chain.url, this.connection!.address) + const { accountNumber, sequence } = await this.agent!.getNonce()//this.chain.url, this.connection!.address) // Print the body of the batch this.log.debug(`Messages in batch:`) for (const msg of this.messages??[]) { diff --git a/packages/scrt/scrt-mocknet.ts b/packages/scrt/scrt-mocknet.ts index 4628079498..ec9f379168 100644 --- a/packages/scrt/scrt-mocknet.ts +++ b/packages/scrt/scrt-mocknet.ts @@ -42,12 +42,9 @@ class ScrtMocknetConnection extends Stub.StubConnection { return Promise.resolve({}) } - protected queryImpl ( - contract: Address|{address: Address}, - message: Message - ): Promise { + protected queryImpl ({ address, message }): Promise { return (this.backend as ScrtMocknetBackend) - .getContract(contract) + .getContract({address}) .query({ msg: message }) } } @@ -57,13 +54,16 @@ export { ScrtMocknetConnection as Connection } class ScrtMocknetAgent extends Stub.StubAgent { protected instantiateImpl (...args: Parameters) { - return this.connection.backend.instantiate( - this.address!, ...args - ) as Promise + return this.connection.backend.instantiate({ + ...args[0] as typeof args[0] & { codeId: CodeId }, + creator: this.address! + }) as Promise } - protected executeImpl (...args: Parameters): Promise { - return this.connection.backend.execute(this.address!, ...args) + protected async executeImpl (...args: Parameters): + Promise + { + return await this.connection.backend.execute(this.address!, ...args) as T } } @@ -186,12 +186,19 @@ class ScrtMocknetBackend extends Stub.StubBackend { } //async instantiate (codeId: CodeId, options: unknown): Promise & { - async instantiate ( - creator: Address, ...args: Parameters - ): Promise { - const [codeId, { codeHash, label, initSend, initMsg, initFee }] = args + async instantiate (args: { + creator: Address + codeId: CodeId + codeHash: CodeHash + label: string + initMsg: Message + initSend?: unknown[] + initFee? + initMemo? + }): + Promise + { + const { creator, codeId, codeHash, label, initSend, initMsg, initFee } = args if (!codeId) { throw new Error('missing code id') } @@ -376,13 +383,7 @@ class ScrtMocknetBackend extends Stub.StubBackend { })) } - connect (): - Promise - connect (_: string|Partial): - Promise - async connect ( - parameter?: string|Partial - ): Promise { + async connect (...args: unknown[]): Promise { const connection = new ScrtMocknetConnection({ chainId: this.chainId, url: this.url, @@ -472,7 +473,10 @@ class ScrtMocknetContract { runtime?: WebAssembly.Instance['exports']> storage = new Map() - constructor (readonly mocknet: ScrtMocknetBackend, options: Partial> = {}) { + constructor ( + readonly mocknet: ScrtMocknetBackend, + options: Partial> = {} + ) { Object.assign(this, options) } diff --git a/packages/scrt/snip-20.test.ts b/packages/scrt/snip-20.test.ts index 9bc1729925..7bfc363381 100644 --- a/packages/scrt/snip-20.test.ts +++ b/packages/scrt/snip-20.test.ts @@ -9,7 +9,7 @@ export default function testSnip20 () { admin: 'address' }).prng_seed?.length > 0) - assert.equal(new Snip20('address').id, 'address') + assert.equal(new Snip20({ address: 'address' }).id, 'address') - assert(new Snip20('address').vk instanceof ViewingKeyClient) + assert(new Snip20({ address: 'address' }).vk instanceof ViewingKeyClient) } diff --git a/packages/scrt/snip-721.test.ts b/packages/scrt/snip-721.test.ts index 4d11770337..d202c82732 100644 --- a/packages/scrt/snip-721.test.ts +++ b/packages/scrt/snip-721.test.ts @@ -1,5 +1,5 @@ import { Snip721 } from './snip-721' export default async function testSnip721 () { - new Snip721('address') + new Snip721({ address: 'address' }) } diff --git a/packages/scrt/snip-721.ts b/packages/scrt/snip-721.ts index 3c73ce5e11..6565ac11d8 100644 --- a/packages/scrt/snip-721.ts +++ b/packages/scrt/snip-721.ts @@ -6,7 +6,7 @@ export class Snip721 extends Chain.Contract implements Token.NonFungible { isFungible = () => false get id () { - return this.instance!.address! + return this.address! } } diff --git a/stores.test.ts b/stores.test.ts index cd1da3bcd9..963ba46d3e 100644 --- a/stores.test.ts +++ b/stores.test.ts @@ -6,7 +6,7 @@ export default async function testJSONFileStores () { await withTmpDir(async dir=>{ const deployment = new TestProjectDeployment() await deployment.upload({ - uploader: new Stub.StubConnection(), + uploader: new Stub.StubAgent({}), uploadStore: new JSONFileUploadStore(dir) }) })