diff --git a/agent/base.ts b/agent/base.ts
index 0aab708fc93..1a72d8c973d 100644
--- a/agent/base.ts
+++ b/agent/base.ts
@@ -1,7 +1,7 @@
/** 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 . **/
-import { Error as BaseError } from '@hackbg/oops'
+import { Error } from '@hackbg/oops'
import { Console, bold, colors } from '@hackbg/logs'
import type { Deployment } from './deploy'
@@ -79,22 +79,9 @@ export type Address = string
export type TxHash = string
/** Error kinds. */
-class FadromaError extends BaseError {
- /** Thrown when a required parameter is missing. */
- static Missing: typeof FadromaError_Missing
-}
+class FadromaError extends Error {}
-class FadromaError_Missing extends FadromaError.define(
- 'Missing', (msg='a required parameter was missing') => msg as string
-) {
- static Address = this.define('Address', () => 'no address')
- static Name = this.define("Name", () => "no name")
- static Uploader = this.define('Uploader', () => "no uploader")
- static Workspace = this.define('Workspace', () => "no workspace")
+export {
+ Console,
+ FadromaError as Error
}
-
-export const Error = Object.assign(FadromaError, {
- Missing: FadromaError_Missing,
-})
-
-export { Console }
diff --git a/agent/chain.ts b/agent/chain.ts
index f7311b96a96..e9d495137c1 100644
--- a/agent/chain.ts
+++ b/agent/chain.ts
@@ -292,16 +292,16 @@ export abstract class Agent {
contract = new UploadedCode({ codeId: contract })
}
if (isNaN(Number(contract.codeId))) {
- throw new Error(`invalid code id: ${contract.codeId}`)
+ throw new Error(`can't instantiate contract with missing code id: ${contract.codeId}`)
}
if (!contract.codeId) {
- throw new Error.Missing.CodeId()
+ throw new Error("can't instantiate contract without code id")
}
if (!options.label) {
- throw new Error.Missing.Label()
+ throw new Error("can't instantiate contract without label")
}
if (!options.initMsg) {
- throw new Error.Missing.InitMsg()
+ throw new Error("can't instantiate contract without init message")
}
const t0 = performance.now()
const result = await this.doInstantiate(contract.codeId, {
@@ -363,7 +363,7 @@ export abstract class Agent {
abstract getCodeHashOfCodeId (codeId: CodeId):
Promise
- abstract doQuery (contract: { address: Address }, message: Message):
+ protected abstract doQuery (contract: { address: Address }, message: Message):
Promise
/** Send native tokens to 1 recipient. */
diff --git a/agent/client.ts b/agent/client.ts
index bd55b11594d..2b89bbd8523 100644
--- a/agent/client.ts
+++ b/agent/client.ts
@@ -31,10 +31,10 @@ export class ContractClient {
/** Execute a query on the specified contract as the specified Agent. */
query (message: Message): Promise {
if (!this.agent) {
- throw new Error.Missing.Agent(this.constructor?.name)
+ throw new Error("can't query contract without agent")
}
if (!this.contract.address) {
- throw new Error.Missing.Address()
+ throw new Error("can't query contract without address")
}
return this.agent.query(
this.contract as ContractInstance & { address: Address }, message
@@ -44,10 +44,13 @@ export class ContractClient {
/** Execute a transaction on the specified contract as the specified Agent. */
execute (message: Message, options: Parameters[2] = {}): Promise {
if (!this.agent) {
- throw new Error.Missing.Agent(this.constructor?.name)
+ throw new Error("can't transact with contract without agent")
+ }
+ if (!this.agent.execute) {
+ throw new Error("can't transact with contract without authorizing the agent")
}
if (!this.contract.address) {
- throw new Error.Missing.Address()
+ throw new Error("can't transact with contract without address")
}
return this.agent.execute(
this.contract as ContractInstance & { address: Address }, message, options
diff --git a/connect/connect.ts b/connect/connect.ts
index 8e649341895..9e721e9ede3 100644
--- a/connect/connect.ts
+++ b/connect/connect.ts
@@ -43,7 +43,7 @@ export const connectModes = {
// Support for OKP4:
OKP4Testnet: CW.OKP4.testnet,
- OKP4Devnet: (...args: Parameters): CW.OKP4.Chain => {
+ OKP4Devnet: (...args: Parameters): CW.OKP4.Agent => {
throw new Error('Devnets are only available through @hackbg/fadroma')
},
diff --git a/connect/cw/cw-base.ts b/connect/cw/cw-base.ts
index 5d3352c190c..a85d209c7ad 100644
--- a/connect/cw/cw-base.ts
+++ b/connect/cw/cw-base.ts
@@ -132,7 +132,12 @@ class CWAgent extends Agent {
}
protected async doUpload (data: Uint8Array): Promise> {
- if (!this.address) throw new Error.Missing.Address()
+ if (!this.address) {
+ throw new CWError("can't upload contract without sender address")
+ }
+ if (!(this.api as SigningCosmWasmClient)?.instantiate) {
+ throw new CWError("can't upload contract without authorizing the agent")
+ }
const result = await this.api.upload(
this.address, data, this.fees?.upload || 'auto', "Uploaded by Fadroma"
)
@@ -151,12 +156,6 @@ class CWAgent extends Agent {
codeId: CodeId,
options: Parameters[1]
): Promise> {
- if (!options.label) {
- throw new CWError("can't instantiate contract without label")
- }
- if (!options.initMsg) {
- throw new CWError("can't instantiate contract without init message")
- }
if (!this.address) {
throw new CWError("can't instantiate contract without sender address")
}
@@ -167,7 +166,7 @@ class CWAgent extends Agent {
this.address!,
Number(codeId),
options.initMsg,
- options.label,
+ options.label!,
options.initFee || 'auto',
{ admin: this.address, funds: options.initSend, memo: options.initMemo }
)
diff --git a/connect/cw/okp4/okp4.ts b/connect/cw/okp4/okp4.ts
index e9e47c3fc96..2085a8298e1 100644
--- a/connect/cw/okp4/okp4.ts
+++ b/connect/cw/okp4/okp4.ts
@@ -82,7 +82,6 @@ class OKP4Agent extends Agent {
/** Get clients for all Cognitarium instances,
* keyed by address. */
async cognitaria ({ map = true } = {}) {
- const { api } = await this.ready
const ids = Object.values(cognitariumCodeIds)
return await this.getContractsById(Cognitarium, ids, map)
}
@@ -90,7 +89,6 @@ class OKP4Agent extends Agent {
/** Get clients for all Objectarium instances,
* keyed by address. */
async objectaria ({ map = true } = {}) {
- const { api } = await this.ready
const ids = Object.values(objectariumCodeIds)
return await this.getContractsById(Objectarium, ids, map)
}
@@ -98,7 +96,6 @@ class OKP4Agent extends Agent {
/** Get clients for all Law Stone instances,
* keyed by address. */
async lawStones ({ map = true } = {}) {
- const { api } = await this.ready
const ids = Object.values(lawStoneCodeIds)
return await this.getContractsById(LawStone, ids, map)
}
@@ -110,14 +107,13 @@ class OKP4Agent extends Agent {
): Promise<
typeof map extends true ? Map : Record
> {
- const { api } = await this.ready
const chainId = this.chainId
const contracts = map ? new Map() : {}
for (const id of ids) {
const codeId = Number(id)
if (isNaN(codeId)) throw new Error('non-number code ID encountered')
- const { checksum: codeHash } = await api.getCodeDetails(codeId)
- const addresses = await api.getContracts(codeId)
+ const { checksum: codeHash } = await this.api.getCodeDetails(codeId)
+ const addresses = await this.api.getContracts(codeId)
for (const address of addresses) {
const contract = new Client(
{ address, codeHash, chainId, codeId: String(codeId) },
diff --git a/connect/scrt/scrt-chain.ts b/connect/scrt/scrt-chain.ts
index ae2149e95f4..899f8ae5830 100644
--- a/connect/scrt/scrt-chain.ts
+++ b/connect/scrt/scrt-chain.ts
@@ -329,7 +329,9 @@ class ScrtAgent extends Agent {
}
async encrypt (codeHash: CodeHash, msg: Message) {
- if (!codeHash) throw new Error.Missing.CodeHash()
+ if (!codeHash) {
+ throw new Error("can't encrypt message without code hash")
+ }
const { encryptionUtils } = this.api as any
const encrypted = await encryptionUtils.encrypt(codeHash, msg as object)
return base64.encode(encrypted)
diff --git a/connect/scrt/scrt-mocknet.ts b/connect/scrt/scrt-mocknet.ts
index d213b3f4d20..af963709801 100644
--- a/connect/scrt/scrt-mocknet.ts
+++ b/connect/scrt/scrt-mocknet.ts
@@ -556,8 +556,12 @@ export class MocknetContract {
const height = Math.floor(now/5000)
const time = Math.floor(now/1000)
const sent_funds: any[] = []
- if (!this.address) throw new Error.Missing.Address()
- if (!this.codeHash) throw new Error.Missing.CodeHash()
+ if (!this.address) {
+ throw new Error("can't run contract without address")
+ }
+ if (!this.codeHash) {
+ throw new Error("can't run contract without code hash")
+ }
const { address, codeHash } = this
if (this.cwVersion === '0.x') {
const block = { height, time, chain_id }
diff --git a/ops/build.ts b/ops/build.ts
index 92654befc83..9b50884d337 100644
--- a/ops/build.ts
+++ b/ops/build.ts
@@ -133,7 +133,9 @@ export abstract class LocalRustCompiler extends Compiler {
protected resolveSource (source: string|Partial): Partial {
if (typeof source === 'string') source = { crate: source }
let { crate, workspace = this.workspace, revision = 'HEAD' } = source
- if (!crate) throw new Error.Missing.Crate()
+ if (!crate) {
+ throw new Error("missing crate name")
+ }
// If the `crate` field contains a slash, this is a crate path and not a crate name.
// Add the crate path to the workspace path, and set the real crate name.
if (source.crate && source.crate.includes(sep)) {
@@ -581,7 +583,9 @@ export class RawLocalRustCompiler extends LocalRustCompiler {
source.workspace ??= this.workspace
source.revision ??= HEAD
const { workspace, revision, crate } = source
- if (!crate && !workspace) throw new Error.Missing.Crate()
+ if (!(crate || workspace)) {
+ throw new Error("missing crate name or workspace path")
+ }
const { env, tmpGit, tmpBuild } = this.getEnvAndTemp(source, workspace, revision)
// Run the build script as a subprocess
const location = await this.runBuild(source, env)
diff --git a/ops/devnets.ts b/ops/devnets.ts
index ddcd57a8644..67c09928aed 100644
--- a/ops/devnets.ts
+++ b/ops/devnets.ts
@@ -340,8 +340,12 @@ export class Devnet implements DevnetHandle {
this.log.debug('Creating...')
// ensure we have image and chain id
const image = await this.image
- if (!this.image) throw new DevnetError.Missing.DevnetImage()
- if (!this.chainId) throw new DevnetError.Missing.ChainId()
+ if (!this.image) {
+ throw new DevnetError("missing devnet container image")
+ }
+ if (!this.chainId) {
+ throw new DevnetError("can't create devnet without chain ID")
+ }
// if port is unspecified or taken, increment
this.port = await ports.getFreePort(this.port)
// create container
diff --git a/ops/project.ts b/ops/project.ts
index 5c57fb2fef1..166ece2238b 100644
--- a/ops/project.ts
+++ b/ops/project.ts
@@ -319,7 +319,9 @@ export class Project extends CommandContext {
'export', `export current deployment to JSON`,
async (path?: string) => {
const deployment = await this.selectDeployment()
- if (!deployment) throw new Error.Missing.Deployment()
+ if (!deployment) {
+ throw new Error("deployment not found")
+ }
if (!path) path = process.cwd()
// If passed a directory, generate file name
let file = $(path)
@@ -344,12 +346,12 @@ export class Project extends CommandContext {
contracts: Record> = {},
): InstanceType {
if (!name) {
- throw new Error.Missing.Name()
+ throw new Error("missing deployment name")
}
if (this.deployStore.has(name)) {
return this.Deployment.fromReceipt(this.deployStore.get(name)!)
} else {
- throw new Error.Missing.Deployment()
+ throw new Error(`deployment not found: ${name}`)
}
}
diff --git a/ops/stores.ts b/ops/stores.ts
index 1d23f6984af..d6aa5d37b6a 100644
--- a/ops/stores.ts
+++ b/ops/stores.ts
@@ -37,8 +37,12 @@ export class JSONFileUploadStore extends UploadStore {
}
get (codeHash: CodeHash|{ codeHash: CodeHash }): UploadedCode|undefined {
- if (typeof codeHash === 'object') codeHash = codeHash.codeHash
- if (!codeHash) throw new Error.Missing.CodeHash()
+ if (typeof codeHash === 'object') {
+ codeHash = codeHash.codeHash
+ }
+ if (!codeHash) {
+ throw new Error("can't get upload info: missing code hash")
+ }
const receipt = this.dir.at(`${codeHash!.toLowerCase()}.json`).as(JSONFile)
if (receipt.exists()) {
const uploaded = receipt.load()
@@ -53,8 +57,12 @@ export class JSONFileUploadStore extends UploadStore {
}
set (codeHash: CodeHash|{ codeHash: CodeHash }, value: Partial): this {
- if (typeof codeHash === 'object') codeHash = codeHash.codeHash
- if (!codeHash) throw new Error.Missing.CodeHash()
+ if (typeof codeHash === 'object') {
+ codeHash = codeHash.codeHash
+ }
+ if (!codeHash) {
+ throw new Error("can't set upload info: missing code hash")
+ }
const receipt = this.dir.at(`${codeHash.toLowerCase()}.json`).as(JSONFile)
this.log('writing', receipt.shortPath)
receipt.save(super.get(codeHash)!.toReceipt())