Merge branch 'main' into feat/add-staking-cancel-unbond-msg
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/amino",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Helpers for Amino based signing.",
|
||||
"contributors": [
|
||||
"Simon Warta <webmaster128@users.noreply.github.com>"
|
||||
|
||||
@@ -81,15 +81,41 @@ describe("coins", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("works for two", () => {
|
||||
expect(parseCoins("819966000ucosm,700000000ustake")).toEqual([
|
||||
it("works for various denoms", () => {
|
||||
// very short (3)
|
||||
expect(parseCoins("7643bar")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
amount: "7643",
|
||||
denom: "bar",
|
||||
},
|
||||
]);
|
||||
|
||||
// very long (128)
|
||||
expect(
|
||||
parseCoins(
|
||||
"7643abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
amount: "7643",
|
||||
denom:
|
||||
"abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
|
||||
},
|
||||
]);
|
||||
|
||||
// IBC denom (https://github.com/cosmos/cosmos-sdk/blob/v0.42.7/types/coin_test.go#L512-L519)
|
||||
expect(parseCoins("7643ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2",
|
||||
},
|
||||
]);
|
||||
|
||||
// Token factory denom (https://docs.osmosis.zone/osmosis-core/modules/tokenfactory/)
|
||||
expect(parseCoins("100000000000factory/osmo1c584m4lq25h83yp6ag8hh4htjr92d954vklzja/ufoo")).toEqual([
|
||||
{
|
||||
amount: "100000000000",
|
||||
denom: "factory/osmo1c584m4lq25h83yp6ag8hh4htjr92d954vklzja/ufoo",
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -144,6 +170,19 @@ describe("coins", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("works for two", () => {
|
||||
expect(parseCoins("819966000ucosm,700000000ustake")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("ignores empty elements", () => {
|
||||
// start
|
||||
expect(parseCoins(",819966000ucosm,700000000ustake")).toEqual([
|
||||
@@ -186,6 +225,20 @@ describe("coins", () => {
|
||||
|
||||
// amount missing
|
||||
expect(() => parseCoins("ucosm")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom starting with slash
|
||||
expect(() => parseCoins("3456/ibc")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom too short
|
||||
expect(() => parseCoins("3456a")).toThrowError(/invalid coin string/i);
|
||||
expect(() => parseCoins("3456aa")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom too long
|
||||
expect(() =>
|
||||
parseCoins(
|
||||
"3456abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgha",
|
||||
),
|
||||
).toThrowError(/invalid coin string/i);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -46,13 +46,21 @@ export function coins(amount: number | string, denom: string): Coin[] {
|
||||
/**
|
||||
* Takes a coins list like "819966000ucosm,700000000ustake" and parses it.
|
||||
*
|
||||
* A Stargate-ready variant of this function is available via:
|
||||
* Starting with CosmJS 0.32.3, the following imports are all synonym and support
|
||||
* a variety of denom types such as IBC denoms or tokenfactory. If you need to
|
||||
* restrict the denom to something very minimal, this needs to be implemented
|
||||
* separately in the caller.
|
||||
*
|
||||
* ```
|
||||
* import { parseCoins } from "@cosmjs/proto-signing";
|
||||
* // or
|
||||
* // equals
|
||||
* import { parseCoins } from "@cosmjs/stargate";
|
||||
* // equals
|
||||
* import { parseCoins } from "@cosmjs/amino";
|
||||
* ```
|
||||
*
|
||||
* This function is not made for supporting decimal amounts and does not support
|
||||
* parsing gas prices.
|
||||
*/
|
||||
export function parseCoins(input: string): Coin[] {
|
||||
return input
|
||||
@@ -60,7 +68,8 @@ export function parseCoins(input: string): Coin[] {
|
||||
.split(",")
|
||||
.filter(Boolean)
|
||||
.map((part) => {
|
||||
const match = part.match(/^([0-9]+)([a-zA-Z]+)/);
|
||||
// Denom regex from Stargate (https://github.com/cosmos/cosmos-sdk/blob/v0.42.7/types/coin.go#L599-L601)
|
||||
const match = part.match(/^([0-9]+)([a-zA-Z][a-zA-Z0-9/]{2,127})$/);
|
||||
if (!match) throw new Error("Got an invalid coin string");
|
||||
return {
|
||||
amount: match[1].replace(/^0+/, "") || "0",
|
||||
|
||||
@@ -46,7 +46,7 @@ async function main(hackatomWasmPath: string) {
|
||||
// Execute contract
|
||||
const executeFee = calculateFee(300_000, gasPrice);
|
||||
const result = await client.execute(alice.address0, contractAddress, { release: {} }, executeFee);
|
||||
const wasmEvent = result.logs[0].events.find((e) => e.type === "wasm");
|
||||
const wasmEvent = result.events.find((e) => e.type === "wasm");
|
||||
console.info("The `wasm` event emitted by the contract execution:", wasmEvent);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/cli",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Command line interface",
|
||||
"contributors": [
|
||||
"IOV SAS <admin@iov.one>",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/cosmwasm-stargate",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "CosmWasm SDK",
|
||||
"contributors": [
|
||||
"Will Clark <willclarktech@users.noreply.github.com>"
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
Registry,
|
||||
TxBodyEncodeObject,
|
||||
} from "@cosmjs/proto-signing";
|
||||
import { assertIsDeliverTxSuccess, coins, logs, MsgSendEncodeObject, StdFee } from "@cosmjs/stargate";
|
||||
import { assertIsDeliverTxSuccess, coins, MsgSendEncodeObject, StdFee } from "@cosmjs/stargate";
|
||||
import { assert, sleep } from "@cosmjs/utils";
|
||||
import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
@@ -188,7 +188,6 @@ describe("CosmWasmClient", () => {
|
||||
amount: coins(5000, "ucosm"),
|
||||
gas: "890000",
|
||||
};
|
||||
|
||||
const chainId = await client.getChainId();
|
||||
const sequenceResponse = await client.getSequence(alice.address0);
|
||||
assert(sequenceResponse);
|
||||
@@ -222,8 +221,11 @@ describe("CosmWasmClient", () => {
|
||||
const signedTx = Uint8Array.from(TxRaw.encode(txRaw).finish());
|
||||
const result = await client.broadcastTx(signedTx);
|
||||
assertIsDeliverTxSuccess(result);
|
||||
const amountAttr = logs.findAttribute(logs.parseRawLog(result.rawLog), "transfer", "amount");
|
||||
expect(amountAttr.value).toEqual("1234567ucosm");
|
||||
const amountAttrs = result.events
|
||||
.filter((e) => e.type == "transfer")
|
||||
.flatMap((e) => e.attributes.filter((a) => a.key == "amount"));
|
||||
expect(amountAttrs[0].value).toEqual("5000ucosm"); // fee
|
||||
expect(amountAttrs[1].value).toEqual("1234567ucosm"); // MsgSend amount
|
||||
expect(result.transactionHash).toMatch(/^[0-9A-F]{64}$/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,15 +58,19 @@ export function _instantiate2AddressIntermediate(
|
||||
/**
|
||||
* Predictable address generation for the MsgInstantiateContract2
|
||||
* introduced with wasmd 0.29.
|
||||
*
|
||||
* With `checksum`, `creator` and `salt`, the instantiate 2 address is
|
||||
* generated in binary form. The `bech32Prefix` is then used for the bech32 representation.
|
||||
* Chains using address formats other than bech32 are not supported by this API.
|
||||
*/
|
||||
export function instantiate2Address(
|
||||
checksum: Uint8Array,
|
||||
creator: string,
|
||||
salt: Uint8Array,
|
||||
prefix: string,
|
||||
bech32Prefix: string,
|
||||
): string {
|
||||
// Non-empty msg values are discouraged.
|
||||
// See https://medium.com/cosmwasm/dev-note-3-limitations-of-instantiate2-and-how-to-deal-with-them-a3f946874230.
|
||||
const msg = null;
|
||||
return _instantiate2AddressIntermediate(checksum, creator, salt, msg, prefix).address;
|
||||
return _instantiate2AddressIntermediate(checksum, creator, salt, msg, bech32Prefix).address;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
coin,
|
||||
coins,
|
||||
DeliverTxResponse,
|
||||
logs,
|
||||
SigningStargateClient,
|
||||
StdFee,
|
||||
} from "@cosmjs/stargate";
|
||||
@@ -15,7 +14,7 @@ import { assert, assertDefined } from "@cosmjs/utils";
|
||||
import { MsgExecuteContract, MsgInstantiateContract, MsgStoreCode } from "cosmjs-types/cosmwasm/wasm/v1/tx";
|
||||
import { AbsoluteTxPosition, ContractCodeHistoryOperationType } from "cosmjs-types/cosmwasm/wasm/v1/types";
|
||||
|
||||
import { SigningCosmWasmClient } from "../../signingcosmwasmclient";
|
||||
import { findAttribute, SigningCosmWasmClient } from "../../signingcosmwasmclient";
|
||||
import {
|
||||
alice,
|
||||
bech32AddressMatcher,
|
||||
@@ -385,12 +384,11 @@ describe("WasmExtension", () => {
|
||||
{
|
||||
const result = await uploadContract(wallet, getHackatom());
|
||||
assertIsDeliverTxSuccess(result);
|
||||
const parsedLogs = logs.parseLogs(logs.parseRawLog(result.rawLog));
|
||||
const codeIdAttr = logs.findAttribute(parsedLogs, "store_code", "code_id");
|
||||
const codeIdAttr = findAttribute(result.events, "store_code", "code_id");
|
||||
codeId = Number.parseInt(codeIdAttr.value, 10);
|
||||
expect(codeId).toBeGreaterThanOrEqual(1);
|
||||
expect(codeId).toBeLessThanOrEqual(200);
|
||||
const actionAttr = logs.findAttribute(parsedLogs, "message", "module");
|
||||
const actionAttr = findAttribute(result.events, "message", "module");
|
||||
expect(actionAttr.value).toEqual("wasm");
|
||||
}
|
||||
|
||||
@@ -400,12 +398,14 @@ describe("WasmExtension", () => {
|
||||
{
|
||||
const result = await instantiateContract(wallet, codeId, beneficiaryAddress, funds);
|
||||
assertIsDeliverTxSuccess(result);
|
||||
const parsedLogs = logs.parseLogs(logs.parseRawLog(result.rawLog));
|
||||
const contractAddressAttr = logs.findAttribute(parsedLogs, "instantiate", "_contract_address");
|
||||
const contractAddressAttr = findAttribute(result.events, "instantiate", "_contract_address");
|
||||
contractAddress = contractAddressAttr.value;
|
||||
const amountAttr = logs.findAttribute(parsedLogs, "transfer", "amount");
|
||||
expect(amountAttr.value).toEqual("1234ucosm,321ustake");
|
||||
const actionAttr = logs.findAttribute(parsedLogs, "message", "module");
|
||||
const amountAttrs = result.events
|
||||
.filter((e) => e.type == "transfer")
|
||||
.flatMap((e) => e.attributes.filter((a) => a.key == "amount"));
|
||||
expect(amountAttrs[0].value).toEqual("5000000ucosm"); // fee
|
||||
expect(amountAttrs[1].value).toEqual("1234ucosm,321ustake"); // instantiate funds
|
||||
const actionAttr = findAttribute(result.events, "message", "module");
|
||||
expect(actionAttr.value).toEqual("wasm");
|
||||
|
||||
const balanceUcosm = await client.bank.balance(contractAddress, "ucosm");
|
||||
@@ -418,8 +418,7 @@ describe("WasmExtension", () => {
|
||||
{
|
||||
const result = await executeContract(wallet, contractAddress, { release: {} });
|
||||
assertIsDeliverTxSuccess(result);
|
||||
const parsedLogs = logs.parseLogs(logs.parseRawLog(result.rawLog));
|
||||
const wasmEvent = parsedLogs.find(() => true)?.events.find((e) => e.type === "wasm");
|
||||
const wasmEvent = result.events.find((e) => e.type === "wasm");
|
||||
assert(wasmEvent, "Event of type wasm expected");
|
||||
expect(wasmEvent.attributes).toContain({ key: "action", value: "release" });
|
||||
expect(wasmEvent.attributes).toContain({
|
||||
|
||||
@@ -126,23 +126,75 @@ describe("SigningCosmWasmClient", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with legacy Amino signer access type", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix });
|
||||
const options = { ...defaultSigningClientOptions, prefix: wasmd.prefix };
|
||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||
const client = await SigningCosmWasmClient.connectWithSigner(
|
||||
wasmd.endpoint,
|
||||
wallet,
|
||||
defaultSigningClientOptions,
|
||||
);
|
||||
const wasm = getHackatom().data;
|
||||
const accessConfig: AccessConfig = {
|
||||
permission: AccessType.ACCESS_TYPE_EVERYBODY,
|
||||
address: "",
|
||||
addresses: [],
|
||||
};
|
||||
const { codeId, checksum, originalSize, compressedSize } = await client.upload(
|
||||
alice.address0,
|
||||
wasm,
|
||||
defaultUploadFee,
|
||||
);
|
||||
expect(checksum).toEqual(toHex(sha256(wasm)));
|
||||
expect(originalSize).toEqual(wasm.length);
|
||||
expect(compressedSize).toBeLessThan(wasm.length * 0.5);
|
||||
expect(codeId).toBeGreaterThanOrEqual(1);
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with Amino JSON signer (instantiatePermission set to one address)", async () => {
|
||||
pending("Known issue: https://github.com/CosmWasm/wasmd/issues/1863");
|
||||
pendingWithoutWasmd();
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix });
|
||||
const client = await SigningCosmWasmClient.connectWithSigner(
|
||||
wasmd.endpoint,
|
||||
wallet,
|
||||
defaultSigningClientOptions,
|
||||
);
|
||||
const wasm = getHackatom().data;
|
||||
const instantiatePermission = AccessConfig.fromPartial({
|
||||
permission: AccessType.ACCESS_TYPE_ANY_OF_ADDRESSES,
|
||||
addresses: [makeRandomAddress()],
|
||||
});
|
||||
const { codeId, checksum, originalSize, compressedSize } = await client.upload(
|
||||
alice.address0,
|
||||
wasm,
|
||||
defaultUploadFee,
|
||||
"test memo",
|
||||
accessConfig,
|
||||
instantiatePermission,
|
||||
);
|
||||
expect(checksum).toEqual(toHex(sha256(wasm)));
|
||||
expect(originalSize).toEqual(wasm.length);
|
||||
expect(compressedSize).toBeLessThan(wasm.length * 0.5);
|
||||
expect(codeId).toBeGreaterThanOrEqual(1);
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with Amino JSON signer (instantiatePermission set to everybody)", async () => {
|
||||
pending("Known issue: https://github.com/CosmWasm/wasmd/issues/1863");
|
||||
pendingWithoutWasmd();
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix });
|
||||
const client = await SigningCosmWasmClient.connectWithSigner(
|
||||
wasmd.endpoint,
|
||||
wallet,
|
||||
defaultSigningClientOptions,
|
||||
);
|
||||
const wasm = getHackatom().data;
|
||||
const instantiatePermission = AccessConfig.fromPartial({
|
||||
permission: AccessType.ACCESS_TYPE_EVERYBODY,
|
||||
addresses: [],
|
||||
});
|
||||
const { codeId, checksum, originalSize, compressedSize } = await client.upload(
|
||||
alice.address0,
|
||||
wasm,
|
||||
defaultUploadFee,
|
||||
"test memo",
|
||||
instantiatePermission,
|
||||
);
|
||||
expect(checksum).toEqual(toHex(sha256(wasm)));
|
||||
expect(originalSize).toEqual(wasm.length);
|
||||
@@ -261,7 +313,7 @@ describe("SigningCosmWasmClient", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with legacy Amino signer", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix });
|
||||
const client = await SigningCosmWasmClient.connectWithSigner(
|
||||
@@ -269,6 +321,23 @@ describe("SigningCosmWasmClient", () => {
|
||||
wallet,
|
||||
defaultSigningClientOptions,
|
||||
);
|
||||
const funds = [coin(1234, "ucosm"), coin(321, "ustake")];
|
||||
|
||||
// Without admin
|
||||
await client.instantiate(
|
||||
alice.address0,
|
||||
deployedHackatom.codeId,
|
||||
{
|
||||
verifier: alice.address0,
|
||||
beneficiary: makeRandomAddress(),
|
||||
},
|
||||
"contract 1",
|
||||
defaultInstantiateFee,
|
||||
{
|
||||
funds: funds,
|
||||
memo: "instantiate it",
|
||||
},
|
||||
);
|
||||
|
||||
// With admin
|
||||
await client.instantiate(
|
||||
@@ -280,19 +349,10 @@ describe("SigningCosmWasmClient", () => {
|
||||
},
|
||||
"contract 1",
|
||||
defaultInstantiateFee,
|
||||
{ admin: makeRandomAddress() },
|
||||
);
|
||||
|
||||
// Without admin
|
||||
await client.instantiate(
|
||||
alice.address0,
|
||||
deployedHackatom.codeId,
|
||||
{
|
||||
verifier: alice.address0,
|
||||
beneficiary: makeRandomAddress(),
|
||||
funds: funds,
|
||||
admin: makeRandomAddress(),
|
||||
},
|
||||
"contract 1",
|
||||
defaultInstantiateFee,
|
||||
);
|
||||
|
||||
client.disconnect();
|
||||
@@ -313,7 +373,7 @@ describe("SigningCosmWasmClient", () => {
|
||||
const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee);
|
||||
const funds = [coin(1234, "ucosm"), coin(321, "ustake")];
|
||||
const beneficiaryAddress = makeRandomAddress();
|
||||
const salt = Uint8Array.from([0x01]);
|
||||
const salt = Random.getBytes(64); // different salt every time we run the test to avoid address collision erors
|
||||
const wasm = getHackatom().data;
|
||||
const msg = {
|
||||
verifier: alice.address0,
|
||||
@@ -344,41 +404,65 @@ describe("SigningCosmWasmClient", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with Amino JSON signing", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const aminoJsonWallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, {
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, {
|
||||
prefix: wasmd.prefix,
|
||||
});
|
||||
const client = await SigningCosmWasmClient.connectWithSigner(
|
||||
wasmd.endpoint,
|
||||
aminoJsonWallet,
|
||||
wallet,
|
||||
defaultSigningClientOptions,
|
||||
);
|
||||
const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee);
|
||||
const funds = [coin(1234, "ucosm"), coin(321, "ustake")];
|
||||
const salt = Random.getBytes(64);
|
||||
const msg = {
|
||||
verifier: alice.address0,
|
||||
beneficiary: makeRandomAddress(),
|
||||
};
|
||||
|
||||
const { contractAddress } = await client.instantiate2(
|
||||
alice.address0,
|
||||
codeId,
|
||||
salt,
|
||||
msg,
|
||||
"My cool label--",
|
||||
defaultInstantiateFee,
|
||||
{
|
||||
memo: "Let's see if the memo is used",
|
||||
funds: funds,
|
||||
},
|
||||
);
|
||||
// Without admin
|
||||
{
|
||||
const salt = Random.getBytes(64);
|
||||
const { contractAddress } = await client.instantiate2(
|
||||
alice.address0,
|
||||
codeId,
|
||||
salt,
|
||||
msg,
|
||||
"My cool label--",
|
||||
defaultInstantiateFee,
|
||||
{
|
||||
memo: "Let's see if the memo is used",
|
||||
funds: funds,
|
||||
},
|
||||
);
|
||||
const ucosmBalance = await client.getBalance(contractAddress, "ucosm");
|
||||
const ustakeBalance = await client.getBalance(contractAddress, "ustake");
|
||||
expect(ucosmBalance).toEqual(funds[0]);
|
||||
expect(ustakeBalance).toEqual(funds[1]);
|
||||
}
|
||||
|
||||
const ucosmBalance = await client.getBalance(contractAddress, "ucosm");
|
||||
const ustakeBalance = await client.getBalance(contractAddress, "ustake");
|
||||
expect(ucosmBalance).toEqual(funds[0]);
|
||||
expect(ustakeBalance).toEqual(funds[1]);
|
||||
// With admin
|
||||
{
|
||||
const salt = Random.getBytes(64);
|
||||
const { contractAddress } = await client.instantiate2(
|
||||
alice.address0,
|
||||
codeId,
|
||||
salt,
|
||||
msg,
|
||||
"My cool label--",
|
||||
defaultInstantiateFee,
|
||||
{
|
||||
memo: "Let's see if the memo is used",
|
||||
funds: funds,
|
||||
admin: makeRandomAddress(),
|
||||
},
|
||||
);
|
||||
const ucosmBalance = await client.getBalance(contractAddress, "ucosm");
|
||||
const ustakeBalance = await client.getBalance(contractAddress, "ustake");
|
||||
expect(ucosmBalance).toEqual(funds[0]);
|
||||
expect(ustakeBalance).toEqual(funds[1]);
|
||||
}
|
||||
|
||||
client.disconnect();
|
||||
});
|
||||
@@ -525,7 +609,7 @@ describe("SigningCosmWasmClient", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with legacy Amino signer", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix });
|
||||
const client = await SigningCosmWasmClient.connectWithSigner(
|
||||
@@ -607,7 +691,7 @@ describe("SigningCosmWasmClient", () => {
|
||||
expect(result.height).toBeGreaterThan(0);
|
||||
expect(result.gasWanted).toBeGreaterThan(0);
|
||||
expect(result.gasUsed).toBeGreaterThan(0);
|
||||
const wasmEvent = result.logs[0].events.find((e) => e.type === "wasm");
|
||||
const wasmEvent = result.events.find((e) => e.type === "wasm");
|
||||
assert(wasmEvent, "Event of type wasm expected");
|
||||
expect(wasmEvent.attributes).toContain({ key: "action", value: "release" });
|
||||
expect(wasmEvent.attributes).toContain({
|
||||
@@ -628,7 +712,7 @@ describe("SigningCosmWasmClient", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with legacy Amino signer", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix });
|
||||
const client = await SigningCosmWasmClient.connectWithSigner(
|
||||
@@ -660,7 +744,7 @@ describe("SigningCosmWasmClient", () => {
|
||||
{ release: {} },
|
||||
defaultExecuteFee,
|
||||
);
|
||||
const wasmEvent = result.logs[0].events.find((e) => e.type === "wasm");
|
||||
const wasmEvent = result.events.find((e) => e.type === "wasm");
|
||||
assert(wasmEvent, "Event of type wasm expected");
|
||||
expect(wasmEvent.attributes).toContain({ key: "action", value: "release" });
|
||||
expect(wasmEvent.attributes).toContain({
|
||||
@@ -727,16 +811,17 @@ describe("SigningCosmWasmClient", () => {
|
||||
],
|
||||
"auto",
|
||||
);
|
||||
expect(result.logs.length).toEqual(2);
|
||||
const wasmEvent1 = result.logs[0].events.find((e) => e.type === "wasm");
|
||||
assert(wasmEvent1, "Event of type wasm expected");
|
||||
const { events } = result;
|
||||
const wasmEvents = events.filter((e) => e.type == "wasm");
|
||||
expect(wasmEvents.length).toEqual(2);
|
||||
const [wasmEvent1, wasmEvent2] = wasmEvents;
|
||||
expect(wasmEvent1.type).toEqual("wasm");
|
||||
expect(wasmEvent1.attributes).toContain({ key: "action", value: "release" });
|
||||
expect(wasmEvent1.attributes).toContain({
|
||||
key: "destination",
|
||||
value: beneficiaryAddress1,
|
||||
});
|
||||
const wasmEvent2 = result.logs[1].events.find((e) => e.type === "wasm");
|
||||
assert(wasmEvent2, "Event of type wasm expected");
|
||||
expect(wasmEvent2.type).toEqual("wasm");
|
||||
expect(wasmEvent2.attributes).toContain({ key: "action", value: "release" });
|
||||
expect(wasmEvent2.attributes).toContain({
|
||||
key: "destination",
|
||||
@@ -777,7 +862,8 @@ describe("SigningCosmWasmClient", () => {
|
||||
memo,
|
||||
);
|
||||
assertIsDeliverTxSuccess(result);
|
||||
expect(result.rawLog).toBeTruthy();
|
||||
expect(result.rawLog).toEqual(""); // empty for wasmd >= 0.50.0 (https://github.com/cosmos/cosmos-sdk/pull/15845)
|
||||
expect(result.events.length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// got tokens
|
||||
const after = await client.getBalance(beneficiaryAddress, "ucosm");
|
||||
@@ -787,7 +873,7 @@ describe("SigningCosmWasmClient", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with legacy Amino signer", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix });
|
||||
const client = await SigningCosmWasmClient.connectWithSigner(
|
||||
@@ -816,7 +902,8 @@ describe("SigningCosmWasmClient", () => {
|
||||
memo,
|
||||
);
|
||||
assertIsDeliverTxSuccess(result);
|
||||
expect(result.rawLog).toBeTruthy();
|
||||
expect(result.rawLog).toEqual(""); // empty for wasmd >= 0.50.0 (https://github.com/cosmos/cosmos-sdk/pull/15845)
|
||||
expect(result.events.length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// got tokens
|
||||
const after = await client.getBalance(beneficiaryAddress, "ucosm");
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from "@cosmjs/proto-signing";
|
||||
import {
|
||||
AminoTypes,
|
||||
Attribute,
|
||||
calculateFee,
|
||||
Coin,
|
||||
createDefaultAminoConverters,
|
||||
@@ -72,6 +73,7 @@ export interface UploadResult {
|
||||
readonly compressedSize: number;
|
||||
/** The ID of the code asigned by the chain */
|
||||
readonly codeId: number;
|
||||
/** @deprecated Not filled in Cosmos SDK >= 0.50. Use events instead. */
|
||||
readonly logs: readonly logs.Log[];
|
||||
/** Block height in which the transaction is included */
|
||||
readonly height: number;
|
||||
@@ -106,6 +108,7 @@ export interface InstantiateOptions {
|
||||
export interface InstantiateResult {
|
||||
/** The address of the newly instantiated contract */
|
||||
readonly contractAddress: string;
|
||||
/** @deprecated Not filled in Cosmos SDK >= 0.50. Use events instead. */
|
||||
readonly logs: readonly logs.Log[];
|
||||
/** Block height in which the transaction is included */
|
||||
readonly height: number;
|
||||
@@ -120,6 +123,7 @@ export interface InstantiateResult {
|
||||
* Result type of updateAdmin and clearAdmin
|
||||
*/
|
||||
export interface ChangeAdminResult {
|
||||
/** @deprecated Not filled in Cosmos SDK >= 0.50. Use events instead. */
|
||||
readonly logs: readonly logs.Log[];
|
||||
/** Block height in which the transaction is included */
|
||||
readonly height: number;
|
||||
@@ -131,6 +135,7 @@ export interface ChangeAdminResult {
|
||||
}
|
||||
|
||||
export interface MigrateResult {
|
||||
/** @deprecated Not filled in Cosmos SDK >= 0.50. Use events instead. */
|
||||
readonly logs: readonly logs.Log[];
|
||||
/** Block height in which the transaction is included */
|
||||
readonly height: number;
|
||||
@@ -148,6 +153,7 @@ export interface ExecuteInstruction {
|
||||
}
|
||||
|
||||
export interface ExecuteResult {
|
||||
/** @deprecated Not filled in Cosmos SDK >= 0.50. Use events instead. */
|
||||
readonly logs: readonly logs.Log[];
|
||||
/** Block height in which the transaction is included */
|
||||
readonly height: number;
|
||||
@@ -158,6 +164,24 @@ export interface ExecuteResult {
|
||||
readonly gasUsed: bigint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches in events for an event of the given event type which contains an
|
||||
* attribute for with the given key.
|
||||
*
|
||||
* Throws if the attribute was not found.
|
||||
*/
|
||||
export function findAttribute(events: readonly Event[], eventType: string, attrKey: string): Attribute {
|
||||
// all attributes from events with the right event type
|
||||
const attributes = events.filter((event) => event.type === eventType).flatMap((e) => e.attributes);
|
||||
const out = attributes.find((attr) => attr.key === attrKey);
|
||||
if (!out) {
|
||||
throw new Error(
|
||||
`Could not find attribute '${attrKey}' in first event of type '${eventType}' in first log.`,
|
||||
);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function createDeliverTxResponseErrorMessage(result: DeliverTxResponse): string {
|
||||
return `Error when broadcasting tx ${result.transactionHash} at height ${result.height}. Code: ${result.code}; Raw log: ${result.rawLog}`;
|
||||
}
|
||||
@@ -178,6 +202,9 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
private readonly signer: OfflineSigner;
|
||||
private readonly aminoTypes: AminoTypes;
|
||||
private readonly gasPrice: GasPrice | undefined;
|
||||
// Starting with Cosmos SDK 0.47, we see many cases in which 1.3 is not enough anymore
|
||||
// E.g. https://github.com/cosmos/cosmos-sdk/issues/16020
|
||||
private readonly defaultGasMultiplier = 1.4;
|
||||
|
||||
/**
|
||||
* Creates an instance by connecting to the given CometBFT RPC endpoint.
|
||||
@@ -288,14 +315,13 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
if (isDeliverTxFailure(result)) {
|
||||
throw new Error(createDeliverTxResponseErrorMessage(result));
|
||||
}
|
||||
const parsedLogs = logs.parseRawLog(result.rawLog);
|
||||
const codeIdAttr = logs.findAttribute(parsedLogs, "store_code", "code_id");
|
||||
const codeIdAttr = findAttribute(result.events, "store_code", "code_id");
|
||||
return {
|
||||
checksum: toHex(sha256(wasmCode)),
|
||||
originalSize: wasmCode.length,
|
||||
compressedSize: compressed.length,
|
||||
codeId: Number.parseInt(codeIdAttr.value, 10),
|
||||
logs: parsedLogs,
|
||||
logs: logs.parseRawLog(result.rawLog),
|
||||
height: result.height,
|
||||
transactionHash: result.transactionHash,
|
||||
events: result.events,
|
||||
@@ -327,11 +353,10 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
if (isDeliverTxFailure(result)) {
|
||||
throw new Error(createDeliverTxResponseErrorMessage(result));
|
||||
}
|
||||
const parsedLogs = logs.parseRawLog(result.rawLog);
|
||||
const contractAddressAttr = logs.findAttribute(parsedLogs, "instantiate", "_contract_address");
|
||||
const contractAddressAttr = findAttribute(result.events, "instantiate", "_contract_address");
|
||||
return {
|
||||
contractAddress: contractAddressAttr.value,
|
||||
logs: parsedLogs,
|
||||
logs: logs.parseRawLog(result.rawLog),
|
||||
height: result.height,
|
||||
transactionHash: result.transactionHash,
|
||||
events: result.events,
|
||||
@@ -366,11 +391,10 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
if (isDeliverTxFailure(result)) {
|
||||
throw new Error(createDeliverTxResponseErrorMessage(result));
|
||||
}
|
||||
const parsedLogs = logs.parseRawLog(result.rawLog);
|
||||
const contractAddressAttr = logs.findAttribute(parsedLogs, "instantiate", "_contract_address");
|
||||
const contractAddressAttr = findAttribute(result.events, "instantiate", "_contract_address");
|
||||
return {
|
||||
contractAddress: contractAddressAttr.value,
|
||||
logs: parsedLogs,
|
||||
logs: logs.parseRawLog(result.rawLog),
|
||||
height: result.height,
|
||||
transactionHash: result.transactionHash,
|
||||
events: result.events,
|
||||
@@ -593,9 +617,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
if (fee == "auto" || typeof fee === "number") {
|
||||
assertDefined(this.gasPrice, "Gas price must be set in the client options when auto gas is used.");
|
||||
const gasEstimation = await this.simulate(signerAddress, messages, memo);
|
||||
// Starting with Cosmos SDK 0.47, we see many cases in which 1.3 is not enough anymore
|
||||
// E.g. https://github.com/cosmos/cosmos-sdk/issues/16020
|
||||
const multiplier = typeof fee === "number" ? fee : 1.4;
|
||||
const multiplier = typeof fee === "number" ? fee : this.defaultGasMultiplier;
|
||||
usedFee = calculateFee(Math.round(gasEstimation * multiplier), this.gasPrice);
|
||||
} else {
|
||||
usedFee = fee;
|
||||
@@ -631,7 +653,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
if (fee == "auto" || typeof fee === "number") {
|
||||
assertDefined(this.gasPrice, "Gas price must be set in the client options when auto gas is used.");
|
||||
const gasEstimation = await this.simulate(signerAddress, messages, memo);
|
||||
const multiplier = typeof fee === "number" ? fee : 1.3;
|
||||
const multiplier = typeof fee === "number" ? fee : this.defaultGasMultiplier;
|
||||
usedFee = calculateFee(Math.round(gasEstimation * multiplier), this.gasPrice);
|
||||
} else {
|
||||
usedFee = fee;
|
||||
|
||||
@@ -101,18 +101,12 @@ export const unused = {
|
||||
};
|
||||
|
||||
export const validator = {
|
||||
/**
|
||||
* delegator_address from /cosmos.staking.v1beta1.MsgCreateValidator in scripts/wasmd/template/.wasmd/config/genesis.json
|
||||
*
|
||||
* `jq ".app_state.genutil.gen_txs[0].body.messages[0].delegator_address" scripts/wasmd/template/.wasmd/config/genesis.json`
|
||||
*/
|
||||
delegatorAddress: "wasm1g6kvj7w4c8g0vhl35kjgpe3jmuauet0e5tnevj",
|
||||
/**
|
||||
* validator_address from /cosmos.staking.v1beta1.MsgCreateValidator in scripts/wasmd/template/.wasmd/config/genesis.json
|
||||
*
|
||||
* `jq ".app_state.genutil.gen_txs[0].body.messages[0].validator_address" scripts/wasmd/template/.wasmd/config/genesis.json`
|
||||
*/
|
||||
validatorAddress: "wasmvaloper1g6kvj7w4c8g0vhl35kjgpe3jmuauet0ephx9zg",
|
||||
validatorAddress: "wasmvaloper1k2vfqeu2upskfv7awn29g5kvxxnmugkzy6rch0",
|
||||
accountNumber: 0,
|
||||
sequence: 1,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/crypto",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Cryptography resources for blockchain projects",
|
||||
"contributors": [
|
||||
"IOV SAS <admin@iov.one>",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/encoding",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Encoding helpers for blockchain projects",
|
||||
"contributors": [
|
||||
"IOV SAS <admin@iov.one>"
|
||||
|
||||
@@ -15,8 +15,9 @@ export function toUtf8(str: string): Uint8Array {
|
||||
/**
|
||||
* Takes UTF-8 data and decodes it to a string.
|
||||
*
|
||||
* In lossy mode, the replacement character � is used to substitude invalid
|
||||
* encodings. By default lossy mode is off and invalid data will lead to exceptions.
|
||||
* In lossy mode, the [REPLACEMENT CHARACTER](https://en.wikipedia.org/wiki/Specials_(Unicode_block))
|
||||
* is used to substitude invalid encodings.
|
||||
* By default lossy mode is off and invalid data will lead to exceptions.
|
||||
*/
|
||||
export function fromUtf8(data: Uint8Array, lossy = false): string {
|
||||
const fatal = !lossy;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/faucet-client",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "The faucet client",
|
||||
"contributors": [
|
||||
"Will Clark <willclarktech@users.noreply.github.com>"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/faucet",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "The faucet",
|
||||
"contributors": [
|
||||
"Ethan Frey <ethanfrey@users.noreply.github.com>",
|
||||
|
||||
@@ -83,9 +83,9 @@ export class Webserver {
|
||||
}
|
||||
|
||||
try {
|
||||
await faucet.credit(address, matchingDenom);
|
||||
// Count addresses to prevent draining
|
||||
this.addressCounter.set(address, new Date());
|
||||
await faucet.credit(address, matchingDenom);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new HttpError(500, "Sending tokens failed");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/json-rpc",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Framework for implementing a JSON-RPC 2.0 API",
|
||||
"contributors": [
|
||||
"IOV SAS <admin@iov.one>",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/ledger-amino",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "A library for signing Amino-encoded transactions using Ledger devices",
|
||||
"contributors": [
|
||||
"Will Clark <willclarktech@users.noreply.github.com>"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/math",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Math helpers for blockchain projects",
|
||||
"contributors": [
|
||||
"IOV SAS <admin@iov.one>"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/proto-signing",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Utilities for protobuf based signing (Cosmos SDK 0.40+)",
|
||||
"contributors": [
|
||||
"Will Clark <willclarktech@users.noreply.github.com>",
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
import { parseCoins } from "./coins";
|
||||
|
||||
describe("coins", () => {
|
||||
describe("parseCoins", () => {
|
||||
it("works for empty", () => {
|
||||
expect(parseCoins("")).toEqual([]);
|
||||
});
|
||||
|
||||
it("works for one element", () => {
|
||||
expect(parseCoins("7643ureef")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("works for various denoms", () => {
|
||||
// very short (3)
|
||||
expect(parseCoins("7643bar")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "bar",
|
||||
},
|
||||
]);
|
||||
|
||||
// very long (128)
|
||||
expect(
|
||||
parseCoins(
|
||||
"7643abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom:
|
||||
"abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
|
||||
},
|
||||
]);
|
||||
|
||||
// IBC denom (https://github.com/cosmos/cosmos-sdk/blob/v0.42.7/types/coin_test.go#L512-L519)
|
||||
expect(parseCoins("7643ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("trims leading zeros", () => {
|
||||
expect(parseCoins("07643ureef")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
expect(parseCoins("007643ureef")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
expect(parseCoins("0ureef")).toEqual([
|
||||
{
|
||||
amount: "0",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
expect(parseCoins("0000ureef")).toEqual([
|
||||
{
|
||||
amount: "0",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("works for large numbers", () => {
|
||||
expect(parseCoins(`${Number.MAX_SAFE_INTEGER}ureef`)).toEqual([
|
||||
{
|
||||
amount: "9007199254740991",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
// 2**64-1
|
||||
expect(parseCoins("18446744073709551615ureef")).toEqual([
|
||||
{
|
||||
amount: "18446744073709551615",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
// 2**128-1
|
||||
expect(parseCoins("340282366920938463463374607431768211455ureef")).toEqual([
|
||||
{
|
||||
amount: "340282366920938463463374607431768211455",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("works for two", () => {
|
||||
expect(parseCoins("819966000ucosm,700000000ustake")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("ignores empty elements", () => {
|
||||
// start
|
||||
expect(parseCoins(",819966000ucosm,700000000ustake")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
},
|
||||
]);
|
||||
// middle
|
||||
expect(parseCoins("819966000ucosm,,700000000ustake")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
},
|
||||
]);
|
||||
// end
|
||||
expect(parseCoins("819966000ucosm,700000000ustake,")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("throws for invalid inputs", () => {
|
||||
// denom missing
|
||||
expect(() => parseCoins("3456")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// amount missing
|
||||
expect(() => parseCoins("ucosm")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom starting with slash
|
||||
expect(() => parseCoins("3456/ibc")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom too short
|
||||
expect(() => parseCoins("3456a")).toThrowError(/invalid coin string/i);
|
||||
expect(() => parseCoins("3456aa")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom too long
|
||||
expect(() =>
|
||||
parseCoins(
|
||||
"3456abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgha",
|
||||
),
|
||||
).toThrowError(/invalid coin string/i);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,23 +0,0 @@
|
||||
import { Coin } from "@cosmjs/amino";
|
||||
|
||||
/**
|
||||
* Takes a coins list like "819966000ucosm,700000000ustake" and parses it.
|
||||
*
|
||||
* This is a Stargate ready version of parseCoins from @cosmjs/amino.
|
||||
* It supports more denoms.
|
||||
*/
|
||||
export function parseCoins(input: string): Coin[] {
|
||||
return input
|
||||
.replace(/\s/g, "")
|
||||
.split(",")
|
||||
.filter(Boolean)
|
||||
.map((part) => {
|
||||
// Denom regex from Stargate (https://github.com/cosmos/cosmos-sdk/blob/v0.42.7/types/coin.go#L599-L601)
|
||||
const match = part.match(/^([0-9]+)([a-zA-Z][a-zA-Z0-9/]{2,127})$/);
|
||||
if (!match) throw new Error("Got an invalid coin string");
|
||||
return {
|
||||
amount: match[1].replace(/^0+/, "") || "0",
|
||||
denom: match[2],
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
// This type happens to be shared between Amino and Direct sign modes
|
||||
export { parseCoins } from "./coins";
|
||||
export { DecodedTxRaw, decodeTxRaw } from "./decode";
|
||||
export {
|
||||
DirectSecp256k1HdWallet,
|
||||
@@ -31,4 +30,6 @@ export {
|
||||
} from "./signer";
|
||||
export { makeAuthInfoBytes, makeSignBytes, makeSignDoc } from "./signing";
|
||||
export { executeKdf, KdfConfiguration } from "./wallet";
|
||||
export { Coin, coin, coins } from "@cosmjs/amino";
|
||||
|
||||
// re-exports
|
||||
export { Coin, coin, coins, parseCoins } from "@cosmjs/amino";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/socket",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Utility functions for working with WebSockets",
|
||||
"contributors": [
|
||||
"IOV SAS <admin@iov.one>",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/stargate",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Utilities for Cosmos SDK 0.40",
|
||||
"contributors": [
|
||||
"Simon Warta <webmaster128@users.noreply.github.com>"
|
||||
|
||||
@@ -54,7 +54,10 @@ export function parseLogs(input: unknown): readonly Log[] {
|
||||
return input.map(parseLog);
|
||||
}
|
||||
|
||||
export function parseRawLog(input = "[]"): readonly Log[] {
|
||||
export function parseRawLog(input: string | undefined): readonly Log[] {
|
||||
// Cosmos SDK >= 0.50 gives us an empty string here. This should be handled like undefined.
|
||||
if (!input) return [];
|
||||
|
||||
const logsToParse = JSON.parse(input).map(({ events }: { events: readonly unknown[] }, i: number) => ({
|
||||
msg_index: i,
|
||||
events,
|
||||
|
||||
@@ -148,7 +148,7 @@ describe("gov messages", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with Amino JSON sign mode", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutSimapp();
|
||||
assert(voterWalletAmino);
|
||||
assert(proposalId, "Missing proposal ID");
|
||||
@@ -206,7 +206,7 @@ describe("gov messages", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with Amino JSON sign mode", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutSimapp();
|
||||
if (simapp50Enabled()) pending("Not working, see https://github.com/cosmos/cosmos-sdk/issues/18546");
|
||||
assert(voterWalletAmino);
|
||||
|
||||
@@ -94,7 +94,7 @@ describe("staking messages", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with Amino JSON sign mode", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutSimapp();
|
||||
if (simapp50Enabled()) pending("Not working, see https://github.com/cosmos/cosmos-sdk/issues/18546");
|
||||
|
||||
@@ -235,7 +235,7 @@ describe("staking messages", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with Amino JSON sign mode", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutSimapp();
|
||||
if (simapp50Enabled()) pending("Not working, see https://github.com/cosmos/cosmos-sdk/issues/18546");
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ describe("vesting messages", () => {
|
||||
client.disconnect();
|
||||
});
|
||||
|
||||
it("works with Amino JSON sign mode", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutSimapp46OrHigher(); // Amino JSON broken on chain before Cosmos SDK 0.46
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||
const client = await SigningStargateClient.connectWithSigner(
|
||||
|
||||
@@ -126,13 +126,14 @@ describe("SigningStargateClient", () => {
|
||||
} else {
|
||||
expect(result.rawLog).toBeTruthy();
|
||||
}
|
||||
expect(result.events.length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// got tokens
|
||||
const after = await client.getBalance(beneficiaryAddress, "ucosm");
|
||||
expect(after).toEqual(amount[0]);
|
||||
});
|
||||
|
||||
it("works with legacy Amino signer", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pendingWithoutSimapp();
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||
const client = await SigningStargateClient.connectWithSigner(
|
||||
@@ -167,6 +168,7 @@ describe("SigningStargateClient", () => {
|
||||
} else {
|
||||
expect(result.rawLog).toBeTruthy();
|
||||
}
|
||||
expect(result.events.length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// got tokens
|
||||
const after = await client.getBalance(beneficiaryAddress, "ucosm");
|
||||
@@ -299,7 +301,7 @@ describe("SigningStargateClient", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("works with Amino signing", async () => {
|
||||
it("works with Amino JSON signer", async () => {
|
||||
pending("We cannot test this easily anymore since the IBC module was removed from simapp");
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||
const client = await SigningStargateClient.connectWithSigner(
|
||||
|
||||
@@ -110,6 +110,9 @@ export class SigningStargateClient extends StargateClient {
|
||||
private readonly signer: OfflineSigner;
|
||||
private readonly aminoTypes: AminoTypes;
|
||||
private readonly gasPrice: GasPrice | undefined;
|
||||
// Starting with Cosmos SDK 0.47, we see many cases in which 1.3 is not enough anymore
|
||||
// E.g. https://github.com/cosmos/cosmos-sdk/issues/16020
|
||||
private readonly defaultGasMultiplier = 1.4;
|
||||
|
||||
/**
|
||||
* Creates an instance by connecting to the given CometBFT RPC endpoint.
|
||||
@@ -308,9 +311,7 @@ export class SigningStargateClient extends StargateClient {
|
||||
if (fee == "auto" || typeof fee === "number") {
|
||||
assertDefined(this.gasPrice, "Gas price must be set in the client options when auto gas is used.");
|
||||
const gasEstimation = await this.simulate(signerAddress, messages, memo);
|
||||
// Starting with Cosmos SDK 0.47, we see many cases in which 1.3 is not enough anymore
|
||||
// E.g. https://github.com/cosmos/cosmos-sdk/issues/16020
|
||||
const multiplier = typeof fee === "number" ? fee : 1.4;
|
||||
const multiplier = typeof fee === "number" ? fee : this.defaultGasMultiplier;
|
||||
usedFee = calculateFee(Math.round(gasEstimation * multiplier), this.gasPrice);
|
||||
} else {
|
||||
usedFee = fee;
|
||||
@@ -337,7 +338,7 @@ export class SigningStargateClient extends StargateClient {
|
||||
if (fee == "auto" || typeof fee === "number") {
|
||||
assertDefined(this.gasPrice, "Gas price must be set in the client options when auto gas is used.");
|
||||
const gasEstimation = await this.simulate(signerAddress, messages, memo);
|
||||
const multiplier = typeof fee === "number" ? fee : 1.3;
|
||||
const multiplier = typeof fee === "number" ? fee : this.defaultGasMultiplier;
|
||||
usedFee = calculateFee(Math.round(gasEstimation * multiplier), this.gasPrice);
|
||||
} else {
|
||||
usedFee = fee;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/stream",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Utility functions for producing and consuming streams",
|
||||
"contributors": [
|
||||
"IOV SAS <admin@iov.one>",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/tendermint-rpc",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Tendermint RPC clients",
|
||||
"contributors": [
|
||||
"IOV SAS <admin@iov.one>",
|
||||
|
||||
@@ -599,7 +599,7 @@ function decodeNodeInfo(data: RpcNodeInfo): responses.NodeInfo {
|
||||
listenAddr: assertNotEmpty(data.listen_addr),
|
||||
network: assertNotEmpty(data.network),
|
||||
version: assertString(data.version), // Can be empty (https://github.com/cosmos/cosmos-sdk/issues/7963)
|
||||
channels: assertNotEmpty(data.channels),
|
||||
channels: assertString(data.channels), // can be empty
|
||||
moniker: assertNotEmpty(data.moniker),
|
||||
other: dictionaryToStringMap(data.other),
|
||||
protocolVersion: {
|
||||
|
||||
@@ -597,7 +597,7 @@ function decodeNodeInfo(data: RpcNodeInfo): responses.NodeInfo {
|
||||
listenAddr: assertNotEmpty(data.listen_addr),
|
||||
network: assertNotEmpty(data.network),
|
||||
version: assertString(data.version), // Can be empty (https://github.com/cosmos/cosmos-sdk/issues/7963)
|
||||
channels: assertNotEmpty(data.channels),
|
||||
channels: assertString(data.channels), // can be empty
|
||||
moniker: assertNotEmpty(data.moniker),
|
||||
other: dictionaryToStringMap(data.other),
|
||||
protocolVersion: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cosmjs/utils",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"description": "Utility tools, primarily for testing code",
|
||||
"contributors": [
|
||||
"IOV SAS <admin@iov.one>"
|
||||
|
||||
Reference in New Issue
Block a user