From 36855ecb3d4c723dd1d4b9dfe53281ba2990cee6 Mon Sep 17 00:00:00 2001 From: Adam A Date: Fri, 3 May 2024 22:43:10 +0300 Subject: [PATCH] wip: fix(scrt): update to match changes in agent, pt.1 --- packages/scrt/scrt-connection.ts | 134 ++++++++++++++++++------------- packages/scrt/scrt-identity.ts | 4 +- 2 files changed, 78 insertions(+), 60 deletions(-) diff --git a/packages/scrt/scrt-connection.ts b/packages/scrt/scrt-connection.ts index 734f0ee199..a6d604c046 100644 --- a/packages/scrt/scrt-connection.ts +++ b/packages/scrt/scrt-connection.ts @@ -16,12 +16,16 @@ 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 + /** Supports multiple authentication methods. */ declare identity: ScrtIdentity + /** Set permissive fees by default. */ fees = { upload: ScrtConnection.gasToken.fee(10000000), @@ -29,6 +33,7 @@ export class ScrtConnection extends Chain.Connection { exec: ScrtConnection.gasToken.fee(1000000), send: ScrtConnection.gasToken.fee(1000000), } + constructor (properties?: Partial) { super(properties as Partial) this.api ??= new SecretNetworkClient({ url: this.url!, chainId: this.chainId!, }) @@ -59,19 +64,29 @@ export class ScrtConnection extends Chain.Connection { } } - protected async doGetBlockInfo () { + protected async fetchBlockImpl () { const { block_id: { hash, part_set_header } = {}, block: { header, data, evidence, last_commit } = {} } = await this.api.query.tendermint.getLatestBlock({}) } - protected doGetHeight () { - return this.doGetBlockInfo().then((block: any)=> + protected async fetchCodeInfoImpl () {} + + protected async fetchCodeInstancesImpl () {} + + protected async fetchContractInfoImpl () {} + + authenticate (identity: ScrtIdentity): Promise { + return new ScrtAgent({ connection: this, identity }) + } + + protected fetchHeightImpl () { + return this.fetchBlockInfoImpl().then((block: any)=> Number(block.block?.header?.height)) } - protected doGetCodes () { + protected fetchCodesImpl () { const codes: Record = {} return withIntoError(this.api.query.compute.codes({})) .then(({code_infos})=>{ @@ -87,14 +102,14 @@ export class ScrtConnection extends Chain.Connection { }) } - protected async doGetCodeId (contract_address: Address): Promise { + protected async fetchCodeIdImpl (contract_address: Address): Promise { return (await withIntoError(this.api.query.compute.contractInfo({ contract_address }))) .ContractInfo!.code_id! } - protected async doGetContractsByCodeId (code_id: CodeId): Promise> { + protected async fetchContractsByCodeIdImpl (code_id: CodeId): Promise> { return (await withIntoError(this.api.query.compute.contractsByCodeId({ code_id }))) .contract_infos! .map(({ contract_address, contract_info: { label, creator } }: any)=>({ @@ -104,21 +119,21 @@ export class ScrtConnection extends Chain.Connection { })) } - protected async doGetCodeHashOfAddress (contract_address: Address): Promise { + protected async fetchCodeHashOfAddressImpl (contract_address: Address): Promise { return (await withIntoError(this.api.query.compute.codeHashByContractAddress({ contract_address }))) .code_hash! } - protected async doGetCodeHashOfCodeId (code_id: CodeId): Promise { + protected async fetchCodeHashOfCodeIdImpl (code_id: CodeId): Promise { return (await withIntoError(this.api.query.compute.codeHashByCodeId({ code_id }))) .code_hash! } - protected async doGetBalance (denom: string = this.defaultDenom, address: string|undefined = this.address) { + protected async fetchBalanceImpl (denom: string = this.defaultDenom, address: string|undefined = this.address) { return (await withIntoError(this.api.query.bank.balance({ address, denom @@ -135,7 +150,7 @@ export class ScrtConnection extends Chain.Connection { /** Query a contract. * @returns the result of the query */ - protected doQuery (contract: { address: Address, codeHash: CodeHash }, message: Message): Promise { + protected queryImpl (contract: { address: Address, codeHash: CodeHash }, message: Message): Promise { return withIntoError(this.api.query.compute.queryContract({ contract_address: contract.address, code_hash: contract.codeHash, @@ -147,10 +162,53 @@ export class ScrtConnection extends Chain.Connection { return this.api.query.auth.account({ address: this.address }) } - protected async doSend ( + async setMaxGas (): Promise { + const max = ScrtConnection.gasToken.fee((await this.fetchLimits()).gas) + this.fees = { upload: max, init: max, exec: max, send: max } + return this + } + + async fetchLimits (): Promise<{ gas: number }> { + const params = { subspace: "baseapp", key: "BlockParams" } + const { param } = await this.api.query.params.params(params) + let { max_bytes, max_gas } = JSON.parse(param?.value??'{}') + this.log.debug(`Fetched default gas limit: ${max_gas} and code size limit: ${max_bytes}`) + if (max_gas < 0) { + max_gas = 10000000 + this.log.warn(`Chain returned negative max gas limit. Defaulting to: ${max_gas}`) + } + return { gas: max_gas } + } + + async getNonce (): Promise<{ accountNumber: number, sequence: number }> { + const result: any = await this.api.query.auth.account({ address: this.address }) ?? (() => { + throw new Error(`Cannot find account "${this.address}", make sure it has a balance.`) + }) + 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") + } + const { encryptionUtils } = this.api as any + const encrypted = await encryptionUtils.encrypt(codeHash, msg as object) + return base64.encode(encrypted) + } + + batch (): Batch { + return new ScrtBatch({ connection: this }) as unknown as Batch + } + +} + +export class ScrtAgent extends Chain.Agent { + + protected async sendImpl ( recipient: Address, amounts: Token.ICoin[], - options?: Parameters[2] + options?: Parameters[2] ) { return withIntoError(this.api.tx.bank.send( { from_address: this.address!, to_address: recipient, amount: amounts }, @@ -158,7 +216,7 @@ export class ScrtConnection extends Chain.Connection { )) } - protected doSendMany ( + protected sendManyImpl ( outputs: [Address, Token.ICoin[]][], options?: unknown ): Promise { throw new Error('unimplemented') @@ -169,7 +227,7 @@ export class ScrtConnection extends Chain.Connection { } /** Upload a WASM binary. */ - protected async doUpload (data: Uint8Array): Promise> { + protected async uploadImpl (data: Uint8Array): Promise> { const request = { sender: this.address!, wasm_byte_code: data, source: "", builder: "" } const gasLimit = Number(this.fees.upload?.amount[0].amount) || undefined const result = await withIntoError(this.api!.tx.compute.storeCode(request, { gasLimit })) @@ -208,9 +266,9 @@ export class ScrtConnection extends Chain.Connection { } } - protected async doInstantiate ( + protected async instantiateImpl ( codeId: CodeId, - options: Parameters[1] + options: Parameters[1] ): Promise> { if (!this.address) throw new Error("agent has no address") const parameters = { @@ -246,10 +304,10 @@ export class ScrtConnection extends Chain.Connection { } } - protected async doExecute ( + protected async executeImpl ( contract: { address: Address, codeHash: CodeHash }, message: Message, - options?: Parameters[2] & { + options?: Parameters[2] & { preSimulate?: boolean } ): Promise { @@ -288,46 +346,6 @@ export class ScrtConnection extends Chain.Connection { } return result as TxResponse } - - async setMaxGas (): Promise { - const max = ScrtConnection.gasToken.fee((await this.fetchLimits()).gas) - this.fees = { upload: max, init: max, exec: max, send: max } - return this - } - - async fetchLimits (): Promise<{ gas: number }> { - const params = { subspace: "baseapp", key: "BlockParams" } - const { param } = await this.api.query.params.params(params) - let { max_bytes, max_gas } = JSON.parse(param?.value??'{}') - this.log.debug(`Fetched default gas limit: ${max_gas} and code size limit: ${max_bytes}`) - if (max_gas < 0) { - max_gas = 10000000 - this.log.warn(`Chain returned negative max gas limit. Defaulting to: ${max_gas}`) - } - return { gas: max_gas } - } - - async getNonce (): Promise<{ accountNumber: number, sequence: number }> { - const result: any = await this.api.query.auth.account({ address: this.address }) ?? (() => { - throw new Error(`Cannot find account "${this.address}", make sure it has a balance.`) - }) - 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") - } - const { encryptionUtils } = this.api as any - const encrypted = await encryptionUtils.encrypt(codeHash, msg as object) - return base64.encode(encrypted) - } - - batch (): Batch { - return new ScrtBatch({ connection: this }) as unknown as Batch - } - } export class ScrtBlock extends Chain.Block { diff --git a/packages/scrt/scrt-identity.ts b/packages/scrt/scrt-identity.ts index 0caba22ca3..138450081a 100644 --- a/packages/scrt/scrt-identity.ts +++ b/packages/scrt/scrt-identity.ts @@ -1,10 +1,10 @@ -import { Chain, Identity } from '@fadroma/agent' +import { Chain } from '@fadroma/agent' import type { ChainId } from '@fadroma/agent' import { SecretNetworkClient, Wallet } from '@hackbg/secretjs-esm' import type { EncryptionUtils } from '@hackbg/secretjs-esm' import { ScrtError as Error, bold, colors, assign, Bip39, Bip39EN } from './scrt-base' -export abstract class ScrtIdentity extends Identity { +export abstract class ScrtIdentity extends Chain.Identity { abstract getApi ({chainId, url}: {chainId: ChainId, url: string|URL}): SecretNetworkClient static fromKeplr = () => {