diff --git a/CHANGELOG.md b/CHANGELOG.md index f551668d..5a363537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,12 @@ and this project adheres to - @cosmjs/cosmwasm-stargate: The `transferAmount` property on `InstantiateOptions` (accepted as a parameter to `SigningCosmWasmClient.instantiate`) has been renamed to `funds`. +- @cosmjs/cosmwasm-stargate: Default fee/gas values have been removed. Fees now + need to be calculated and passed to `SigningCosmWasmClient` when calling any + methods which submit transactions to the blockchain. +- @cosmjs/stargate: Default fee/gas values have been removed. Fees now need to + be calculated and passed to `SigningStargateClient` when calling any methods + which submit transactions to the blockchain. - @cosmjs/tendermint-rpc: Make `tendermint34.Header.lastBlockId` and `tendermint34.Block.lastCommit` optional to better handle the case of height 1 where there is no previous block. @@ -31,6 +37,11 @@ and this project adheres to ### Removed - Node.js v10 is no longer supported. Please use v12 or later. +- @cosmjs/cosmwasm-stargate: Remove `CosmWasmFeeTable` type and + `defaultGasLimits` object. +- @cosmjs/stargate: Remove types, objects and functions to do with default fees: + `CosmosFeeTable`, `FeeTable`, `GasLimits`, `defaultGasLimits`, + `defaultGasPrice` and `buildFeeTable`. - @cosmjs/tendermint-rpc: `Client` has been removed. Please use `Tendermint33Client` or `Tendermint34Client`, depending on your needs. diff --git a/packages/cosmwasm-stargate/src/cosmwasmclient.spec.ts b/packages/cosmwasm-stargate/src/cosmwasmclient.spec.ts index 7b0502e8..3092ded5 100644 --- a/packages/cosmwasm-stargate/src/cosmwasmclient.spec.ts +++ b/packages/cosmwasm-stargate/src/cosmwasmclient.spec.ts @@ -20,6 +20,8 @@ import { CosmWasmClient, PrivateCosmWasmClient } from "./cosmwasmclient"; import { SigningCosmWasmClient } from "./signingcosmwasmclient"; import { alice, + defaultInstantiateFee, + defaultUploadFee, deployedHackatom, getHackatom, makeRandomAddress, @@ -31,7 +33,7 @@ import { } from "./testutils.spec"; interface HackatomInstance { - readonly initMsg: { + readonly instantiateMsg: { readonly verifier: string; readonly beneficiary: string; }; @@ -318,15 +320,17 @@ describe("CosmWasmClient", () => { if (wasmdEnabled()) { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet); - const { codeId } = await client.upload(alice.address0, getHackatom().data); - const initMsg = { verifier: makeRandomAddress(), beneficiary: makeRandomAddress() }; + const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee); + const instantiateMsg = { verifier: makeRandomAddress(), beneficiary: makeRandomAddress() }; + const label = "random hackatom"; const { contractAddress } = await client.instantiate( alice.address0, codeId, - initMsg, - "random hackatom", + instantiateMsg, + label, + defaultInstantiateFee, ); - contract = { initMsg: initMsg, address: contractAddress }; + contract = { instantiateMsg: instantiateMsg, address: contractAddress }; } }); @@ -338,8 +342,8 @@ describe("CosmWasmClient", () => { const raw = await client.queryContractRaw(contract.address, configKey); assert(raw, "must get result"); expect(JSON.parse(fromAscii(raw))).toEqual({ - verifier: contract.initMsg.verifier, - beneficiary: contract.initMsg.beneficiary, + verifier: contract.instantiateMsg.verifier, + beneficiary: contract.instantiateMsg.beneficiary, funder: alice.address0, }); }); @@ -372,15 +376,17 @@ describe("CosmWasmClient", () => { if (wasmdEnabled()) { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet); - const { codeId } = await client.upload(alice.address0, getHackatom().data); - const initMsg = { verifier: makeRandomAddress(), beneficiary: makeRandomAddress() }; + const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee); + const instantiateMsg = { verifier: makeRandomAddress(), beneficiary: makeRandomAddress() }; + const label = "a different hackatom"; const { contractAddress } = await client.instantiate( alice.address0, codeId, - initMsg, - "a different hackatom", + instantiateMsg, + label, + defaultInstantiateFee, ); - contract = { initMsg: initMsg, address: contractAddress }; + contract = { instantiateMsg: instantiateMsg, address: contractAddress }; } }); @@ -390,7 +396,7 @@ describe("CosmWasmClient", () => { const client = await CosmWasmClient.connect(wasmd.endpoint); const result = await client.queryContractSmart(contract.address, { verifier: {} }); - expect(result).toEqual({ verifier: contract.initMsg.verifier }); + expect(result).toEqual({ verifier: contract.instantiateMsg.verifier }); }); it("errors for malformed query message", async () => { diff --git a/packages/cosmwasm-stargate/src/index.ts b/packages/cosmwasm-stargate/src/index.ts index c48f6a81..e90bbc57 100644 --- a/packages/cosmwasm-stargate/src/index.ts +++ b/packages/cosmwasm-stargate/src/index.ts @@ -22,9 +22,7 @@ export { MsgUpdateAdminEncodeObject, } from "./encodeobjects"; export { - defaultGasLimits, ChangeAdminResult, - CosmWasmFeeTable, // part of SigningCosmWasmClientOptions ExecuteResult, InstantiateOptions, InstantiateResult, diff --git a/packages/cosmwasm-stargate/src/signingcosmwasmclient.spec.ts b/packages/cosmwasm-stargate/src/signingcosmwasmclient.spec.ts index 65f264a0..f592b0a3 100644 --- a/packages/cosmwasm-stargate/src/signingcosmwasmclient.spec.ts +++ b/packages/cosmwasm-stargate/src/signingcosmwasmclient.spec.ts @@ -9,7 +9,6 @@ import { assertIsBroadcastTxSuccess, coin, coins, - GasPrice, MsgDelegateEncodeObject, MsgSendEncodeObject, } from "@cosmjs/stargate"; @@ -27,6 +26,13 @@ import { MsgStoreCodeEncodeObject } from "./encodeobjects"; import { SigningCosmWasmClient, UploadMeta } from "./signingcosmwasmclient"; import { alice, + defaultClearAdminFee, + defaultExecuteFee, + defaultInstantiateFee, + defaultMigrateFee, + defaultSendFee, + defaultUpdateAdminFee, + defaultUploadFee, getHackatom, makeRandomAddress, makeWasmClient, @@ -57,167 +63,6 @@ describe("SigningCosmWasmClient", () => { const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); expect(client.registry.lookupType("/custom.MsgCustom")).toEqual(MsgSend); }); - - it("can be constructed with custom gas price", async () => { - pendingWithoutWasmd(); - const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); - const options = { - prefix: wasmd.prefix, - gasPrice: GasPrice.fromString("3.14utest"), - }; - const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); - expect(client.fees).toEqual({ - upload: { - amount: coins(4710000, "utest"), - gas: "1500000", - }, - init: { - amount: coins(1570000, "utest"), - gas: "500000", - }, - migrate: { - amount: coins(628000, "utest"), - gas: "200000", - }, - exec: { - amount: coins(628000, "utest"), - gas: "200000", - }, - send: { - amount: coins(251200, "utest"), - gas: "80000", - }, - changeAdmin: { - amount: coins(251200, "utest"), - gas: "80000", - }, - delegate: { - amount: coins(502400, "utest"), - gas: "160000", - }, - transfer: { - amount: coins(502400, "utest"), - gas: "160000", - }, - undelegate: { - amount: coins(502400, "utest"), - gas: "160000", - }, - withdraw: { - amount: coins(502400, "utest"), - gas: "160000", - }, - }); - }); - - it("can be constructed with custom gas limits", async () => { - pendingWithoutWasmd(); - const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); - const options = { - prefix: wasmd.prefix, - gasLimits: { - send: 160000, - }, - }; - const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); - expect(client.fees).toEqual({ - upload: { - amount: coins(37500, "ucosm"), - gas: "1500000", - }, - init: { - amount: coins(12500, "ucosm"), - gas: "500000", - }, - migrate: { - amount: coins(5000, "ucosm"), - gas: "200000", - }, - exec: { - amount: coins(5000, "ucosm"), - gas: "200000", - }, - send: { - amount: coins(4000, "ucosm"), - gas: "160000", - }, - changeAdmin: { - amount: coins(2000, "ucosm"), - gas: "80000", - }, - delegate: { - amount: coins(4000, "ucosm"), - gas: "160000", - }, - transfer: { - amount: coins(4000, "ucosm"), - gas: "160000", - }, - undelegate: { - amount: coins(4000, "ucosm"), - gas: "160000", - }, - withdraw: { - amount: coins(4000, "ucosm"), - gas: "160000", - }, - }); - }); - - it("can be constructed with custom gas price and gas limits", async () => { - pendingWithoutWasmd(); - const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); - const options = { - prefix: wasmd.prefix, - gasPrice: GasPrice.fromString("3.14utest"), - gasLimits: { - send: 160000, - }, - }; - const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); - expect(client.fees).toEqual({ - upload: { - amount: coins(4710000, "utest"), - gas: "1500000", - }, - init: { - amount: coins(1570000, "utest"), - gas: "500000", - }, - migrate: { - amount: coins(628000, "utest"), - gas: "200000", - }, - exec: { - amount: coins(628000, "utest"), - gas: "200000", - }, - send: { - amount: coins(502400, "utest"), - gas: "160000", - }, - changeAdmin: { - amount: coins(251200, "utest"), - gas: "80000", - }, - delegate: { - amount: coins(502400, "utest"), - gas: "160000", - }, - transfer: { - amount: coins(502400, "utest"), - gas: "160000", - }, - undelegate: { - amount: coins(502400, "utest"), - gas: "160000", - }, - withdraw: { - amount: coins(502400, "utest"), - gas: "160000", - }, - }); - }); }); describe("upload", () => { @@ -228,7 +73,7 @@ describe("SigningCosmWasmClient", () => { const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); const wasm = getHackatom().data; const { codeId, originalChecksum, originalSize, compressedChecksum, compressedSize } = - await client.upload(alice.address0, wasm); + await client.upload(alice.address0, wasm, defaultUploadFee); expect(originalChecksum).toEqual(toHex(sha256(wasm))); expect(originalSize).toEqual(wasm.length); expect(compressedChecksum).toMatch(/^[0-9a-f]{64}$/); @@ -246,7 +91,7 @@ describe("SigningCosmWasmClient", () => { source: "https://crates.io/api/v1/crates/cw-nameservice/0.1.0/download", builder: "confio/cosmwasm-opt:0.6.2", }; - const { codeId } = await client.upload(alice.address0, hackatom.data, meta); + const { codeId } = await client.upload(alice.address0, hackatom.data, defaultUploadFee, meta); const codeDetails = await client.getCodeDetails(codeId); expect(codeDetails.source).toEqual(meta.source); expect(codeDetails.builder).toEqual(meta.builder); @@ -259,7 +104,7 @@ describe("SigningCosmWasmClient", () => { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); const options = { prefix: wasmd.prefix }; const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); - const { codeId } = await client.upload(alice.address0, getHackatom().data); + const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee); const funds = [coin(1234, "ucosm"), coin(321, "ustake")]; const beneficiaryAddress = makeRandomAddress(); const { contractAddress } = await client.instantiate( @@ -270,6 +115,7 @@ describe("SigningCosmWasmClient", () => { beneficiary: beneficiaryAddress, }, "My cool label", + defaultInstantiateFee, { memo: "Let's see if the memo is used", funds: funds, @@ -287,7 +133,7 @@ describe("SigningCosmWasmClient", () => { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); const options = { prefix: wasmd.prefix }; const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); - const { codeId } = await client.upload(alice.address0, getHackatom().data); + const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee); const beneficiaryAddress = makeRandomAddress(); const { contractAddress } = await client.instantiate( alice.address0, @@ -297,6 +143,7 @@ describe("SigningCosmWasmClient", () => { beneficiary: beneficiaryAddress, }, "My cool label", + defaultInstantiateFee, { admin: unused.address }, ); const wasmClient = await makeWasmClient(wasmd.endpoint); @@ -310,7 +157,7 @@ describe("SigningCosmWasmClient", () => { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); const options = { prefix: wasmd.prefix }; const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); - const { codeId } = await client.upload(alice.address0, getHackatom().data); + const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee); const contractAddress1 = await client.instantiate( alice.address0, codeId, @@ -319,6 +166,7 @@ describe("SigningCosmWasmClient", () => { beneficiary: makeRandomAddress(), }, "contract 1", + defaultInstantiateFee, ); const contractAddress2 = await client.instantiate( alice.address0, @@ -328,6 +176,7 @@ describe("SigningCosmWasmClient", () => { beneficiary: makeRandomAddress(), }, "contract 2", + defaultInstantiateFee, ); expect(contractAddress1).not.toEqual(contractAddress2); }); @@ -339,7 +188,7 @@ describe("SigningCosmWasmClient", () => { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); const options = { prefix: wasmd.prefix }; const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); - const { codeId } = await client.upload(alice.address0, getHackatom().data); + const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee); const beneficiaryAddress = makeRandomAddress(); const { contractAddress } = await client.instantiate( alice.address0, @@ -349,6 +198,8 @@ describe("SigningCosmWasmClient", () => { beneficiary: beneficiaryAddress, }, "My cool label", + defaultInstantiateFee, + { admin: alice.address0, }, @@ -358,7 +209,7 @@ describe("SigningCosmWasmClient", () => { assert(contractInfo1); expect(contractInfo1.admin).toEqual(alice.address0); - await client.updateAdmin(alice.address0, contractAddress, unused.address); + await client.updateAdmin(alice.address0, contractAddress, unused.address, defaultUpdateAdminFee); const { contractInfo: contractInfo2 } = await wasmClient.wasm.getContractInfo(contractAddress); assert(contractInfo2); expect(contractInfo2.admin).toEqual(unused.address); @@ -371,7 +222,7 @@ describe("SigningCosmWasmClient", () => { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); const options = { prefix: wasmd.prefix }; const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); - const { codeId } = await client.upload(alice.address0, getHackatom().data); + const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee); const beneficiaryAddress = makeRandomAddress(); const { contractAddress } = await client.instantiate( alice.address0, @@ -381,6 +232,7 @@ describe("SigningCosmWasmClient", () => { beneficiary: beneficiaryAddress, }, "My cool label", + defaultInstantiateFee, { admin: alice.address0, }, @@ -390,7 +242,7 @@ describe("SigningCosmWasmClient", () => { assert(contractInfo1); expect(contractInfo1.admin).toEqual(alice.address0); - await client.clearAdmin(alice.address0, contractAddress); + await client.clearAdmin(alice.address0, contractAddress, defaultClearAdminFee); const { contractInfo: contractInfo2 } = await wasmClient.wasm.getContractInfo(contractAddress); assert(contractInfo2); expect(contractInfo2.admin).toEqual(""); @@ -403,8 +255,8 @@ describe("SigningCosmWasmClient", () => { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); const options = { prefix: wasmd.prefix }; const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); - const { codeId: codeId1 } = await client.upload(alice.address0, getHackatom().data); - const { codeId: codeId2 } = await client.upload(alice.address0, getHackatom().data); + const { codeId: codeId1 } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee); + const { codeId: codeId2 } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee); const beneficiaryAddress = makeRandomAddress(); const { contractAddress } = await client.instantiate( alice.address0, @@ -414,6 +266,7 @@ describe("SigningCosmWasmClient", () => { beneficiary: beneficiaryAddress, }, "My cool label", + defaultInstantiateFee, { admin: alice.address0, }, @@ -424,7 +277,13 @@ describe("SigningCosmWasmClient", () => { expect(contractInfo1.admin).toEqual(alice.address0); const newVerifier = makeRandomAddress(); - await client.migrate(alice.address0, contractAddress, codeId2, { verifier: newVerifier }); + await client.migrate( + alice.address0, + contractAddress, + codeId2, + { verifier: newVerifier }, + defaultMigrateFee, + ); const { contractInfo: contractInfo2 } = await wasmClient.wasm.getContractInfo(contractAddress); assert(contractInfo2); expect({ ...contractInfo2 }).toEqual({ @@ -440,7 +299,7 @@ describe("SigningCosmWasmClient", () => { const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix }); const options = { prefix: wasmd.prefix }; const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options); - const { codeId } = await client.upload(alice.address0, getHackatom().data); + const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee); // instantiate const funds = [coin(233444, "ucosm"), coin(5454, "ustake")]; const beneficiaryAddress = makeRandomAddress(); @@ -452,12 +311,18 @@ describe("SigningCosmWasmClient", () => { beneficiary: beneficiaryAddress, }, "amazing random contract", + defaultInstantiateFee, { funds: funds, }, ); // execute - const result = await client.execute(alice.address0, contractAddress, { release: {} }, undefined); + const result = await client.execute( + alice.address0, + contractAddress, + { release: {} }, + defaultExecuteFee, + ); const wasmEvent = result.logs[0].events.find((e) => e.type === "wasm"); assert(wasmEvent, "Event of type wasm expected"); expect(wasmEvent.attributes).toContain({ key: "action", value: "release" }); @@ -497,7 +362,13 @@ describe("SigningCosmWasmClient", () => { }); // send - const result = await client.sendTokens(alice.address0, beneficiaryAddress, amount, memo); + const result = await client.sendTokens( + alice.address0, + beneficiaryAddress, + amount, + defaultSendFee, + memo, + ); assertIsBroadcastTxSuccess(result); expect(result.rawLog).toBeTruthy(); @@ -525,7 +396,13 @@ describe("SigningCosmWasmClient", () => { }); // send - const result = await client.sendTokens(alice.address0, beneficiaryAddress, amount, memo); + const result = await client.sendTokens( + alice.address0, + beneficiaryAddress, + amount, + defaultSendFee, + memo, + ); assertIsBroadcastTxSuccess(result); expect(result.rawLog).toBeTruthy(); diff --git a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts index 95c72e09..c95632b3 100644 --- a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts @@ -18,14 +18,8 @@ import { AminoTypes, BroadcastTxFailure, BroadcastTxResponse, - buildFeeTable, Coin, - CosmosFeeTable, - defaultGasLimits as defaultStargateGasLimits, - defaultGasPrice, defaultRegistryTypes, - GasLimits, - GasPrice, isBroadcastTxFailure, logs, MsgDelegateEncodeObject, @@ -63,18 +57,6 @@ import { MsgUpdateAdminEncodeObject, } from "./encodeobjects"; -/** - * These fees are used by the higher level methods of SigningCosmWasmClient - */ -export interface CosmWasmFeeTable extends CosmosFeeTable { - readonly upload: StdFee; - readonly init: StdFee; - readonly exec: StdFee; - readonly migrate: StdFee; - /** Paid when setting the contract admin to a new address or unsetting it */ - readonly changeAdmin: StdFee; -} - function prepareBuilder(builder: string | undefined): string { if (builder === undefined) { return ""; // normalization needed by backend @@ -84,15 +66,6 @@ function prepareBuilder(builder: string | undefined): string { } } -export const defaultGasLimits: GasLimits = { - ...defaultStargateGasLimits, - upload: 1_500_000, - init: 500_000, - migrate: 200_000, - exec: 200_000, - changeAdmin: 80_000, -}; - export interface UploadMeta { /** * An URL to a .tar.gz archive of the source code of the contract, which can be used to reproducibly build the Wasm bytecode. @@ -195,14 +168,11 @@ export interface SigningCosmWasmClientOptions { readonly registry?: Registry; readonly aminoTypes?: AminoTypes; readonly prefix?: string; - readonly gasPrice?: GasPrice; - readonly gasLimits?: Partial>; readonly broadcastTimeoutMs?: number; readonly broadcastPollIntervalMs?: number; } export class SigningCosmWasmClient extends CosmWasmClient { - public readonly fees: CosmWasmFeeTable; public readonly registry: Registry; public readonly broadcastTimeoutMs: number | undefined; public readonly broadcastPollIntervalMs: number | undefined; @@ -244,10 +214,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { const { registry = createDefaultRegistry(), aminoTypes = new AminoTypes({ additions: cosmWasmTypes, prefix: options.prefix }), - gasPrice = defaultGasPrice, - gasLimits = {}, } = options; - this.fees = buildFeeTable(gasPrice, defaultGasLimits, gasLimits); this.registry = registry; this.aminoTypes = aminoTypes; this.signer = signer; @@ -259,6 +226,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { public async upload( senderAddress: string, wasmCode: Uint8Array, + fee: StdFee, meta: UploadMeta = {}, memo = "", ): Promise { @@ -275,7 +243,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { }), }; - const result = await this.signAndBroadcast(senderAddress, [storeCodeMsg], this.fees.upload, memo); + const result = await this.signAndBroadcast(senderAddress, [storeCodeMsg], fee, memo); if (isBroadcastTxFailure(result)) { throw new Error(createBroadcastTxErrorMessage(result)); } @@ -297,6 +265,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { codeId: number, msg: Record, label: string, + fee: StdFee, options: InstantiateOptions = {}, ): Promise { const instantiateContractMsg: MsgInstantiateContractEncodeObject = { @@ -310,12 +279,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { admin: options.admin, }), }; - const result = await this.signAndBroadcast( - senderAddress, - [instantiateContractMsg], - this.fees.init, - options.memo, - ); + const result = await this.signAndBroadcast(senderAddress, [instantiateContractMsg], fee, options.memo); if (isBroadcastTxFailure(result)) { throw new Error(createBroadcastTxErrorMessage(result)); } @@ -332,6 +296,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { senderAddress: string, contractAddress: string, newAdmin: string, + fee: StdFee, memo = "", ): Promise { const updateAdminMsg: MsgUpdateAdminEncodeObject = { @@ -342,7 +307,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { newAdmin: newAdmin, }), }; - const result = await this.signAndBroadcast(senderAddress, [updateAdminMsg], this.fees.changeAdmin, memo); + const result = await this.signAndBroadcast(senderAddress, [updateAdminMsg], fee, memo); if (isBroadcastTxFailure(result)) { throw new Error(createBroadcastTxErrorMessage(result)); } @@ -355,6 +320,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { public async clearAdmin( senderAddress: string, contractAddress: string, + fee: StdFee, memo = "", ): Promise { const clearAdminMsg: MsgClearAdminEncodeObject = { @@ -364,7 +330,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { contract: contractAddress, }), }; - const result = await this.signAndBroadcast(senderAddress, [clearAdminMsg], this.fees.changeAdmin, memo); + const result = await this.signAndBroadcast(senderAddress, [clearAdminMsg], fee, memo); if (isBroadcastTxFailure(result)) { throw new Error(createBroadcastTxErrorMessage(result)); } @@ -379,6 +345,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { contractAddress: string, codeId: number, migrateMsg: Record, + fee: StdFee, memo = "", ): Promise { const migrateContractMsg: MsgMigrateContractEncodeObject = { @@ -390,7 +357,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { migrateMsg: toUtf8(JSON.stringify(migrateMsg)), }), }; - const result = await this.signAndBroadcast(senderAddress, [migrateContractMsg], this.fees.migrate, memo); + const result = await this.signAndBroadcast(senderAddress, [migrateContractMsg], fee, memo); if (isBroadcastTxFailure(result)) { throw new Error(createBroadcastTxErrorMessage(result)); } @@ -404,6 +371,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { senderAddress: string, contractAddress: string, msg: Record, + fee: StdFee, memo = "", funds?: readonly Coin[], ): Promise { @@ -416,7 +384,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { funds: [...(funds || [])], }), }; - const result = await this.signAndBroadcast(senderAddress, [executeContractMsg], this.fees.exec, memo); + const result = await this.signAndBroadcast(senderAddress, [executeContractMsg], fee, memo); if (isBroadcastTxFailure(result)) { throw new Error(createBroadcastTxErrorMessage(result)); } @@ -430,6 +398,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { senderAddress: string, recipientAddress: string, amount: readonly Coin[], + fee: StdFee, memo = "", ): Promise { const sendMsg: MsgSendEncodeObject = { @@ -440,45 +409,48 @@ export class SigningCosmWasmClient extends CosmWasmClient { amount: [...amount], }, }; - return this.signAndBroadcast(senderAddress, [sendMsg], this.fees.send, memo); + return this.signAndBroadcast(senderAddress, [sendMsg], fee, memo); } public async delegateTokens( delegatorAddress: string, validatorAddress: string, amount: Coin, + fee: StdFee, memo = "", ): Promise { const delegateMsg: MsgDelegateEncodeObject = { typeUrl: "/cosmos.staking.v1beta1.MsgDelegate", value: MsgDelegate.fromPartial({ delegatorAddress: delegatorAddress, validatorAddress, amount }), }; - return this.signAndBroadcast(delegatorAddress, [delegateMsg], this.fees.delegate, memo); + return this.signAndBroadcast(delegatorAddress, [delegateMsg], fee, memo); } public async undelegateTokens( delegatorAddress: string, validatorAddress: string, amount: Coin, + fee: StdFee, memo = "", ): Promise { const undelegateMsg: MsgUndelegateEncodeObject = { typeUrl: "/cosmos.staking.v1beta1.MsgUndelegate", value: MsgUndelegate.fromPartial({ delegatorAddress: delegatorAddress, validatorAddress, amount }), }; - return this.signAndBroadcast(delegatorAddress, [undelegateMsg], this.fees.undelegate, memo); + return this.signAndBroadcast(delegatorAddress, [undelegateMsg], fee, memo); } public async withdrawRewards( delegatorAddress: string, validatorAddress: string, + fee: StdFee, memo = "", ): Promise { const withdrawDelegatorRewardMsg: MsgWithdrawDelegatorRewardEncodeObject = { typeUrl: "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", value: MsgWithdrawDelegatorReward.fromPartial({ delegatorAddress: delegatorAddress, validatorAddress }), }; - return this.signAndBroadcast(delegatorAddress, [withdrawDelegatorRewardMsg], this.fees.withdraw, memo); + return this.signAndBroadcast(delegatorAddress, [withdrawDelegatorRewardMsg], fee, memo); } /** diff --git a/packages/cosmwasm-stargate/src/testutils.spec.ts b/packages/cosmwasm-stargate/src/testutils.spec.ts index 7f80d47d..a8f37eac 100644 --- a/packages/cosmwasm-stargate/src/testutils.spec.ts +++ b/packages/cosmwasm-stargate/src/testutils.spec.ts @@ -11,7 +11,9 @@ import { import { AuthExtension, BankExtension, + calculateFee, coins, + GasPrice, QueryClient, setupAuthExtension, setupBankExtension, @@ -23,6 +25,15 @@ import { AuthInfo, SignDoc, TxBody } from "cosmjs-types/cosmos/tx/v1beta1/tx"; import { setupWasmExtension, WasmExtension } from "./queries"; import hackatom from "./testdata/contract.json"; +export const defaultGasPrice = GasPrice.fromString("0.025ucosm"); +export const defaultSendFee = calculateFee(80_000, defaultGasPrice); +export const defaultUploadFee = calculateFee(1_500_000, defaultGasPrice); +export const defaultInstantiateFee = calculateFee(500_000, defaultGasPrice); +export const defaultExecuteFee = calculateFee(200_000, defaultGasPrice); +export const defaultMigrateFee = calculateFee(200_000, defaultGasPrice); +export const defaultUpdateAdminFee = calculateFee(80_000, defaultGasPrice); +export const defaultClearAdminFee = calculateFee(80_000, defaultGasPrice); + /** An internal testing type. SigningCosmWasmClient has a similar but different interface */ export interface ContractUploadInstructions { /** The wasm bytecode */ diff --git a/packages/faucet/src/faucet.ts b/packages/faucet/src/faucet.ts index 8df97e29..354a5d06 100644 --- a/packages/faucet/src/faucet.ts +++ b/packages/faucet/src/faucet.ts @@ -5,6 +5,7 @@ import { } from "@cosmjs/launchpad"; import { assertIsBroadcastTxSuccess as assertIsBroadcastTxSuccessStargate, + calculateFee, SigningStargateClient, StargateClient, } from "@cosmjs/stargate"; @@ -88,7 +89,8 @@ export class Faucet { const result = await client.sendTokens(job.recipient, [job.amount], constants.memo); return assertIsBroadcastTxSuccessLaunchpad(result); } - const result = await client.sendTokens(job.sender, job.recipient, [job.amount], constants.memo); + const fee = calculateFee(constants.gasLimits.send, constants.gasPrice); + const result = await client.sendTokens(job.sender, job.recipient, [job.amount], fee, constants.memo); assertIsBroadcastTxSuccessStargate(result); } diff --git a/packages/faucet/src/profile.ts b/packages/faucet/src/profile.ts index eccac4f9..60ba24e1 100644 --- a/packages/faucet/src/profile.ts +++ b/packages/faucet/src/profile.ts @@ -43,10 +43,7 @@ export async function createClients( > => [ senderAddress, isOfflineDirectSigner(wallet) - ? await SigningStargateClient.connectWithSigner(apiUrl, wallet, { - gasLimits: constants.gasLimits, - gasPrice: constants.gasPrice, - }) + ? await SigningStargateClient.connectWithSigner(apiUrl, wallet) : new SigningCosmosClient(apiUrl, senderAddress, wallet, constants.gasPrice, constants.gasLimits), ], ), diff --git a/packages/ledger-amino/src/ledgersigner.spec.ts b/packages/ledger-amino/src/ledgersigner.spec.ts index c3883d47..05901abb 100644 --- a/packages/ledger-amino/src/ledgersigner.spec.ts +++ b/packages/ledger-amino/src/ledgersigner.spec.ts @@ -6,7 +6,6 @@ import { makeSignDoc, Secp256k1HdWallet, serializeSignDoc, - StdFee, } from "@cosmjs/amino"; import { Secp256k1, Secp256k1Signature, sha256 } from "@cosmjs/crypto"; import { fromBase64 } from "@cosmjs/encoding"; @@ -16,6 +15,7 @@ import { } from "@cosmjs/launchpad"; import { assertIsBroadcastTxSuccess as assertIsBroadcastTxSuccessStargate, + calculateFee, SigningStargateClient, } from "@cosmjs/stargate"; import { sleep } from "@cosmjs/utils"; @@ -53,10 +53,7 @@ async function createTransport(): Promise { describe("LedgerSigner", () => { const defaultChainId = "testing"; - const defaultFee: StdFee = { - amount: coins(100, "ucosm"), - gas: "250", - }; + const defaultFee = calculateFee(80_000, "0.025ucosm"); const defaultMemo = "Some memo"; const defaultSequence = "0"; const defaultAccountNumber = "42"; @@ -69,7 +66,13 @@ describe("LedgerSigner", () => { const client = await SigningStargateClient.connectWithSigner(simapp.endpoint, wallet); const amount = coins(226644, "ucosm"); const memo = "Ensure chain has my pubkey"; - const sendResult = await client.sendTokens(faucet.address, defaultLedgerAddress, amount, memo); + const sendResult = await client.sendTokens( + faucet.address, + defaultLedgerAddress, + amount, + defaultFee, + memo, + ); assertIsBroadcastTxSuccessStargate(sendResult); } }); @@ -197,6 +200,7 @@ describe("LedgerSigner", () => { firstAccount.address, defaultLedgerAddress, coins(1234, "ucosm"), + defaultFee, ); assertIsBroadcastTxSuccessStargate(result); }, diff --git a/packages/stargate/src/fee.spec.ts b/packages/stargate/src/fee.spec.ts index 1407ea65..43897041 100644 --- a/packages/stargate/src/fee.spec.ts +++ b/packages/stargate/src/fee.spec.ts @@ -1,6 +1,6 @@ import { Decimal } from "@cosmjs/math"; -import { GasPrice } from "./fee"; +import { calculateFee, GasPrice } from "./fee"; describe("GasPrice", () => { it("can be constructed", () => { @@ -59,3 +59,25 @@ describe("GasPrice", () => { }); }); }); + +describe("calculateFee", () => { + it("multiplies the gas price by the gas limit", () => { + const gasLimit = 80000; + const gasPrice = GasPrice.fromString("0.025ucosm"); + const fee = calculateFee(gasLimit, gasPrice); + expect(fee).toEqual({ + amount: [{ amount: "2000", denom: "ucosm" }], + gas: "80000", + }); + }); + + it("accepts a string gas price", () => { + const gasLimit = 80000; + const gasPrice = "0.025ucosm"; + const fee = calculateFee(gasLimit, gasPrice); + expect(fee).toEqual({ + amount: [{ amount: "2000", denom: "ucosm" }], + gas: "80000", + }); + }); +}); diff --git a/packages/stargate/src/fee.ts b/packages/stargate/src/fee.ts index b8ecc6ea..f8b40590 100644 --- a/packages/stargate/src/fee.ts +++ b/packages/stargate/src/fee.ts @@ -2,11 +2,6 @@ import { StdFee } from "@cosmjs/amino"; import { Decimal, Uint53 } from "@cosmjs/math"; import { coins } from "@cosmjs/proto-signing"; -/** - * This is the same as FeeTable from @cosmjs/launchpad but those might diverge in the future. - */ -export type FeeTable = Record; - /** * Denom checker for the Cosmos SDK 0.42 denom pattern * (https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/types/coin.go#L599-L601). @@ -56,37 +51,12 @@ export class GasPrice { } } -/** - * This is the same as GasLimits from @cosmjs/launchpad but those might diverge in the future. - */ -export type GasLimits> = { - readonly [key in keyof T]: number; -}; - -/** - * This is the same as calculateFee from @cosmjs/launchpad but those might diverge in the future. - */ -function calculateFee(gasLimit: number, { denom, amount: gasPriceAmount }: GasPrice): StdFee { +export function calculateFee(gasLimit: number, gasPrice: GasPrice | string): StdFee { + const processedGasPrice = typeof gasPrice === "string" ? GasPrice.fromString(gasPrice) : gasPrice; + const { denom, amount: gasPriceAmount } = processedGasPrice; const amount = Math.ceil(gasPriceAmount.multiply(new Uint53(gasLimit)).toFloatApproximation()); return { amount: coins(amount, denom), gas: gasLimit.toString(), }; } - -/** - * This is the same as buildFeeTable from @cosmjs/launchpad but those might diverge in the future. - */ -export function buildFeeTable>( - gasPrice: GasPrice, - defaultGasLimits: GasLimits, - gasLimits: Partial>, -): T { - return Object.entries(defaultGasLimits).reduce( - (feeTable, [type, defaultGasLimit]) => ({ - ...feeTable, - [type]: calculateFee(gasLimits[type] || defaultGasLimit, gasPrice), - }), - {} as T, - ); -} diff --git a/packages/stargate/src/index.ts b/packages/stargate/src/index.ts index 34c5785b..fc01db0b 100644 --- a/packages/stargate/src/index.ts +++ b/packages/stargate/src/index.ts @@ -51,7 +51,7 @@ export { MsgUndelegateEncodeObject, MsgWithdrawDelegatorRewardEncodeObject, } from "./encodeobjects"; -export { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./fee"; +export { calculateFee, GasPrice } from "./fee"; export * as logs from "./logs"; export { makeMultisignedTx } from "./multisignature"; export { @@ -95,9 +95,6 @@ export { TimeoutError, } from "./stargateclient"; export { - CosmosFeeTable, - defaultGasLimits, - defaultGasPrice, defaultRegistryTypes, SignerData, SigningStargateClient, diff --git a/packages/stargate/src/signingstargateclient.spec.ts b/packages/stargate/src/signingstargateclient.spec.ts index 8ec679ba..961a59d5 100644 --- a/packages/stargate/src/signingstargateclient.spec.ts +++ b/packages/stargate/src/signingstargateclient.spec.ts @@ -12,10 +12,10 @@ import { decodeTxRaw } from "../../proto-signing/build"; import { AminoMsgDelegate } from "./aminomsgs"; import { AminoTypes } from "./aminotypes"; import { MsgDelegateEncodeObject, MsgSendEncodeObject } from "./encodeobjects"; -import { GasPrice } from "./fee"; import { PrivateSigningStargateClient, SigningStargateClient } from "./signingstargateclient"; import { assertIsBroadcastTxSuccess } from "./stargateclient"; import { + defaultSendFee, faucet, makeRandomAddress, ModifyingDirectSecp256k1HdWallet, @@ -27,60 +27,6 @@ import { describe("SigningStargateClient", () => { describe("constructor", () => { - it("can be constructed with default fees", async () => { - pendingWithoutSimapp(); - const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic); - const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet); - const openedClient = client as unknown as PrivateSigningStargateClient; - expect(openedClient.fees).toEqual({ - send: { - amount: [ - { - amount: "2000", - denom: "ucosm", - }, - ], - gas: "80000", - }, - delegate: { - amount: [ - { - amount: "4000", - denom: "ucosm", - }, - ], - gas: "160000", - }, - transfer: { - amount: [ - { - amount: "4000", - denom: "ucosm", - }, - ], - gas: "160000", - }, - undelegate: { - amount: [ - { - amount: "4000", - denom: "ucosm", - }, - ], - gas: "160000", - }, - withdraw: { - amount: [ - { - amount: "4000", - denom: "ucosm", - }, - ], - gas: "160000", - }, - }); - }); - it("can be constructed with custom registry", async () => { pendingWithoutSimapp(); const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic); @@ -91,180 +37,6 @@ describe("SigningStargateClient", () => { const openedClient = client as unknown as PrivateSigningStargateClient; expect(openedClient.registry.lookupType("/custom.MsgCustom")).toEqual(MsgSend); }); - - it("can be constructed with custom gas price", async () => { - pendingWithoutSimapp(); - const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic); - const gasPrice = GasPrice.fromString("3.14utest"); - const options = { gasPrice: gasPrice }; - const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet, options); - const openedClient = client as unknown as PrivateSigningStargateClient; - expect(openedClient.fees).toEqual({ - send: { - amount: [ - { - amount: "251200", // 3.14 * 80_000 - denom: "utest", - }, - ], - gas: "80000", - }, - delegate: { - amount: [ - { - amount: "502400", // 3.14 * 160_000 - denom: "utest", - }, - ], - gas: "160000", - }, - transfer: { - amount: [ - { - amount: "502400", - denom: "utest", - }, - ], - gas: "160000", - }, - undelegate: { - amount: [ - { - amount: "502400", - denom: "utest", - }, - ], - gas: "160000", - }, - withdraw: { - amount: [ - { - amount: "502400", - denom: "utest", - }, - ], - gas: "160000", - }, - }); - }); - - it("can be constructed with custom gas limits", async () => { - pendingWithoutSimapp(); - const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic); - const gasLimits = { - send: 160000, - delegate: 120000, - }; - const options = { gasLimits: gasLimits }; - const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet, options); - const openedClient = client as unknown as PrivateSigningStargateClient; - expect(openedClient.fees).toEqual({ - send: { - amount: [ - { - amount: "4000", // 0.025 * 160_000 - denom: "ucosm", - }, - ], - gas: "160000", - }, - delegate: { - amount: [ - { - amount: "3000", // 0.025 * 120_000 - denom: "ucosm", - }, - ], - gas: "120000", - }, - transfer: { - amount: [ - { - amount: "4000", - denom: "ucosm", - }, - ], - gas: "160000", - }, - undelegate: { - amount: [ - { - amount: "4000", - denom: "ucosm", - }, - ], - gas: "160000", - }, - withdraw: { - amount: [ - { - amount: "4000", - denom: "ucosm", - }, - ], - gas: "160000", - }, - }); - }); - - it("can be constructed with custom gas price and gas limits", async () => { - pendingWithoutSimapp(); - const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic); - const gasPrice = GasPrice.fromString("3.14utest"); - const gasLimits = { - send: 160000, - }; - const options = { gasPrice: gasPrice, gasLimits: gasLimits }; - const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet, options); - const openedClient = client as unknown as PrivateSigningStargateClient; - expect(openedClient.fees).toEqual({ - send: { - amount: [ - { - amount: "502400", // 3.14 * 160_000 - denom: "utest", - }, - ], - gas: "160000", - }, - delegate: { - amount: [ - { - amount: "502400", // 3.14 * 160_000 - denom: "utest", - }, - ], - gas: "160000", - }, - transfer: { - amount: [ - { - amount: "502400", - denom: "utest", - }, - ], - gas: "160000", - }, - undelegate: { - amount: [ - { - amount: "502400", - denom: "utest", - }, - ], - gas: "160000", - }, - withdraw: { - amount: [ - { - amount: "502400", - denom: "utest", - }, - ], - gas: "160000", - }, - }); - }); }); describe("sendTokens", () => { @@ -285,7 +57,13 @@ describe("SigningStargateClient", () => { }); // send - const result = await client.sendTokens(faucet.address0, beneficiaryAddress, amount, memo); + const result = await client.sendTokens( + faucet.address0, + beneficiaryAddress, + amount, + defaultSendFee, + memo, + ); assertIsBroadcastTxSuccess(result); expect(result.rawLog).toBeTruthy(); @@ -311,7 +89,13 @@ describe("SigningStargateClient", () => { }); // send - const result = await client.sendTokens(faucet.address0, beneficiaryAddress, amount, memo); + const result = await client.sendTokens( + faucet.address0, + beneficiaryAddress, + amount, + defaultSendFee, + memo, + ); assertIsBroadcastTxSuccess(result); expect(result.rawLog).toBeTruthy(); diff --git a/packages/stargate/src/signingstargateclient.ts b/packages/stargate/src/signingstargateclient.ts index f2cc0829..9010372a 100644 --- a/packages/stargate/src/signingstargateclient.ts +++ b/packages/stargate/src/signingstargateclient.ts @@ -67,31 +67,8 @@ import { MsgUndelegateEncodeObject, MsgWithdrawDelegatorRewardEncodeObject, } from "./encodeobjects"; -import { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./fee"; import { BroadcastTxResponse, StargateClient } from "./stargateclient"; -/** - * These fees are used by the higher level methods of SigningCosmosClient - * - * This is the same as CosmosFeeTable from @cosmjs/launchpad but those might diverge in the future. - */ -export interface CosmosFeeTable extends FeeTable { - readonly send: StdFee; - readonly delegate: StdFee; - readonly transfer: StdFee; - readonly undelegate: StdFee; - readonly withdraw: StdFee; -} - -export const defaultGasPrice = GasPrice.fromString("0.025ucosm"); -export const defaultGasLimits: GasLimits = { - send: 80_000, - delegate: 160_000, - transfer: 160_000, - undelegate: 160_000, - withdraw: 160_000, -}; - export const defaultRegistryTypes: ReadonlyArray<[string, GeneratedType]> = [ ["/cosmos.bank.v1beta1.MsgMultiSend", MsgMultiSend], ["/cosmos.distribution.v1beta1.MsgFundCommunityPool", MsgFundCommunityPool], @@ -141,7 +118,6 @@ export interface SignerData { /** Use for testing only */ export interface PrivateSigningStargateClient { - readonly fees: CosmosFeeTable; readonly registry: Registry; } @@ -149,14 +125,11 @@ export interface SigningStargateClientOptions { readonly registry?: Registry; readonly aminoTypes?: AminoTypes; readonly prefix?: string; - readonly gasPrice?: GasPrice; - readonly gasLimits?: Partial>; readonly broadcastTimeoutMs?: number; readonly broadcastPollIntervalMs?: number; } export class SigningStargateClient extends StargateClient { - public readonly fees: CosmosFeeTable; public readonly registry: Registry; public readonly broadcastTimeoutMs: number | undefined; public readonly broadcastPollIntervalMs: number | undefined; @@ -195,13 +168,8 @@ export class SigningStargateClient extends StargateClient { options: SigningStargateClientOptions, ) { super(tmClient); - const { - registry = createDefaultRegistry(), - aminoTypes = new AminoTypes({ prefix: options.prefix }), - gasPrice = defaultGasPrice, - gasLimits = {}, - } = options; - this.fees = buildFeeTable(gasPrice, defaultGasLimits, gasLimits); + const { registry = createDefaultRegistry(), aminoTypes = new AminoTypes({ prefix: options.prefix }) } = + options; this.registry = registry; this.aminoTypes = aminoTypes; this.signer = signer; @@ -213,6 +181,7 @@ export class SigningStargateClient extends StargateClient { senderAddress: string, recipientAddress: string, amount: readonly Coin[], + fee: StdFee, memo = "", ): Promise { const sendMsg: MsgSendEncodeObject = { @@ -223,13 +192,14 @@ export class SigningStargateClient extends StargateClient { amount: [...amount], }, }; - return this.signAndBroadcast(senderAddress, [sendMsg], this.fees.send, memo); + return this.signAndBroadcast(senderAddress, [sendMsg], fee, memo); } public async delegateTokens( delegatorAddress: string, validatorAddress: string, amount: Coin, + fee: StdFee, memo = "", ): Promise { const delegateMsg: MsgDelegateEncodeObject = { @@ -240,13 +210,14 @@ export class SigningStargateClient extends StargateClient { amount: amount, }), }; - return this.signAndBroadcast(delegatorAddress, [delegateMsg], this.fees.delegate, memo); + return this.signAndBroadcast(delegatorAddress, [delegateMsg], fee, memo); } public async undelegateTokens( delegatorAddress: string, validatorAddress: string, amount: Coin, + fee: StdFee, memo = "", ): Promise { const undelegateMsg: MsgUndelegateEncodeObject = { @@ -257,12 +228,13 @@ export class SigningStargateClient extends StargateClient { amount: amount, }), }; - return this.signAndBroadcast(delegatorAddress, [undelegateMsg], this.fees.undelegate, memo); + return this.signAndBroadcast(delegatorAddress, [undelegateMsg], fee, memo); } public async withdrawRewards( delegatorAddress: string, validatorAddress: string, + fee: StdFee, memo = "", ): Promise { const withdrawMsg: MsgWithdrawDelegatorRewardEncodeObject = { @@ -272,7 +244,7 @@ export class SigningStargateClient extends StargateClient { validatorAddress: validatorAddress, }), }; - return this.signAndBroadcast(delegatorAddress, [withdrawMsg], this.fees.withdraw, memo); + return this.signAndBroadcast(delegatorAddress, [withdrawMsg], fee, memo); } public async sendIbcTokens( @@ -284,6 +256,7 @@ export class SigningStargateClient extends StargateClient { timeoutHeight: Height | undefined, /** timeout in seconds */ timeoutTimestamp: number | undefined, + fee: StdFee, memo = "", ): Promise { const timeoutTimestampNanoseconds = timeoutTimestamp @@ -301,7 +274,7 @@ export class SigningStargateClient extends StargateClient { timeoutTimestamp: timeoutTimestampNanoseconds, }), }; - return this.signAndBroadcast(senderAddress, [transferMsg], this.fees.transfer, memo); + return this.signAndBroadcast(senderAddress, [transferMsg], fee, memo); } public async signAndBroadcast( diff --git a/packages/stargate/src/testutils.spec.ts b/packages/stargate/src/testutils.spec.ts index 44814d2d..3f0e17d1 100644 --- a/packages/stargate/src/testutils.spec.ts +++ b/packages/stargate/src/testutils.spec.ts @@ -12,6 +12,8 @@ import { import { SignMode } from "cosmjs-types/cosmos/tx/signing/v1beta1/signing"; import { AuthInfo, SignDoc, TxBody } from "cosmjs-types/cosmos/tx/v1beta1/tx"; +import { calculateFee, GasPrice } from "./fee"; + export function simappEnabled(): boolean { return !!process.env.SIMAPP_ENABLED; } @@ -46,6 +48,9 @@ export function fromOneElementArray(elements: ArrayLike): T { return elements[0]; } +export const defaultGasPrice = GasPrice.fromString("0.025ucosm"); +export const defaultSendFee = calculateFee(80_000, defaultGasPrice); + export const simapp = { tendermintUrl: "localhost:26658", tendermintUrlWs: "ws://localhost:26658", diff --git a/scripts/wasmd/deploy_cw1.js b/scripts/wasmd/deploy_cw1.js index dd10bd5c..707999fb 100755 --- a/scripts/wasmd/deploy_cw1.js +++ b/scripts/wasmd/deploy_cw1.js @@ -1,8 +1,9 @@ #!/usr/bin/env -S yarn node /* eslint-disable @typescript-eslint/naming-convention */ -const { DirectSecp256k1HdWallet } = require("@cosmjs/proto-signing"); const { SigningCosmWasmClient } = require("@cosmjs/cosmwasm-stargate"); +const { DirectSecp256k1HdWallet } = require("@cosmjs/proto-signing"); +const { GasPrice, calculateFee } = require("@cosmjs/stargate"); const fs = require("fs"); const endpoint = "http://localhost:26659"; @@ -21,11 +22,19 @@ const codeMeta = { }; async function main() { + const gasPrice = GasPrice.fromString("0.025ucosm"); const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: "wasm" }); const client = await SigningCosmWasmClient.connectWithSigner(endpoint, wallet); const wasm = fs.readFileSync(__dirname + "/contracts/cw1_subkeys.wasm"); - const uploadReceipt = await client.upload(alice.address0, wasm, codeMeta, "Upload CW1 subkeys contract"); + const uploadFee = calculateFee(1_500_000, gasPrice); + const uploadReceipt = await client.upload( + alice.address0, + wasm, + uploadFee, + codeMeta, + "Upload CW1 subkeys contract", + ); console.info(`Upload succeeded. Receipt: ${JSON.stringify(uploadReceipt)}`); const initMsg = { @@ -33,16 +42,30 @@ async function main() { mutable: true, }; const label = "Subkey test"; - const { contractAddress } = await client.instantiate(alice.address0, uploadReceipt.codeId, initMsg, label, { - memo: `Create a CW1 instance for ${alice.address0}`, - admin: alice.address0, - }); - await client.sendTokens(alice.address0, contractAddress, [ + const instantiateFee = calculateFee(500_000, gasPrice); + const { contractAddress } = await client.instantiate( + alice.address0, + uploadReceipt.codeId, + initMsg, + label, + instantiateFee, { - amount: "1000", - denom: "ucosm", + memo: `Create a CW1 instance for ${alice.address0}`, + admin: alice.address0, }, - ]); + ); + const sendFee = calculateFee(80_000, gasPrice); + await client.sendTokens( + alice.address0, + contractAddress, + [ + { + amount: "1000", + denom: "ucosm", + }, + ], + sendFee, + ); console.info(`Contract instantiated for ${alice.address0} subkey at ${contractAddress}`); } diff --git a/scripts/wasmd/deploy_cw3.js b/scripts/wasmd/deploy_cw3.js index f41f0a3c..a388880c 100755 --- a/scripts/wasmd/deploy_cw3.js +++ b/scripts/wasmd/deploy_cw3.js @@ -1,8 +1,9 @@ #!/usr/bin/env -S yarn node /* eslint-disable @typescript-eslint/naming-convention */ -const { DirectSecp256k1HdWallet } = require("@cosmjs/proto-signing"); const { SigningCosmWasmClient } = require("@cosmjs/cosmwasm-stargate"); +const { DirectSecp256k1HdWallet } = require("@cosmjs/proto-signing"); +const { GasPrice, calculateFee } = require("@cosmjs/stargate"); const fs = require("fs"); const endpoint = "http://localhost:26659"; @@ -63,35 +64,46 @@ const initData = [ ]; async function main() { + const gasPrice = GasPrice.fromString("0.025ucosm"); const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: "wasm" }); const client = await SigningCosmWasmClient.connectWithSigner(endpoint, wallet); const wasm = fs.readFileSync(__dirname + "/contracts/cw3_fixed_multisig.wasm"); + const uploadFee = calculateFee(1_500_000, gasPrice); const uploadReceipt = await client.upload( alice.address0, wasm, + uploadFee, codeMeta, "Upload CW3 fixed multisig contract", ); console.info(`Upload succeeded. Receipt: ${JSON.stringify(uploadReceipt)}`); + const instantiateFee = calculateFee(500_000, gasPrice); + const sendFee = calculateFee(80_000, gasPrice); for (const { admin, initMsg, label } of initData) { const { contractAddress } = await client.instantiate( alice.address0, uploadReceipt.codeId, initMsg, label, + instantiateFee, { memo: `Create a CW3 instance for ${initMsg.symbol}`, admin: admin, }, ); - await client.sendTokens(alice.address0, contractAddress, [ - { - amount: "1000", - denom: "ucosm", - }, - ]); + await client.sendTokens( + alice.address0, + contractAddress, + [ + { + amount: "1000", + denom: "ucosm", + }, + ], + sendFee, + ); console.info(`Contract instantiated for ${label} at ${contractAddress}`); } } diff --git a/scripts/wasmd/deploy_hackatom.js b/scripts/wasmd/deploy_hackatom.js index 1f7227fd..629a5403 100755 --- a/scripts/wasmd/deploy_hackatom.js +++ b/scripts/wasmd/deploy_hackatom.js @@ -1,8 +1,9 @@ #!/usr/bin/env -S yarn node /* eslint-disable @typescript-eslint/naming-convention */ -const { DirectSecp256k1HdWallet } = require("@cosmjs/proto-signing"); const { SigningCosmWasmClient } = require("@cosmjs/cosmwasm-stargate"); +const { DirectSecp256k1HdWallet } = require("@cosmjs/proto-signing"); +const { calculateFee, GasPrice } = require("@cosmjs/stargate"); const fs = require("fs"); const endpoint = "http://localhost:26659"; @@ -48,18 +49,34 @@ const inits = [ ]; async function main() { + const gasPrice = GasPrice.fromString("0.025ucosm"); const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: "wasm" }); const client = await SigningCosmWasmClient.connectWithSigner(endpoint, wallet); const wasm = fs.readFileSync(__dirname + "/contracts/hackatom.wasm"); - const uploadReceipt = await client.upload(alice.address0, wasm, codeMeta, "Upload hackatom contract"); + const uploadFee = calculateFee(1_500_000, gasPrice); + const uploadReceipt = await client.upload( + alice.address0, + wasm, + uploadFee, + codeMeta, + "Upload hackatom contract", + ); console.info(`Upload succeeded. Receipt: ${JSON.stringify(uploadReceipt)}`); + const instantiateFee = calculateFee(500_000, gasPrice); for (const { label, msg, admin } of inits) { - const { contractAddress } = await client.instantiate(alice.address0, uploadReceipt.codeId, msg, label, { - memo: `Create a hackatom instance in deploy_hackatom.js`, - admin: admin, - }); + const { contractAddress } = await client.instantiate( + alice.address0, + uploadReceipt.codeId, + msg, + label, + instantiateFee, + { + memo: `Create a hackatom instance in deploy_hackatom.js`, + admin: admin, + }, + ); console.info(`Contract instantiated at ${contractAddress}`); } } diff --git a/scripts/wasmd/send_first.js b/scripts/wasmd/send_first.js index 686ae7cc..2383e22b 100755 --- a/scripts/wasmd/send_first.js +++ b/scripts/wasmd/send_first.js @@ -5,7 +5,12 @@ const { coins } = require("@cosmjs/amino"); const { Random } = require("@cosmjs/crypto"); const { Bech32 } = require("@cosmjs/encoding"); const { DirectSecp256k1HdWallet } = require("@cosmjs/proto-signing"); -const { assertIsBroadcastTxSuccess, SigningStargateClient } = require("@cosmjs/stargate"); +const { + assertIsBroadcastTxSuccess, + SigningStargateClient, + calculateFee, + GasPrice, +} = require("@cosmjs/stargate"); const rpcUrl = "http://localhost:26659"; const prefix = "wasm"; @@ -20,8 +25,9 @@ async function main() { const client = await SigningStargateClient.connectWithSigner(rpcUrl, wallet, { prefix: prefix }); const recipient = Bech32.encode(prefix, Random.getBytes(20)); const amount = coins(226644, "ucosm"); + const fee = calculateFee(80_000, "0.025ucosm"); const memo = "Ensure chain has my pubkey"; - const sendResult = await client.sendTokens(faucet.address0, recipient, amount, memo); + const sendResult = await client.sendTokens(faucet.address0, recipient, amount, fee, memo); assertIsBroadcastTxSuccess(sendResult); }