Skip to content

Commit

Permalink
wip 5
Browse files Browse the repository at this point in the history
  • Loading branch information
egasimus committed Oct 27, 2023
1 parent f924756 commit c3fca2d
Show file tree
Hide file tree
Showing 29 changed files with 1,124 additions and 1,282 deletions.
32 changes: 21 additions & 11 deletions agent/agent-batch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,20 +156,30 @@ export abstract class Batch implements BatchAgent {
* })
* @returns
* the unmodified inputs. */
async instantiateMany <C extends Many<ContractInstance>> (
inputs: C,
options: any
): Promise<C> {
if (!inputs) {
async instantiateMany <M extends Many<ContractInstance>> (
contracts: M,
options: {
initFee?: ICoin[]|'auto',
initFunds?: ICoin[],
initMemo?: string,
} = {}
): Promise<M> {
if (!contracts) {
throw new Error('no contracts passed to instantiateMany')
}
this.log(`adding ${Object.values(inputs).length} instantiate messages`)
const outputs: any = (inputs instanceof Array) ? [] : {}
await Promise.all(Object.entries(inputs).map(async ([key, instance]: [Name, ContractInstance])=>{
if (instance.address) {
outputs[key] = instance.address
this.log(`adding ${Object.values(contracts).length} instantiate messages`)
const outputs: any = (contracts instanceof Array) ? [] : {}
await Promise.all(Object.entries(contracts).map(async ([key, contract]: [Name, ContractInstance])=>{
if (contract.address) {
outputs[key] = contract.address
} else {
outputs[key] = await this.instantiate(instance, options)
outputs[key] = await this.instantiate(contract, {
label: contract.label!,
initMsg: contract.initMsg!,
initFee: contract.initFee || options.initFee,
initFunds: contract.initFunds || options.initFunds,
initMemo: contract.initMemo || options.initMemo
})
}
}))
return outputs
Expand Down
31 changes: 18 additions & 13 deletions agent/agent-chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -586,27 +586,32 @@ export abstract class Agent {
* either an Array<ContractInstance> or a Record<string, ContractInstance>,
* depending on what is passed as inputs. */
async instantiateMany <M extends Many<ContractInstance>> (
instances: M
contracts: M,
options: {
initFee?: ICoin[]|'auto',
initFunds?: ICoin[],
initMemo?: string,
} = {}
): Promise<M> {
// Returns an array of TX results.
const batch = this.batch((batch: any)=>batch.instantiateMany(instances))
const batch = this.batch((batch: any)=>batch.instantiateMany(contracts))
const response = await batch.run()
// Populate instances with resulting addresses
for (const instance of Object.values(instances)) {
if (instance.address) continue
// Find result corresponding to instance
const found = response.find(({ label }:any)=>label===instance.label)
// Populate contracts with resulting addresses
for (const contract of Object.values(contracts)) {
if (contract.address) continue
// Find result corresponding to contract
const found = response.find(({ label }:any)=>label===contract.label)
if (found) {
const { address, tx, sender } = found // FIXME: implementation dependent
instance.address = address
instance.initTx = tx
instance.initBy = sender
contract.address = address
contract.initTx = tx
contract.initBy = sender
} else {
this.log.warn(`Failed to find address for ${instance.label}.`)
this.log.warn(`Failed to find address for ${contract.label}.`)
continue
}
}
return instances
return contracts
}

/** Get a client instance for talking to a specific smart contract as this executor. */
Expand All @@ -616,7 +621,7 @@ export abstract class Agent {
codeHash?: CodeHash,
...args: unknown[]
): C {
return new $C(this, { address, codeHash }) as C
return new $C({ address, codeHash }, this) as C
}

/** Call a transaction method on a smart contract. */
Expand Down
20 changes: 13 additions & 7 deletions agent/agent-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import type {
Agent, Chain, ChainId, ChainMode, ExecOpts
} from './agent-chain'
import type {
DeployStore
UploadStore, DeployStore
} from './agent-store'

import { hideProperties } from '@hackbg/hide'
Expand Down Expand Up @@ -374,7 +374,7 @@ export class ContractInstance extends ContractTemplate {

connect <C extends ContractClient> (agent: Agent, $C?: ContractClientClass<C>) {
$C ??= ContractClient as ContractClientClass<C>
return new $C(agent, this)
return new $C(this, agent)
}

}
Expand Down Expand Up @@ -456,6 +456,9 @@ export class Deployment extends ValueObject {
async build (options: {
builder?: Builder
}): Promise<Record<CodeHash, CompiledCode>> {
if (!options.builder) {
throw new Error.Missing.Builder()
}
const building: Array<Promise<CompiledCode & { codeHash: CodeHash }>> = []
for (const [name, contract] of this.templates.entries()) {
building.push(contract.compile(options.builder))
Expand All @@ -472,6 +475,9 @@ export class Deployment extends ValueObject {
builder?: Builder,
uploadStore?: UploadStore,
}): Promise<Record<CodeId, ContractTemplate>> {
if (!options.agent) {
throw new Error.Missing.Agent()
}
const uploading: Array<Promise<ContractTemplate & { codeId: CodeId }>> = []
for (const [name, contract] of this.templates.entries()) {
uploading.push(contract.upload(options.agent, {}))
Expand All @@ -489,6 +495,9 @@ export class Deployment extends ValueObject {
uploadStore?: UploadStore,
deployStore?: DeployStore,
}): Promise<Record<Address, ContractInstance>> {
if (!options.agent) {
throw new Error.Missing.Agent()
}
const deploying: Array<Promise<ContractInstance & { address: Address }>> = []
for (const [name, contract] of this.contracts.entries()) {
deploying.push(contract.instantiate(options.agent, {}))
Expand Down Expand Up @@ -540,7 +549,7 @@ export class DeploymentContractLabel {

/** A constructor for a ContractClient subclass. */
export interface ContractClientClass<C extends ContractClient> extends
Class<C, [Agent, Address|Partial<ContractInstance>]> {}
Class<C, [Address|Partial<ContractInstance>, Agent|undefined]> {}

/** ContractClient: interface to the API of a particular contract instance.
* Has an `address` on a specific `chain`, usually also an `agent`.
Expand All @@ -552,10 +561,7 @@ export class ContractClient {

agent?: Agent

constructor (
contract: Address|Partial<ContractInstance>,
agent?: Agent
) {
constructor (contract: Address|Partial<ContractInstance>, agent?: Agent) {
this.agent = agent
if (typeof contract === 'string') {
this.contract = new ContractInstance({ address: contract })
Expand Down
85 changes: 8 additions & 77 deletions agent/agent-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,100 +4,31 @@ import type { ChainId } from './agent-chain'
import { Deployment, ContractTemplate } from './agent-contract'
import type { DeploymentClass, DeploymentState } from './agent-contract'

const toCodeHash = (codeHash: CodeHash|{ codeHash: CodeHash }): CodeHash => {
if (typeof codeHash === 'object') codeHash = codeHash.codeHash
if (!codeHash) throw new Error.Missing.CodeHash()
return codeHash
}

export class UploadStore extends Map<CodeHash, ContractTemplate> {
log = new Console('UploadStore')

constructor (readonly chainId: ChainId) {
super()
}

get (codeHash: CodeHash|{ codeHash: CodeHash }): ContractTemplate|undefined {
return super.get(toCodeHash(codeHash))
get (codeHash: CodeHash): ContractTemplate|undefined {
return super.get(codeHash)
}

set (codeHash: CodeHash|{ codeHash: CodeHash }, value: Partial<ContractTemplate>): this {
codeHash = toCodeHash(codeHash)
set (codeHash: CodeHash, value: Partial<ContractTemplate>): this {
if (!(value instanceof ContractTemplate)) value = new ContractTemplate(value)
if (value.codeHash && (value.codeHash !== codeHash)) throw new Error.Invalid('code hash mismatch')
return super.set(toCodeHash(codeHash), value as ContractTemplate)
}

delete (name: Name): boolean {
return true
return super.set(codeHash, value as ContractTemplate)
}
}

export type DeployStoreFormat = 'v1'

/** Mapping from deployment format ids to deployment store constructors. */
export type DeployStores = Partial<Record<DeployStoreFormat, DeployStoreClass<DeployStore>>>

/** Constructor for the different varieties of DeployStore. */
export interface DeployStoreClass<D extends DeployStore> extends Class<D, [
/** Defaults when hydrating Deployment instances from the store. */
unknown,
(Partial<Deployment>|undefined)?,
]> {}

/** A deploy store collects receipts corresponding to individual instances of Deployment,
* and can create Deployment objects with the data from the receipts. */
export abstract class DeployStore extends Map<Name, Deployment> {
export class DeployStore extends Map<Name, Deployment> {
log = new Console('DeployStore')

constructor () {
super()
}

/** Default values for Deployments created from this store. */
defaults: Partial<Deployment> = {}

/** Create a new Deployment, and populate with stored data.
* @returns Deployer */
getDeployment <D extends Deployment> (
$D: DeploymentClass<D> = Deployment as unknown as DeploymentClass<D>,
...args: ConstructorParameters<typeof $D>
): D {
const { name } = args[0] ??= {}
const deployment: D = $D.fromReceipt((name && this.load(name)) || {})
deployment.store = this
return deployment
}

get (name: Name): Deployment|undefined {
return undefined
return super.get(name)
}

set (name: Name, deployment: Partial<Deployment>): this {
return this
}

delete (name: Name): boolean {
return true
if (!(deployment instanceof Deployment)) deployment = new Deployment(deployment)
return super.set(name, deployment as Deployment)
}

/** Get the names of all stored deployments. */
abstract list (): string[]

/** Get a deployment by name, or the active deployment if none is passed.
* @returns Deployment, or null if such doesn't exist. */
abstract load (name: string|null|undefined): DeploymentState|null

/** Update a deployment's data. */
abstract save (name: string, state?: DeploymentState): void

/** Create a new deployment. */
abstract create (name?: string): Promise<DeploymentState>

/** Activate a new deployment, or throw if such doesn't exist. */
abstract select (name: string): Promise<DeploymentState>

/** Get name of the active deployment, or null if there isn't one. */
abstract get activeName (): string|null

}
4 changes: 2 additions & 2 deletions agent/agent-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ export class CustomToken extends TokenFungible {
/** @returns false */
isNative = () => false
/** @returns Client */
asClient (agent: Agent): ContractClient
asClient <C extends ContractClientClass<ContractClient>> (
agent: Agent, $C: C = ContractClient as unknown as C
): InstanceType<C> {
const options = { address: this.addr, codeHash: this.hash }
return new $C(agent, options) as InstanceType<C>
return new $C({ address: this.addr, codeHash: this.hash }, agent) as InstanceType<C>
}
}

Expand Down
13 changes: 0 additions & 13 deletions connect/connect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,13 @@ import * as assert from 'node:assert'

import { Suite } from '@hackbg/ensuite'
export default new Suite([
['chains', testConnectChains],
['config', testConnectConfig],
['errors', testConnectErrors],
['console', testConnectConsole],
['scrt', () => import('./scrt/scrt.test')],
['cw', () => import('./cw/cw.test')]
])

export async function testConnectChains () {
for (const platform of ['secretjs', 'secretcli']) {
for (const mode of ['mainnet', 'testnet', 'devnet', 'mocknet']) {
const agent = connect({
platform,
mode,
mnemonic: '...'
})
}
}
}

export async function testConnectConfig () {
const config = new ConnectConfig()
config.getChain()
Expand Down
6 changes: 6 additions & 0 deletions connect/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export class ConnectConfig extends Config {
}

export class ConnectConsole extends Console {

label = 'Fadroma Connect'

supportedChains (supportedChains: Record<string, unknown> = connectModes) {
Expand All @@ -174,19 +175,24 @@ export class ConnectConsole extends Console {
}
this.br()
}

}

export class ConnectError extends Error {

static SelectChainHint =
`Try setting the FADROMA_CHAIN env var to one of the supported values.`

static UnknownChainSelected = this.define('UnknownChainSelected',
(name: string, chains?: Record<string, unknown>)=>{
//chains && log.supportedChains(chains)
return `Unknown chain "${name}". ${this.SelectChainHint}`
})

static NoChainSelected = this.define('NoChainSelected',
(chains?: Record<string, unknown>)=>{
//chains && log.supportedChains(chains)
return `No chain selected. ${this.SelectChainHint}`
})

}
3 changes: 2 additions & 1 deletion connect/cw/cw.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export async function testCWSigner () {
const devnet = await new Devnet({ platform: 'okp4_5.0' }).create()
const chain = devnet.getChain()
const agent = await chain.getAgent({ mnemonic }).ready as CW.OKP4.Agent
const signed = await agent.signer.signAmino("", { test: 1 })
//@ts-ignore
const signed = await agent.signer!.signAmino("", { test: 1 })
}

export async function testCWChain () {
Expand Down
8 changes: 8 additions & 0 deletions connect/cw/ensuite.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
coverage:
exclude:
- "**/*.dist.*"
- "**/*.test.*"
- "*.dist.*"
- "coverage/**/*"
- "*/coverage/**/*"
- "cosmjs-esm"
8 changes: 4 additions & 4 deletions connect/cw/okp4/okp4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class OKP4Chain extends Chain {
}

protected async getContractsById <C extends ContractClient> (
$C: ContractClientClass<C>,
Client: ContractClientClass<C> = ContractClient as ContractClientClass<C>,
ids: CodeId[],
map = true
): Promise<
Expand All @@ -108,10 +108,10 @@ class OKP4Chain extends Chain {
const { checksum: codeHash } = await api.getCodeDetails(codeId)
const addresses = await api.getContracts(codeId)
for (const address of addresses) {
const contract = new $C(
{ address, codeHash, codeId: String(codeId) } as Partial<C>
const contract = new Client(
{ address, codeHash, chainId, codeId: String(codeId) },
undefined
)
contract.chainId = chainId
if (map) {
(contracts as Map<Address, C>).set(address, contract)
} else {
Expand Down
Loading

0 comments on commit c3fca2d

Please sign in to comment.