Skip to content

Commit

Permalink
wip 49: 56.06%, 15 type errors
Browse files Browse the repository at this point in the history
regress much? finalizing devnet definitions and unifying tests
  • Loading branch information
egasimus committed Nov 6, 2023
1 parent bd1374c commit 6c242e8
Show file tree
Hide file tree
Showing 24 changed files with 819 additions and 1,110 deletions.
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,9 @@ or the devnet Dockerfiles), make sure to preserve the registry URL prefix and SH
of the base image. In the spirit of reproducible builds, this prevents a hostile build
environment from potentially replacing base images with its own versions for "optimization"
purposes.

### Notes

* When refactoring, avoid turning static methods into arrow functions,
as they may depend on static inheritance (whose behavior is different
in arrow functions).
2 changes: 2 additions & 0 deletions agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,7 @@ export * from './code'
export * from './deploy'
export * from './devnet'
export * from './store'

export * as Stub from './stub'
export * as Token from './token'
export { Agent as default } from './chain'
8 changes: 2 additions & 6 deletions agent/chain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ export async function testUnauthenticated () {
}

export async function testAuthenticated () {
const chain = new Stub.Agent({ chainId: 'stub' })
let agent: Agent = await chain.authenticate({ name: 'testing1', address: '...' })
assert.equal(agent[Symbol.toStringTag], 'stub (mocknet): testing1')
const agent = new Stub.Agent({ chainId: 'stub' }).connect({ name: 'testing1', address: '...' })
//assert.equal(agent[Symbol.toStringTag], 'stub (mocknet): testing1')
assert(agent instanceof Stub.Agent, 'an Agent was returned')
assert(agent.address, 'agent has address')
assert.equal(agent.name, 'testing1', 'agent.name assigned')
Expand All @@ -74,17 +73,14 @@ export async function testAuthenticated () {
await agent.sendMany([])
await agent.upload(fixture('null.wasm'), {})
await agent.upload(new Uint8Array(), {})

await agent.instantiate('1', { label: 'foo', initMsg: 'bar' })
await agent.instantiate({ codeId: '1' }, { label: 'foo', initMsg: {} })
assert.rejects(()=>agent.instantiate('foo', {}))
assert.rejects(()=>agent.instantiate('', {}))
assert.rejects(()=>agent.instantiate('1', { label: 'foo' }))
assert.rejects(()=>agent.instantiate('1', { initMsg: {} }))

await agent.execute('stub', {}, {})
await agent.execute({ address: 'stub' }, {}, {})

const batch = agent.batch()
.upload({})
.upload({})
Expand Down
101 changes: 23 additions & 78 deletions agent/chain.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/** Fadroma. Copyright (C) 2023 Hack.bg. License: GNU AGPLv3 or custom.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. **/
import type { Name, Address, Class, Into, Many, TxHash, Label, Message } from './base'
import type { Name, Address, Class, Into, Many, TxHash, Label, Message, Uint128 } from './base'
import { Error, Console, bold, into, assign } from './base'
import type * as Token from './token'
import { Fee } from './token'
import type { UploadStore } from './store'
import type { CodeHash, CodeId } from './code'
import { CompiledCode, UploadedCode } from './code'
import { ContractInstance, } from './deploy'
import { ContractClient, ContractClientClass } from './client'
import type { Devnet } from './devnet'
import { assignDevnet } from './devnet'

/** A chain can be in one of the following modes: */
export enum Mode {
Expand All @@ -23,12 +23,14 @@ export enum Mode {
/** The unique ID of a chain. */
export type ChainId = string

/** A constructor for an Agent subclass. */
export interface AgentClass<A extends Agent>
extends Class<A, [ ...ConstructorParameters<typeof Agent>, ...unknown[] ]> {}

/** A connection to a chain. */
export abstract class Agent {
/** Smallest unit of native token. */
static gasToken = ''
/** @returns Fee in uscrt */
static gas (amount: Uint128|number): Fee {
return new Fee(amount, this.gasToken)
}

/** @returns a mainnet instance of this chain. */
static mainnet (options: Partial<Agent> = {}): Agent {
Expand All @@ -51,86 +53,42 @@ export abstract class Agent {
}

/** Logger. */
log = new Console(this.constructor.name)

log = new Console('Agent')
/** The API URL to use. */
url: string = ''

/** An instance of the underlying implementation-specific SDK. */
api?: unknown

/** Whether this is mainnet, public testnet, local devnet, or mocknet. */
mode?: Mode

/** The unique id of the chain. */
chainId?: ChainId

/** Smallest unit of native token. */
gasToken: string = (this.constructor as typeof Agent).gasToken
/** Default fee maximums for send, upload, init, and execute. */
fees?: {
send?: Token.IFee,
upload?: Token.IFee,
init?: Token.IFee,
exec?: Token.IFee
}

/** If this is a devnet, this contains an interface to the devnet container. */
devnet?: Devnet

fees?: { send?: Token.IFee, upload?: Token.IFee, init?: Token.IFee, exec?: Token.IFee }
/** Whether this chain is stopped. */
stopped?: boolean

/** The friendly name of the agent. */
name?: string

/** The address from which transactions are signed and sent. */
address?: Address

/** The default identity used to sign transactions with this agent. */
signer?: unknown
signer?: unknown

constructor (properties?: Partial<Agent>) {
devnet?: Devnet<typeof Agent>|undefined

constructor (properties?: Partial<Agent> & { mnemonic?: string }) {
assign(this, properties, [
'url', 'mode', 'chainId', 'fees', 'devnet', 'stopped', 'name', 'address', 'api', 'signer'
'url', 'mode', 'chainId', 'fees', 'stopped', 'name', 'address', 'api', 'signer'
])
if (this.devnet) {
assignDevnet(this, this.devnet)
if (properties?.chainId && properties?.chainId !== properties?.devnet?.chainId) {
this.log.warn('chainId: ignoring override (devnet)')
}
if (properties?.url && properties?.url.toString() !== properties?.devnet?.url?.toString()) {
this.log.warn('url: ignoring override (devnet)')
}
if (properties?.mode && properties?.mode !== Mode.Devnet) {
this.log.warn('mode: ignoring override (devnet)')
}
} else {
Object.defineProperties(this, {
id: {
enumerable: true, writable: false, value: properties?.chainId
},
mode: {
enumerable: true, writable: false, value: properties?.mode || Mode.Mocknet
}
})
this.url = properties?.url ?? this.url
}

if (this.mode === Mode.Mocknet) {
Object.defineProperty(this, 'url', {
enumerable: true,
writable: false,
value: `fadroma://mocknet-${this.chainId}`
enumerable: true, writable: false, value: `fadroma://mocknet-${this.chainId}`
})
}

Object.defineProperties(this, {
log: {
configurable: true,
enumerable: false,
writable: true,
},
log: { configurable: true, enumerable: false, writable: true, },
})

}

/** Compact string tag for console representation. */
Expand Down Expand Up @@ -198,7 +156,7 @@ export abstract class Agent {
console.log({height})
if (height > startingHeight) {
this.log.log(`Block height incremented to ${bold(String(height))}, proceeding`)
return resolve(height)
return resolve(height as number)
}
}
} catch (e) {
Expand All @@ -224,18 +182,9 @@ export abstract class Agent {
return result as Q
}

/** Create a new, authenticated Agent. */
authenticate (options?: {
name?: Name,
address?: Address,
mnemonic?: string,
signer?: unknown,
api?: unknown
}): this {
return new (this.constructor as any)({
...this,
...options
})
/** Create a new Agent inheriting the settings from this one. */
connect (options?: Partial<this> & { mnemonic?: string }): this {
return new (this.constructor as any)({ ...this, ...options||{} })
}

/** Send native tokens to 1 recipient. */
Expand Down Expand Up @@ -370,10 +319,6 @@ export abstract class Agent {
return result
}

/** The default denomination of the chain's native token. */
abstract defaultDenom:
string

abstract getBlockInfo ():
Promise<unknown>

Expand Down
4 changes: 2 additions & 2 deletions agent/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class ContractCode {
if (!compiled.canUpload) {
throw new Error("build failed")
}
return this.compiled = compiled
return this.compiled = compiled as typeof compiled & { codeHash: CodeHash }
}

/** Upload this contract, unless a valid upload is present and a rebuild is not requested. */
Expand All @@ -101,7 +101,7 @@ export class ContractCode {
codeId: CodeId
}> {
if (this.uploaded?.canInstantiate && !reupload && !rebuild) {
return this.uploaded
return this.uploaded as typeof uploaded & { codeId: CodeId }
}
if (!uploader || (typeof uploader === 'string')) {
throw new Error("can't upload: no uploader agent")
Expand Down
29 changes: 10 additions & 19 deletions agent/devnet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import assert, { equal, throws, rejects } from 'node:assert'
import { Error } from './base'
import * as Stub from './stub'
import { Mode } from './chain'
import type { Agent } from './chain'
import { Devnet, assignDevnet } from './devnet'
import { Agent } from './chain'
import { Devnet } from './devnet'

class MyDevnet extends Devnet {
class MyDevnet extends Devnet<typeof Stub.Agent> {
Agent = Stub.Agent
accounts = []
chainId = 'foo'
platform = 'bar'
Expand Down Expand Up @@ -42,29 +43,19 @@ class MyDevnet extends Devnet {

export default async function testDevnet () {
const devnet = new MyDevnet()
const chain = new Stub.Agent({ mode: Mode.Devnet, chainId: 'bar', url: 'http://asdf.com', devnet })
// Properties from Devnet are passed onto Chain
equal(chain.devnet, devnet)
const agent = await devnet.connect({ name: 'Alice' })
//equal(chain.chainId, 'foo')
equal(chain.url, 'http://example.com/')
equal(chain.mode, Mode.Devnet)
equal(chain.stopped, true)
equal(agent.url, 'http://example.com/')
equal(agent.mode, Mode.Devnet)
equal(agent.stopped, true)
devnet.running = true
equal(chain.stopped, false)
throws(()=>chain.devnet=devnet)
throws(()=>chain.stopped=true)
await chain.authenticate({ name: 'Alice' })
const chain2 = new Stub.Agent({ mode: Mode.Mainnet, devnet })
const agent: any = {}
assignDevnet(agent as any, devnet)
equal(agent.stopped, false)
throws(()=>agent.stopped=true)
agent.chainId
agent.url
agent.mode
agent.devnet
agent.stopped
throws(()=>agent.chainId = "")
throws(()=>agent.url = "")
throws(()=>agent.mode = "")
throws(()=>agent.devnet = "")
throws(()=>agent.stopped = "")
}
Loading

0 comments on commit 6c242e8

Please sign in to comment.