mirror of
https://github.com/cosmos/cosmjs.git
synced 2025-03-11 14:09:15 +00:00
Merge pull request #615 from cosmos/594-amino-signing-cosmwasm
Implement Amino signing for bank/staking/wasm in cosmwasm-stargate
This commit is contained in:
commit
9651c5e3a5
@ -49,6 +49,14 @@
|
|||||||
- @cosmjs/tendermint-rpc: Remove types `BlockHash`, `TxBytes` and `TxHash`. Use
|
- @cosmjs/tendermint-rpc: Remove types `BlockHash`, `TxBytes` and `TxHash`. Use
|
||||||
`Uint8Array` instead.
|
`Uint8Array` instead.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- @cosmjs/utils: Added `assertDefinedAndNotNull`.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- @cosmjs/utils: `assertDefined` removed in favour of `assertDefinedAndNotNull`.
|
||||||
|
|
||||||
## 0.23.2 (2021-01-06)
|
## 0.23.2 (2021-01-06)
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
337
packages/cosmwasm-stargate/src/aminotypes.spec.ts
Normal file
337
packages/cosmwasm-stargate/src/aminotypes.spec.ts
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
import {
|
||||||
|
MsgClearAdmin,
|
||||||
|
MsgExecuteContract,
|
||||||
|
MsgInstantiateContract,
|
||||||
|
MsgMigrateContract,
|
||||||
|
MsgStoreCode,
|
||||||
|
MsgUpdateAdmin,
|
||||||
|
} from "@cosmjs/cosmwasm-launchpad";
|
||||||
|
import { fromBase64, toUtf8 } from "@cosmjs/encoding";
|
||||||
|
import { coins } from "@cosmjs/launchpad";
|
||||||
|
import { AminoTypes } from "@cosmjs/stargate";
|
||||||
|
import Long from "long";
|
||||||
|
|
||||||
|
import { cosmWasmTypes } from "./aminotypes";
|
||||||
|
import { cosmwasm } from "./codec";
|
||||||
|
|
||||||
|
type IMsgStoreCode = cosmwasm.wasm.v1beta1.IMsgStoreCode;
|
||||||
|
type IMsgInstantiateContract = cosmwasm.wasm.v1beta1.IMsgInstantiateContract;
|
||||||
|
type IMsgUpdateAdmin = cosmwasm.wasm.v1beta1.IMsgUpdateAdmin;
|
||||||
|
type IMsgClearAdmin = cosmwasm.wasm.v1beta1.IMsgClearAdmin;
|
||||||
|
type IMsgExecuteContract = cosmwasm.wasm.v1beta1.IMsgExecuteContract;
|
||||||
|
type IMsgMigrateContract = cosmwasm.wasm.v1beta1.IMsgMigrateContract;
|
||||||
|
|
||||||
|
describe("AminoTypes", () => {
|
||||||
|
describe("toAmino", () => {
|
||||||
|
it("works for MsgStoreCode", () => {
|
||||||
|
const msg: IMsgStoreCode = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
wasmByteCode: fromBase64("WUVMTE9XIFNVQk1BUklORQ=="),
|
||||||
|
source: "Arrabiata",
|
||||||
|
builder: "Bob",
|
||||||
|
};
|
||||||
|
const aminoMsg = new AminoTypes({ additions: cosmWasmTypes }).toAmino({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgStoreCode",
|
||||||
|
value: msg,
|
||||||
|
});
|
||||||
|
const expected: MsgStoreCode = {
|
||||||
|
type: "wasm/MsgStoreCode",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
wasm_byte_code: "WUVMTE9XIFNVQk1BUklORQ==",
|
||||||
|
source: "Arrabiata",
|
||||||
|
builder: "Bob",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(aminoMsg).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for MsgInstantiateContract", () => {
|
||||||
|
const msg: IMsgInstantiateContract = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
codeId: Long.fromString("12345"),
|
||||||
|
label: "sticky",
|
||||||
|
initMsg: toUtf8(
|
||||||
|
JSON.stringify({
|
||||||
|
foo: "bar",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
initFunds: coins(1234, "ucosm"),
|
||||||
|
admin: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5",
|
||||||
|
};
|
||||||
|
const aminoMsg = new AminoTypes({ additions: cosmWasmTypes }).toAmino({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgInstantiateContract",
|
||||||
|
value: msg,
|
||||||
|
});
|
||||||
|
const expected: MsgInstantiateContract = {
|
||||||
|
type: "wasm/MsgInstantiateContract",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
code_id: "12345",
|
||||||
|
label: "sticky",
|
||||||
|
init_msg: {
|
||||||
|
foo: "bar",
|
||||||
|
},
|
||||||
|
init_funds: coins(1234, "ucosm"),
|
||||||
|
admin: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(aminoMsg).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for MsgUpdateAdmin", () => {
|
||||||
|
const msg: IMsgUpdateAdmin = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
newAdmin: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
};
|
||||||
|
const aminoMsg = new AminoTypes({ additions: cosmWasmTypes }).toAmino({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgUpdateAdmin",
|
||||||
|
value: msg,
|
||||||
|
});
|
||||||
|
const expected: MsgUpdateAdmin = {
|
||||||
|
type: "wasm/MsgUpdateAdmin",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
new_admin: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(aminoMsg).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for MsgClearAdmin", () => {
|
||||||
|
const msg: IMsgClearAdmin = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
};
|
||||||
|
const aminoMsg = new AminoTypes({ additions: cosmWasmTypes }).toAmino({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgClearAdmin",
|
||||||
|
value: msg,
|
||||||
|
});
|
||||||
|
const expected: MsgClearAdmin = {
|
||||||
|
type: "wasm/MsgClearAdmin",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(aminoMsg).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for MsgExecuteContract", () => {
|
||||||
|
const msg: IMsgExecuteContract = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
msg: toUtf8(
|
||||||
|
JSON.stringify({
|
||||||
|
foo: "bar",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
sentFunds: coins(1234, "ucosm"),
|
||||||
|
};
|
||||||
|
const aminoMsg = new AminoTypes({ additions: cosmWasmTypes }).toAmino({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgExecuteContract",
|
||||||
|
value: msg,
|
||||||
|
});
|
||||||
|
const expected: MsgExecuteContract = {
|
||||||
|
type: "wasm/MsgExecuteContract",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
msg: {
|
||||||
|
foo: "bar",
|
||||||
|
},
|
||||||
|
sent_funds: coins(1234, "ucosm"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(aminoMsg).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for MsgMigrateContract", () => {
|
||||||
|
const msg: IMsgMigrateContract = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
codeId: Long.fromString("98765"),
|
||||||
|
migrateMsg: toUtf8(
|
||||||
|
JSON.stringify({
|
||||||
|
foo: "bar",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
const aminoMsg = new AminoTypes({ additions: cosmWasmTypes }).toAmino({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgMigrateContract",
|
||||||
|
value: msg,
|
||||||
|
});
|
||||||
|
const expected: MsgMigrateContract = {
|
||||||
|
type: "wasm/MsgMigrateContract",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
code_id: "98765",
|
||||||
|
msg: {
|
||||||
|
foo: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(aminoMsg).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("fromAmino", () => {
|
||||||
|
it("works for MsgStoreCode", () => {
|
||||||
|
const aminoMsg: MsgStoreCode = {
|
||||||
|
type: "wasm/MsgStoreCode",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
wasm_byte_code: "WUVMTE9XIFNVQk1BUklORQ==",
|
||||||
|
source: "Arrabiata",
|
||||||
|
builder: "Bob",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const msg = new AminoTypes({ additions: cosmWasmTypes }).fromAmino(aminoMsg);
|
||||||
|
const expectedValue: IMsgStoreCode = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
wasmByteCode: fromBase64("WUVMTE9XIFNVQk1BUklORQ=="),
|
||||||
|
source: "Arrabiata",
|
||||||
|
builder: "Bob",
|
||||||
|
};
|
||||||
|
expect(msg).toEqual({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgStoreCode",
|
||||||
|
value: expectedValue,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for MsgInstantiateContract", () => {
|
||||||
|
const aminoMsg: MsgInstantiateContract = {
|
||||||
|
type: "wasm/MsgInstantiateContract",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
code_id: "12345",
|
||||||
|
label: "sticky",
|
||||||
|
init_msg: {
|
||||||
|
foo: "bar",
|
||||||
|
},
|
||||||
|
init_funds: coins(1234, "ucosm"),
|
||||||
|
admin: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const msg = new AminoTypes({ additions: cosmWasmTypes }).fromAmino(aminoMsg);
|
||||||
|
const expectedValue: IMsgInstantiateContract = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
codeId: Long.fromString("12345"),
|
||||||
|
label: "sticky",
|
||||||
|
initMsg: toUtf8(
|
||||||
|
JSON.stringify({
|
||||||
|
foo: "bar",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
initFunds: coins(1234, "ucosm"),
|
||||||
|
admin: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5",
|
||||||
|
};
|
||||||
|
expect(msg).toEqual({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgInstantiateContract",
|
||||||
|
value: expectedValue,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for MsgUpdateAdmin", () => {
|
||||||
|
const aminoMsg: MsgUpdateAdmin = {
|
||||||
|
type: "wasm/MsgUpdateAdmin",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
new_admin: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const msg = new AminoTypes({ additions: cosmWasmTypes }).fromAmino(aminoMsg);
|
||||||
|
const expectedValue: IMsgUpdateAdmin = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
newAdmin: "cosmos10dyr9899g6t0pelew4nvf4j5c3jcgv0r73qga5",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
};
|
||||||
|
expect(msg).toEqual({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgUpdateAdmin",
|
||||||
|
value: expectedValue,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for MsgClearAdmin", () => {
|
||||||
|
const aminoMsg: MsgClearAdmin = {
|
||||||
|
type: "wasm/MsgClearAdmin",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const msg = new AminoTypes({ additions: cosmWasmTypes }).fromAmino(aminoMsg);
|
||||||
|
const expectedValue: IMsgClearAdmin = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
};
|
||||||
|
expect(msg).toEqual({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgClearAdmin",
|
||||||
|
value: expectedValue,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for MsgExecuteContract", () => {
|
||||||
|
const aminoMsg: MsgExecuteContract = {
|
||||||
|
type: "wasm/MsgExecuteContract",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
msg: {
|
||||||
|
foo: "bar",
|
||||||
|
},
|
||||||
|
sent_funds: coins(1234, "ucosm"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const msg = new AminoTypes({ additions: cosmWasmTypes }).fromAmino(aminoMsg);
|
||||||
|
const expectedValue: IMsgExecuteContract = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
msg: toUtf8(
|
||||||
|
JSON.stringify({
|
||||||
|
foo: "bar",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
sentFunds: coins(1234, "ucosm"),
|
||||||
|
};
|
||||||
|
expect(msg).toEqual({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgExecuteContract",
|
||||||
|
value: expectedValue,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works for MsgMigrateContract", () => {
|
||||||
|
const aminoMsg: MsgMigrateContract = {
|
||||||
|
type: "wasm/MsgMigrateContract",
|
||||||
|
value: {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
code_id: "98765",
|
||||||
|
msg: {
|
||||||
|
foo: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const msg = new AminoTypes({ additions: cosmWasmTypes }).fromAmino(aminoMsg);
|
||||||
|
const expectedValue: IMsgMigrateContract = {
|
||||||
|
sender: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
|
||||||
|
contract: "cosmos1xy4yqngt0nlkdcenxymg8tenrghmek4nmqm28k",
|
||||||
|
codeId: Long.fromString("98765"),
|
||||||
|
migrateMsg: toUtf8(
|
||||||
|
JSON.stringify({
|
||||||
|
foo: "bar",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
expect(msg).toEqual({
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgMigrateContract",
|
||||||
|
value: expectedValue,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
161
packages/cosmwasm-stargate/src/aminotypes.ts
Normal file
161
packages/cosmwasm-stargate/src/aminotypes.ts
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
import {
|
||||||
|
MsgClearAdmin,
|
||||||
|
MsgExecuteContract,
|
||||||
|
MsgInstantiateContract,
|
||||||
|
MsgMigrateContract,
|
||||||
|
MsgStoreCode,
|
||||||
|
MsgUpdateAdmin,
|
||||||
|
} from "@cosmjs/cosmwasm-launchpad";
|
||||||
|
import { fromBase64, fromUtf8, toBase64, toUtf8 } from "@cosmjs/encoding";
|
||||||
|
import { AminoConverter, coinFromProto } from "@cosmjs/stargate";
|
||||||
|
import { assertDefinedAndNotNull } from "@cosmjs/utils";
|
||||||
|
import Long from "long";
|
||||||
|
|
||||||
|
import { cosmwasm } from "./codec";
|
||||||
|
|
||||||
|
type IMsgStoreCode = cosmwasm.wasm.v1beta1.IMsgStoreCode;
|
||||||
|
type IMsgInstantiateContract = cosmwasm.wasm.v1beta1.IMsgInstantiateContract;
|
||||||
|
type IMsgUpdateAdmin = cosmwasm.wasm.v1beta1.IMsgUpdateAdmin;
|
||||||
|
type IMsgClearAdmin = cosmwasm.wasm.v1beta1.IMsgClearAdmin;
|
||||||
|
type IMsgExecuteContract = cosmwasm.wasm.v1beta1.IMsgExecuteContract;
|
||||||
|
type IMsgMigrateContract = cosmwasm.wasm.v1beta1.IMsgMigrateContract;
|
||||||
|
|
||||||
|
export const cosmWasmTypes: Record<string, AminoConverter> = {
|
||||||
|
"/cosmwasm.wasm.v1beta1.MsgStoreCode": {
|
||||||
|
aminoType: "wasm/MsgStoreCode",
|
||||||
|
toAmino: ({ sender, wasmByteCode, source, builder }: IMsgStoreCode): MsgStoreCode["value"] => {
|
||||||
|
assertDefinedAndNotNull(sender, "missing sender");
|
||||||
|
assertDefinedAndNotNull(wasmByteCode, "missing wasmByteCode");
|
||||||
|
assertDefinedAndNotNull(source, "missing source");
|
||||||
|
assertDefinedAndNotNull(builder, "missing builder");
|
||||||
|
return {
|
||||||
|
sender: sender,
|
||||||
|
wasm_byte_code: toBase64(wasmByteCode),
|
||||||
|
source: source,
|
||||||
|
builder: builder,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
fromAmino: ({ sender, wasm_byte_code, source, builder }: MsgStoreCode["value"]): IMsgStoreCode => ({
|
||||||
|
sender: sender,
|
||||||
|
wasmByteCode: fromBase64(wasm_byte_code),
|
||||||
|
source: source,
|
||||||
|
builder: builder,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
"/cosmwasm.wasm.v1beta1.MsgInstantiateContract": {
|
||||||
|
aminoType: "wasm/MsgInstantiateContract",
|
||||||
|
toAmino: ({
|
||||||
|
sender,
|
||||||
|
codeId,
|
||||||
|
label,
|
||||||
|
initMsg,
|
||||||
|
initFunds,
|
||||||
|
admin,
|
||||||
|
}: IMsgInstantiateContract): MsgInstantiateContract["value"] => {
|
||||||
|
assertDefinedAndNotNull(sender, "missing sender");
|
||||||
|
assertDefinedAndNotNull(codeId, "missing codeId");
|
||||||
|
assertDefinedAndNotNull(label, "missing label");
|
||||||
|
assertDefinedAndNotNull(initMsg, "missing initMsg");
|
||||||
|
assertDefinedAndNotNull(initFunds, "missing initFunds");
|
||||||
|
return {
|
||||||
|
sender: sender,
|
||||||
|
code_id: codeId.toString(),
|
||||||
|
label: label,
|
||||||
|
init_msg: JSON.parse(fromUtf8(initMsg)),
|
||||||
|
init_funds: initFunds.map(coinFromProto),
|
||||||
|
admin: admin ?? undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
fromAmino: ({
|
||||||
|
sender,
|
||||||
|
code_id,
|
||||||
|
label,
|
||||||
|
init_msg,
|
||||||
|
init_funds,
|
||||||
|
admin,
|
||||||
|
}: MsgInstantiateContract["value"]): IMsgInstantiateContract => ({
|
||||||
|
sender: sender,
|
||||||
|
codeId: Long.fromString(code_id),
|
||||||
|
label: label,
|
||||||
|
initMsg: toUtf8(JSON.stringify(init_msg)),
|
||||||
|
initFunds: [...init_funds],
|
||||||
|
admin: admin,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
"/cosmwasm.wasm.v1beta1.MsgUpdateAdmin": {
|
||||||
|
aminoType: "wasm/MsgUpdateAdmin",
|
||||||
|
toAmino: ({ sender, newAdmin, contract }: IMsgUpdateAdmin): MsgUpdateAdmin["value"] => {
|
||||||
|
assertDefinedAndNotNull(sender, "missing sender");
|
||||||
|
assertDefinedAndNotNull(newAdmin, "missing newAdmin");
|
||||||
|
assertDefinedAndNotNull(contract, "missing contract");
|
||||||
|
return {
|
||||||
|
sender: sender,
|
||||||
|
new_admin: newAdmin,
|
||||||
|
contract: contract,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
fromAmino: ({ sender, new_admin, contract }: MsgUpdateAdmin["value"]): IMsgUpdateAdmin => ({
|
||||||
|
sender: sender,
|
||||||
|
newAdmin: new_admin,
|
||||||
|
contract: contract,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
"/cosmwasm.wasm.v1beta1.MsgClearAdmin": {
|
||||||
|
aminoType: "wasm/MsgClearAdmin",
|
||||||
|
toAmino: ({ sender, contract }: IMsgClearAdmin): MsgClearAdmin["value"] => {
|
||||||
|
assertDefinedAndNotNull(sender, "missing sender");
|
||||||
|
assertDefinedAndNotNull(contract, "missing contract");
|
||||||
|
return {
|
||||||
|
sender: sender,
|
||||||
|
contract: contract,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
fromAmino: ({ sender, contract }: MsgClearAdmin["value"]): IMsgClearAdmin => ({
|
||||||
|
sender: sender,
|
||||||
|
contract: contract,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
"/cosmwasm.wasm.v1beta1.MsgExecuteContract": {
|
||||||
|
aminoType: "wasm/MsgExecuteContract",
|
||||||
|
toAmino: ({ sender, contract, msg, sentFunds }: IMsgExecuteContract): MsgExecuteContract["value"] => {
|
||||||
|
assertDefinedAndNotNull(sender, "missing sender");
|
||||||
|
assertDefinedAndNotNull(contract, "missing contract");
|
||||||
|
assertDefinedAndNotNull(msg, "missing msg");
|
||||||
|
assertDefinedAndNotNull(sentFunds, "missing sentFunds");
|
||||||
|
return {
|
||||||
|
sender: sender,
|
||||||
|
contract: contract,
|
||||||
|
msg: JSON.parse(fromUtf8(msg)),
|
||||||
|
sent_funds: sentFunds.map(coinFromProto),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
fromAmino: ({ sender, contract, msg, sent_funds }: MsgExecuteContract["value"]): IMsgExecuteContract => ({
|
||||||
|
sender: sender,
|
||||||
|
contract: contract,
|
||||||
|
msg: toUtf8(JSON.stringify(msg)),
|
||||||
|
sentFunds: [...sent_funds],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
"/cosmwasm.wasm.v1beta1.MsgMigrateContract": {
|
||||||
|
aminoType: "wasm/MsgMigrateContract",
|
||||||
|
toAmino: ({ sender, contract, codeId, migrateMsg }: IMsgMigrateContract): MsgMigrateContract["value"] => {
|
||||||
|
assertDefinedAndNotNull(sender, "missing sender");
|
||||||
|
assertDefinedAndNotNull(contract, "missing contract");
|
||||||
|
assertDefinedAndNotNull(codeId, "missing codeId");
|
||||||
|
assertDefinedAndNotNull(migrateMsg, "missing migrateMsg");
|
||||||
|
return {
|
||||||
|
sender: sender,
|
||||||
|
contract: contract,
|
||||||
|
code_id: codeId.toString(),
|
||||||
|
msg: JSON.parse(fromUtf8(migrateMsg)),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
fromAmino: ({ sender, contract, code_id, msg }: MsgMigrateContract["value"]): IMsgMigrateContract => ({
|
||||||
|
sender: sender,
|
||||||
|
contract: contract,
|
||||||
|
codeId: Long.fromString(code_id),
|
||||||
|
migrateMsg: toUtf8(JSON.stringify(msg)),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
@ -9,7 +9,7 @@ import {
|
|||||||
parseRawLog,
|
parseRawLog,
|
||||||
SigningStargateClient,
|
SigningStargateClient,
|
||||||
} from "@cosmjs/stargate";
|
} from "@cosmjs/stargate";
|
||||||
import { assert, assertDefined } from "@cosmjs/utils";
|
import { assert, assertDefinedAndNotNull } from "@cosmjs/utils";
|
||||||
import Long from "long";
|
import Long from "long";
|
||||||
|
|
||||||
import { cosmwasm } from "../codec";
|
import { cosmwasm } from "../codec";
|
||||||
@ -395,7 +395,7 @@ describe("WasmExtension", () => {
|
|||||||
expect(codeId).toBeGreaterThanOrEqual(1);
|
expect(codeId).toBeGreaterThanOrEqual(1);
|
||||||
expect(codeId).toBeLessThanOrEqual(200);
|
expect(codeId).toBeLessThanOrEqual(200);
|
||||||
|
|
||||||
assertDefined(result.data);
|
assertDefinedAndNotNull(result.data);
|
||||||
const msgData = fromOneElementArray(result.data);
|
const msgData = fromOneElementArray(result.data);
|
||||||
expect(msgData.msgType).toEqual("store-code");
|
expect(msgData.msgType).toEqual("store-code");
|
||||||
expect(MsgStoreCodeResponse.decode(msgData.data!)).toEqual(
|
expect(MsgStoreCodeResponse.decode(msgData.data!)).toEqual(
|
||||||
@ -415,7 +415,7 @@ describe("WasmExtension", () => {
|
|||||||
const amountAttr = logs.findAttribute(parsedLogs, "transfer", "amount");
|
const amountAttr = logs.findAttribute(parsedLogs, "transfer", "amount");
|
||||||
expect(amountAttr.value).toEqual("1234ucosm,321ustake");
|
expect(amountAttr.value).toEqual("1234ucosm,321ustake");
|
||||||
|
|
||||||
assertDefined(result.data);
|
assertDefinedAndNotNull(result.data);
|
||||||
const msgData = fromOneElementArray(result.data);
|
const msgData = fromOneElementArray(result.data);
|
||||||
expect(msgData.msgType).toEqual("instantiate");
|
expect(msgData.msgType).toEqual("instantiate");
|
||||||
expect(MsgInstantiateContractResponse.decode(msgData.data!)).toEqual(
|
expect(MsgInstantiateContractResponse.decode(msgData.data!)).toEqual(
|
||||||
@ -441,7 +441,7 @@ describe("WasmExtension", () => {
|
|||||||
value: beneficiaryAddress,
|
value: beneficiaryAddress,
|
||||||
});
|
});
|
||||||
|
|
||||||
assertDefined(result.data);
|
assertDefinedAndNotNull(result.data);
|
||||||
const msgData = fromOneElementArray(result.data);
|
const msgData = fromOneElementArray(result.data);
|
||||||
expect(msgData.msgType).toEqual("execute");
|
expect(msgData.msgType).toEqual("execute");
|
||||||
expect(MsgExecuteContractResponse.decode(msgData.data!)).toEqual(
|
expect(MsgExecuteContractResponse.decode(msgData.data!)).toEqual(
|
||||||
|
@ -2,12 +2,21 @@
|
|||||||
import { UploadMeta } from "@cosmjs/cosmwasm-launchpad";
|
import { UploadMeta } from "@cosmjs/cosmwasm-launchpad";
|
||||||
import { sha256 } from "@cosmjs/crypto";
|
import { sha256 } from "@cosmjs/crypto";
|
||||||
import { toHex } from "@cosmjs/encoding";
|
import { toHex } from "@cosmjs/encoding";
|
||||||
import { coin, coins, GasPrice } from "@cosmjs/launchpad";
|
import {
|
||||||
import { DirectSecp256k1HdWallet, Registry } from "@cosmjs/proto-signing";
|
coin,
|
||||||
import { assertIsBroadcastTxSuccess, codec } from "@cosmjs/stargate";
|
coins,
|
||||||
|
GasPrice,
|
||||||
|
MsgDelegate as LaunchpadMsgDelegate,
|
||||||
|
Secp256k1HdWallet,
|
||||||
|
} from "@cosmjs/launchpad";
|
||||||
|
import { Coin, cosmosField, DirectSecp256k1HdWallet, registered, Registry } from "@cosmjs/proto-signing";
|
||||||
|
import { AminoTypes, assertIsBroadcastTxSuccess, codec } from "@cosmjs/stargate";
|
||||||
import { assert, sleep } from "@cosmjs/utils";
|
import { assert, sleep } from "@cosmjs/utils";
|
||||||
import Long from "long";
|
import Long from "long";
|
||||||
|
import pako from "pako";
|
||||||
|
import { Message } from "protobufjs";
|
||||||
|
|
||||||
|
import { cosmwasm } from "./codec";
|
||||||
import { PrivateSigningCosmWasmClient, SigningCosmWasmClient } from "./signingcosmwasmclient";
|
import { PrivateSigningCosmWasmClient, SigningCosmWasmClient } from "./signingcosmwasmclient";
|
||||||
import {
|
import {
|
||||||
alice,
|
alice,
|
||||||
@ -15,12 +24,18 @@ import {
|
|||||||
makeRandomAddress,
|
makeRandomAddress,
|
||||||
makeWasmClient,
|
makeWasmClient,
|
||||||
ModifyingDirectSecp256k1HdWallet,
|
ModifyingDirectSecp256k1HdWallet,
|
||||||
|
ModifyingSecp256k1HdWallet,
|
||||||
pendingWithoutWasmd,
|
pendingWithoutWasmd,
|
||||||
unused,
|
unused,
|
||||||
validator,
|
validator,
|
||||||
wasmd,
|
wasmd,
|
||||||
} from "./testutils.spec";
|
} from "./testutils.spec";
|
||||||
|
|
||||||
|
type IMsgSend = codec.cosmos.bank.v1beta1.IMsgSend;
|
||||||
|
type IMsgDelegate = codec.cosmos.staking.v1beta1.IMsgDelegate;
|
||||||
|
type IMsgStoreCode = cosmwasm.wasm.v1beta1.IMsgStoreCode;
|
||||||
|
|
||||||
|
const { MsgSend } = codec.cosmos.bank.v1beta1;
|
||||||
const { MsgDelegate } = codec.cosmos.staking.v1beta1;
|
const { MsgDelegate } = codec.cosmos.staking.v1beta1;
|
||||||
const { Tx } = codec.cosmos.tx.v1beta1;
|
const { Tx } = codec.cosmos.tx.v1beta1;
|
||||||
|
|
||||||
@ -29,15 +44,30 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("can be constructed", async () => {
|
it("can be constructed", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
const options = { prefix: wasmd.prefix };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
expect(client).toBeTruthy();
|
expect(client).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("can be constructed with custom registry", async () => {
|
||||||
|
pendingWithoutWasmd();
|
||||||
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.register("/custom.MsgCustom", MsgSend);
|
||||||
|
const options = { prefix: wasmd.prefix, registry: registry };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
|
const openedClient = (client as unknown) as PrivateSigningCosmWasmClient;
|
||||||
|
expect(openedClient.registry.lookupType("/custom.MsgCustom")).toEqual(MsgSend);
|
||||||
|
});
|
||||||
|
|
||||||
it("can be constructed with custom gas price", async () => {
|
it("can be constructed with custom gas price", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const gasPrice = GasPrice.fromString("3.14utest");
|
const options = {
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, { gasPrice });
|
prefix: wasmd.prefix,
|
||||||
|
gasPrice: GasPrice.fromString("3.14utest"),
|
||||||
|
};
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
const openedClient = (client as unknown) as PrivateSigningCosmWasmClient;
|
const openedClient = (client as unknown) as PrivateSigningCosmWasmClient;
|
||||||
expect(openedClient.fees).toEqual({
|
expect(openedClient.fees).toEqual({
|
||||||
upload: {
|
upload: {
|
||||||
@ -70,10 +100,13 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("can be constructed with custom gas limits", async () => {
|
it("can be constructed with custom gas limits", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const gasLimits = {
|
const options = {
|
||||||
send: 160000,
|
prefix: wasmd.prefix,
|
||||||
|
gasLimits: {
|
||||||
|
send: 160000,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, { gasLimits });
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
const openedClient = (client as unknown) as PrivateSigningCosmWasmClient;
|
const openedClient = (client as unknown) as PrivateSigningCosmWasmClient;
|
||||||
expect(openedClient.fees).toEqual({
|
expect(openedClient.fees).toEqual({
|
||||||
upload: {
|
upload: {
|
||||||
@ -106,14 +139,14 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("can be constructed with custom gas price and gas limits", async () => {
|
it("can be constructed with custom gas price and gas limits", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const gasPrice = GasPrice.fromString("3.14utest");
|
const options = {
|
||||||
const gasLimits = {
|
prefix: wasmd.prefix,
|
||||||
send: 160000,
|
gasPrice: GasPrice.fromString("3.14utest"),
|
||||||
|
gasLimits: {
|
||||||
|
send: 160000,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, {
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
gasPrice,
|
|
||||||
gasLimits,
|
|
||||||
});
|
|
||||||
const openedClient = (client as unknown) as PrivateSigningCosmWasmClient;
|
const openedClient = (client as unknown) as PrivateSigningCosmWasmClient;
|
||||||
expect(openedClient.fees).toEqual({
|
expect(openedClient.fees).toEqual({
|
||||||
upload: {
|
upload: {
|
||||||
@ -148,7 +181,8 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("works", async () => {
|
it("works", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
const options = { prefix: wasmd.prefix };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
const wasm = getHackatom().data;
|
const wasm = getHackatom().data;
|
||||||
const {
|
const {
|
||||||
codeId,
|
codeId,
|
||||||
@ -167,7 +201,8 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("can set builder and source", async () => {
|
it("can set builder and source", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
const options = { prefix: wasmd.prefix };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
const hackatom = getHackatom();
|
const hackatom = getHackatom();
|
||||||
const meta: UploadMeta = {
|
const meta: UploadMeta = {
|
||||||
source: "https://crates.io/api/v1/crates/cw-nameservice/0.1.0/download",
|
source: "https://crates.io/api/v1/crates/cw-nameservice/0.1.0/download",
|
||||||
@ -184,7 +219,8 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("works with transfer amount", async () => {
|
it("works with transfer amount", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
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);
|
||||||
const transferAmount = [coin(1234, "ucosm"), coin(321, "ustake")];
|
const transferAmount = [coin(1234, "ucosm"), coin(321, "ustake")];
|
||||||
const beneficiaryAddress = makeRandomAddress();
|
const beneficiaryAddress = makeRandomAddress();
|
||||||
@ -211,7 +247,8 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("works with admin", async () => {
|
it("works with admin", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
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);
|
||||||
const beneficiaryAddress = makeRandomAddress();
|
const beneficiaryAddress = makeRandomAddress();
|
||||||
const { contractAddress } = await client.instantiate(
|
const { contractAddress } = await client.instantiate(
|
||||||
@ -233,7 +270,8 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("can instantiate one code multiple times", async () => {
|
it("can instantiate one code multiple times", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
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);
|
||||||
const contractAddress1 = await client.instantiate(
|
const contractAddress1 = await client.instantiate(
|
||||||
alice.address0,
|
alice.address0,
|
||||||
@ -261,7 +299,8 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("can update an admin", async () => {
|
it("can update an admin", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
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);
|
||||||
const beneficiaryAddress = makeRandomAddress();
|
const beneficiaryAddress = makeRandomAddress();
|
||||||
const { contractAddress } = await client.instantiate(
|
const { contractAddress } = await client.instantiate(
|
||||||
@ -296,7 +335,8 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("can clear an admin", async () => {
|
it("can clear an admin", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
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);
|
||||||
const beneficiaryAddress = makeRandomAddress();
|
const beneficiaryAddress = makeRandomAddress();
|
||||||
const { contractAddress } = await client.instantiate(
|
const { contractAddress } = await client.instantiate(
|
||||||
@ -331,7 +371,8 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("can can migrate from one code ID to another", async () => {
|
it("can can migrate from one code ID to another", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
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: codeId1 } = await client.upload(alice.address0, getHackatom().data);
|
||||||
const { codeId: codeId2 } = await client.upload(alice.address0, getHackatom().data);
|
const { codeId: codeId2 } = await client.upload(alice.address0, getHackatom().data);
|
||||||
const beneficiaryAddress = makeRandomAddress();
|
const beneficiaryAddress = makeRandomAddress();
|
||||||
@ -371,7 +412,8 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
it("works", async () => {
|
it("works", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
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);
|
||||||
// instantiate
|
// instantiate
|
||||||
const transferAmount = [coin(233444, "ucosm"), coin(5454, "ustake")];
|
const transferAmount = [coin(233444, "ucosm"), coin(5454, "ustake")];
|
||||||
@ -411,10 +453,36 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("sendTokens", () => {
|
describe("sendTokens", () => {
|
||||||
it("works", async () => {
|
it("works with direct signer", async () => {
|
||||||
pendingWithoutWasmd();
|
pendingWithoutWasmd();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet);
|
const options = { prefix: wasmd.prefix };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
|
|
||||||
|
const transferAmount = coins(7890, "ucosm");
|
||||||
|
const beneficiaryAddress = makeRandomAddress();
|
||||||
|
const memo = "for dinner";
|
||||||
|
|
||||||
|
// no tokens here
|
||||||
|
const before = await client.getBalance(beneficiaryAddress, "ucosm");
|
||||||
|
expect(before).toBeNull();
|
||||||
|
|
||||||
|
// send
|
||||||
|
const result = await client.sendTokens(alice.address0, beneficiaryAddress, transferAmount, memo);
|
||||||
|
assertIsBroadcastTxSuccess(result);
|
||||||
|
expect(result.rawLog).toBeTruthy();
|
||||||
|
|
||||||
|
// got tokens
|
||||||
|
const after = await client.getBalance(beneficiaryAddress, "ucosm");
|
||||||
|
assert(after);
|
||||||
|
expect(after).toEqual(transferAmount[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works with legacy Amino signer", async () => {
|
||||||
|
pendingWithoutWasmd();
|
||||||
|
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
|
const options = { prefix: wasmd.prefix };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
|
|
||||||
const transferAmount = coins(7890, "ucosm");
|
const transferAmount = coins(7890, "ucosm");
|
||||||
const beneficiaryAddress = makeRandomAddress();
|
const beneficiaryAddress = makeRandomAddress();
|
||||||
@ -444,7 +512,7 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
|
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
|
||||||
const registry = new Registry();
|
const registry = new Registry();
|
||||||
registry.register(msgDelegateTypeUrl, MsgDelegate);
|
registry.register(msgDelegateTypeUrl, MsgDelegate);
|
||||||
const options = { registry: registry };
|
const options = { prefix: wasmd.prefix, registry: registry };
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
|
|
||||||
const msg = MsgDelegate.create({
|
const msg = MsgDelegate.create({
|
||||||
@ -475,7 +543,7 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
|
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
|
||||||
const registry = new Registry();
|
const registry = new Registry();
|
||||||
registry.register(msgDelegateTypeUrl, MsgDelegate);
|
registry.register(msgDelegateTypeUrl, MsgDelegate);
|
||||||
const options = { registry: registry };
|
const options = { prefix: wasmd.prefix, registry: registry };
|
||||||
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
|
|
||||||
const msg = MsgDelegate.create({
|
const msg = MsgDelegate.create({
|
||||||
@ -506,5 +574,193 @@ describe("SigningCosmWasmClient", () => {
|
|||||||
expect(tx.authInfo!.fee!.gasLimit!.toNumber()).toEqual(333333);
|
expect(tx.authInfo!.fee!.gasLimit!.toNumber()).toEqual(333333);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("legacy Amino mode", () => {
|
||||||
|
// NOTE: One custom registry shared between tests
|
||||||
|
// See https://github.com/protobufjs/protobuf.js#using-decorators
|
||||||
|
// > Decorated types reside in protobuf.roots["decorated"] using a flat structure, so no duplicate names.
|
||||||
|
const customRegistry = new Registry();
|
||||||
|
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
|
||||||
|
|
||||||
|
@registered(customRegistry, msgDelegateTypeUrl)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
class CustomMsgDelegate extends Message {
|
||||||
|
@cosmosField.string(1)
|
||||||
|
public readonly custom_delegator_address?: string;
|
||||||
|
@cosmosField.string(2)
|
||||||
|
public readonly custom_validator_address?: string;
|
||||||
|
@cosmosField.message(3, Coin)
|
||||||
|
public readonly custom_amount?: Coin;
|
||||||
|
}
|
||||||
|
|
||||||
|
it("works with bank MsgSend", async () => {
|
||||||
|
pendingWithoutWasmd();
|
||||||
|
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
|
const options = { prefix: wasmd.prefix };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
|
|
||||||
|
const msgSend: IMsgSend = {
|
||||||
|
fromAddress: alice.address0,
|
||||||
|
toAddress: makeRandomAddress(),
|
||||||
|
amount: coins(1234, "ucosm"),
|
||||||
|
};
|
||||||
|
const msgAny = {
|
||||||
|
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
|
||||||
|
value: msgSend,
|
||||||
|
};
|
||||||
|
const fee = {
|
||||||
|
amount: coins(2000, "ucosm"),
|
||||||
|
gas: "200000",
|
||||||
|
};
|
||||||
|
const memo = "Use your tokens wisely";
|
||||||
|
const result = await client.signAndBroadcast(alice.address0, [msgAny], fee, memo);
|
||||||
|
assertIsBroadcastTxSuccess(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works with staking MsgDelegate", async () => {
|
||||||
|
pendingWithoutWasmd();
|
||||||
|
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
|
const options = { prefix: wasmd.prefix };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
|
|
||||||
|
const msgDelegate: IMsgDelegate = {
|
||||||
|
delegatorAddress: alice.address0,
|
||||||
|
validatorAddress: validator.validatorAddress,
|
||||||
|
amount: coin(1234, "ustake"),
|
||||||
|
};
|
||||||
|
const msgAny = {
|
||||||
|
typeUrl: "/cosmos.staking.v1beta1.MsgDelegate",
|
||||||
|
value: msgDelegate,
|
||||||
|
};
|
||||||
|
const fee = {
|
||||||
|
amount: coins(2000, "ustake"),
|
||||||
|
gas: "200000",
|
||||||
|
};
|
||||||
|
const memo = "Use your tokens wisely";
|
||||||
|
const result = await client.signAndBroadcast(alice.address0, [msgAny], fee, memo);
|
||||||
|
assertIsBroadcastTxSuccess(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works with wasm MsgStoreCode", async () => {
|
||||||
|
pendingWithoutWasmd();
|
||||||
|
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
|
const options = { prefix: wasmd.prefix };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
|
const { data, builder, source } = getHackatom();
|
||||||
|
|
||||||
|
const msgStoreCode: IMsgStoreCode = {
|
||||||
|
sender: alice.address0,
|
||||||
|
wasmByteCode: pako.gzip(data),
|
||||||
|
source: source,
|
||||||
|
builder: builder,
|
||||||
|
};
|
||||||
|
const msgAny = {
|
||||||
|
typeUrl: "/cosmwasm.wasm.v1beta1.MsgStoreCode",
|
||||||
|
value: msgStoreCode,
|
||||||
|
};
|
||||||
|
const fee = {
|
||||||
|
amount: coins(2000, "ustake"),
|
||||||
|
gas: "1500000",
|
||||||
|
};
|
||||||
|
const memo = "Use your tokens wisely";
|
||||||
|
const result = await client.signAndBroadcast(alice.address0, [msgAny], fee, memo);
|
||||||
|
assertIsBroadcastTxSuccess(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works with a custom registry and custom message", async () => {
|
||||||
|
pendingWithoutWasmd();
|
||||||
|
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, wasmd.prefix);
|
||||||
|
const customAminoTypes = new AminoTypes({
|
||||||
|
prefix: wasmd.prefix,
|
||||||
|
additions: {
|
||||||
|
"/cosmos.staking.v1beta1.MsgDelegate": {
|
||||||
|
aminoType: "cosmos-sdk/MsgDelegate",
|
||||||
|
toAmino: ({
|
||||||
|
custom_delegator_address,
|
||||||
|
custom_validator_address,
|
||||||
|
custom_amount,
|
||||||
|
}: CustomMsgDelegate): LaunchpadMsgDelegate["value"] => {
|
||||||
|
assert(custom_delegator_address, "missing custom_delegator_address");
|
||||||
|
assert(custom_validator_address, "missing validator_address");
|
||||||
|
assert(custom_amount, "missing amount");
|
||||||
|
assert(custom_amount.amount, "missing amount.amount");
|
||||||
|
assert(custom_amount.denom, "missing amount.denom");
|
||||||
|
return {
|
||||||
|
delegator_address: custom_delegator_address,
|
||||||
|
validator_address: custom_validator_address,
|
||||||
|
amount: {
|
||||||
|
amount: custom_amount.amount,
|
||||||
|
denom: custom_amount.denom,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
fromAmino: ({
|
||||||
|
delegator_address,
|
||||||
|
validator_address,
|
||||||
|
amount,
|
||||||
|
}: LaunchpadMsgDelegate["value"]): CustomMsgDelegate =>
|
||||||
|
CustomMsgDelegate.create({
|
||||||
|
custom_delegator_address: delegator_address,
|
||||||
|
custom_validator_address: validator_address,
|
||||||
|
custom_amount: Coin.create(amount),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const options = { prefix: wasmd.prefix, registry: customRegistry, aminoTypes: customAminoTypes };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
|
|
||||||
|
const msg = {
|
||||||
|
custom_delegator_address: alice.address0,
|
||||||
|
custom_validator_address: validator.validatorAddress,
|
||||||
|
custom_amount: coin(1234, "ustake"),
|
||||||
|
};
|
||||||
|
const msgAny = {
|
||||||
|
typeUrl: "/cosmos.staking.v1beta1.MsgDelegate",
|
||||||
|
value: msg,
|
||||||
|
};
|
||||||
|
const fee = {
|
||||||
|
amount: coins(2000, "ucosm"),
|
||||||
|
gas: "200000",
|
||||||
|
};
|
||||||
|
const memo = "Use your power wisely";
|
||||||
|
const result = await client.signAndBroadcast(alice.address0, [msgAny], fee, memo);
|
||||||
|
assertIsBroadcastTxSuccess(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works with a modifying signer", async () => {
|
||||||
|
pendingWithoutWasmd();
|
||||||
|
const wallet = await ModifyingSecp256k1HdWallet.fromMnemonic(alice.mnemonic, undefined, "wasm");
|
||||||
|
const options = { prefix: wasmd.prefix };
|
||||||
|
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
|
||||||
|
|
||||||
|
const msg = {
|
||||||
|
delegatorAddress: alice.address0,
|
||||||
|
validatorAddress: validator.validatorAddress,
|
||||||
|
amount: coin(1234, "ustake"),
|
||||||
|
};
|
||||||
|
const msgAny = {
|
||||||
|
typeUrl: msgDelegateTypeUrl,
|
||||||
|
value: msg,
|
||||||
|
};
|
||||||
|
const fee = {
|
||||||
|
amount: coins(2000, "ucosm"),
|
||||||
|
gas: "200000",
|
||||||
|
};
|
||||||
|
const memo = "Use your power wisely";
|
||||||
|
const result = await client.signAndBroadcast(alice.address0, [msgAny], fee, memo);
|
||||||
|
assertIsBroadcastTxSuccess(result);
|
||||||
|
|
||||||
|
await sleep(1000);
|
||||||
|
|
||||||
|
const searchResult = await client.getTx(result.transactionHash);
|
||||||
|
assert(searchResult, "Must find transaction");
|
||||||
|
const tx = Tx.decode(searchResult.tx);
|
||||||
|
// From ModifyingSecp256k1HdWallet
|
||||||
|
expect(tx.body!.memo).toEqual("This was modified");
|
||||||
|
expect({ ...tx.authInfo!.fee!.amount![0] }).toEqual(coin(3000, "ucosm"));
|
||||||
|
expect(tx.authInfo!.fee!.gasLimit!.toNumber()).toEqual(333333);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,18 +21,21 @@ import {
|
|||||||
GasLimits,
|
GasLimits,
|
||||||
GasPrice,
|
GasPrice,
|
||||||
logs,
|
logs,
|
||||||
|
makeSignDoc as makeSignDocAmino,
|
||||||
StdFee,
|
StdFee,
|
||||||
} from "@cosmjs/launchpad";
|
} from "@cosmjs/launchpad";
|
||||||
import { Int53, Uint53 } from "@cosmjs/math";
|
import { Int53, Uint53 } from "@cosmjs/math";
|
||||||
import {
|
import {
|
||||||
EncodeObject,
|
EncodeObject,
|
||||||
encodePubkey,
|
encodePubkey,
|
||||||
|
isOfflineDirectSigner,
|
||||||
makeAuthInfoBytes,
|
makeAuthInfoBytes,
|
||||||
makeSignDoc,
|
makeSignDoc,
|
||||||
OfflineDirectSigner,
|
OfflineSigner,
|
||||||
Registry,
|
Registry,
|
||||||
} from "@cosmjs/proto-signing";
|
} from "@cosmjs/proto-signing";
|
||||||
import {
|
import {
|
||||||
|
AminoTypes,
|
||||||
BroadcastTxFailure,
|
BroadcastTxFailure,
|
||||||
BroadcastTxResponse,
|
BroadcastTxResponse,
|
||||||
codec,
|
codec,
|
||||||
@ -43,10 +46,20 @@ import { adaptor34, Client as TendermintClient } from "@cosmjs/tendermint-rpc";
|
|||||||
import Long from "long";
|
import Long from "long";
|
||||||
import pako from "pako";
|
import pako from "pako";
|
||||||
|
|
||||||
|
import { cosmWasmTypes } from "./aminotypes";
|
||||||
import { cosmwasm } from "./codec";
|
import { cosmwasm } from "./codec";
|
||||||
import { CosmWasmClient } from "./cosmwasmclient";
|
import { CosmWasmClient } from "./cosmwasmclient";
|
||||||
|
|
||||||
|
const { SignMode } = codec.cosmos.tx.signing.v1beta1;
|
||||||
const { TxRaw } = codec.cosmos.tx.v1beta1;
|
const { TxRaw } = codec.cosmos.tx.v1beta1;
|
||||||
|
const { MsgMultiSend } = codec.cosmos.bank.v1beta1;
|
||||||
|
const {
|
||||||
|
MsgBeginRedelegate,
|
||||||
|
MsgCreateValidator,
|
||||||
|
MsgDelegate,
|
||||||
|
MsgEditValidator,
|
||||||
|
MsgUndelegate,
|
||||||
|
} = codec.cosmos.staking.v1beta1;
|
||||||
const {
|
const {
|
||||||
MsgClearAdmin,
|
MsgClearAdmin,
|
||||||
MsgExecuteContract,
|
MsgExecuteContract,
|
||||||
@ -81,6 +94,12 @@ function createBroadcastTxErrorMessage(result: BroadcastTxFailure): string {
|
|||||||
|
|
||||||
function createDefaultRegistry(): Registry {
|
function createDefaultRegistry(): Registry {
|
||||||
return new Registry([
|
return new Registry([
|
||||||
|
["/cosmos.bank.v1beta1.MsgMultiSend", MsgMultiSend],
|
||||||
|
["/cosmos.staking.v1beta1.MsgBeginRedelegate", MsgBeginRedelegate],
|
||||||
|
["/cosmos.staking.v1beta1.MsgCreateValidator", MsgCreateValidator],
|
||||||
|
["/cosmos.staking.v1beta1.MsgDelegate", MsgDelegate],
|
||||||
|
["/cosmos.staking.v1beta1.MsgEditValidator", MsgEditValidator],
|
||||||
|
["/cosmos.staking.v1beta1.MsgUndelegate", MsgUndelegate],
|
||||||
["/cosmwasm.wasm.v1beta1.MsgClearAdmin", MsgClearAdmin],
|
["/cosmwasm.wasm.v1beta1.MsgClearAdmin", MsgClearAdmin],
|
||||||
["/cosmwasm.wasm.v1beta1.MsgExecuteContract", MsgExecuteContract],
|
["/cosmwasm.wasm.v1beta1.MsgExecuteContract", MsgExecuteContract],
|
||||||
["/cosmwasm.wasm.v1beta1.MsgMigrateContract", MsgMigrateContract],
|
["/cosmwasm.wasm.v1beta1.MsgMigrateContract", MsgMigrateContract],
|
||||||
@ -92,6 +111,8 @@ function createDefaultRegistry(): Registry {
|
|||||||
|
|
||||||
export interface SigningCosmWasmClientOptions {
|
export interface SigningCosmWasmClientOptions {
|
||||||
readonly registry?: Registry;
|
readonly registry?: Registry;
|
||||||
|
readonly aminoTypes?: AminoTypes;
|
||||||
|
readonly prefix?: string;
|
||||||
readonly gasPrice?: GasPrice;
|
readonly gasPrice?: GasPrice;
|
||||||
readonly gasLimits?: GasLimits<CosmosFeeTable>;
|
readonly gasLimits?: GasLimits<CosmosFeeTable>;
|
||||||
}
|
}
|
||||||
@ -99,16 +120,18 @@ export interface SigningCosmWasmClientOptions {
|
|||||||
/** Use for testing only */
|
/** Use for testing only */
|
||||||
export interface PrivateSigningCosmWasmClient {
|
export interface PrivateSigningCosmWasmClient {
|
||||||
readonly fees: CosmWasmFeeTable;
|
readonly fees: CosmWasmFeeTable;
|
||||||
|
readonly registry: Registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SigningCosmWasmClient extends CosmWasmClient {
|
export class SigningCosmWasmClient extends CosmWasmClient {
|
||||||
private readonly fees: CosmosFeeTable;
|
private readonly fees: CosmosFeeTable;
|
||||||
private readonly registry: Registry;
|
private readonly registry: Registry;
|
||||||
private readonly signer: OfflineDirectSigner;
|
private readonly signer: OfflineSigner;
|
||||||
|
private readonly aminoTypes: AminoTypes;
|
||||||
|
|
||||||
public static async connectWithSigner(
|
public static async connectWithSigner(
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
signer: OfflineDirectSigner,
|
signer: OfflineSigner,
|
||||||
options: SigningCosmWasmClientOptions = {},
|
options: SigningCosmWasmClientOptions = {},
|
||||||
): Promise<SigningCosmWasmClient> {
|
): Promise<SigningCosmWasmClient> {
|
||||||
const tmClient = await TendermintClient.connect(endpoint, adaptor34);
|
const tmClient = await TendermintClient.connect(endpoint, adaptor34);
|
||||||
@ -117,17 +140,19 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
|||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
tmClient: TendermintClient,
|
tmClient: TendermintClient,
|
||||||
signer: OfflineDirectSigner,
|
signer: OfflineSigner,
|
||||||
options: SigningCosmWasmClientOptions,
|
options: SigningCosmWasmClientOptions,
|
||||||
) {
|
) {
|
||||||
super(tmClient);
|
super(tmClient);
|
||||||
const {
|
const {
|
||||||
registry = createDefaultRegistry(),
|
registry = createDefaultRegistry(),
|
||||||
|
aminoTypes = new AminoTypes({ additions: cosmWasmTypes, prefix: options.prefix }),
|
||||||
gasPrice = defaultGasPrice,
|
gasPrice = defaultGasPrice,
|
||||||
gasLimits = defaultGasLimits,
|
gasLimits = defaultGasLimits,
|
||||||
} = options;
|
} = options;
|
||||||
this.fees = buildFeeTable<CosmosFeeTable>(gasPrice, defaultGasLimits, gasLimits);
|
this.fees = buildFeeTable<CosmosFeeTable>(gasPrice, defaultGasLimits, gasLimits);
|
||||||
this.registry = registry;
|
this.registry = registry;
|
||||||
|
this.aminoTypes = aminoTypes;
|
||||||
this.signer = signer;
|
this.signer = signer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,12 +380,44 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
|||||||
});
|
});
|
||||||
const gasLimit = Int53.fromString(fee.gas).toNumber();
|
const gasLimit = Int53.fromString(fee.gas).toNumber();
|
||||||
|
|
||||||
const authInfoBytes = makeAuthInfoBytes([pubkeyAny], fee.amount, gasLimit, sequence);
|
if (isOfflineDirectSigner(this.signer)) {
|
||||||
const signDoc = makeSignDoc(txBodyBytes, authInfoBytes, chainId, accountNumber);
|
const authInfoBytes = makeAuthInfoBytes([pubkeyAny], fee.amount, gasLimit, sequence);
|
||||||
const { signature, signed } = await this.signer.signDirect(signerAddress, signDoc);
|
const signDoc = makeSignDoc(txBodyBytes, authInfoBytes, chainId, accountNumber);
|
||||||
|
const { signature, signed } = await this.signer.signDirect(signerAddress, signDoc);
|
||||||
|
const txRaw = TxRaw.create({
|
||||||
|
bodyBytes: signed.bodyBytes,
|
||||||
|
authInfoBytes: signed.authInfoBytes,
|
||||||
|
signatures: [fromBase64(signature.signature)],
|
||||||
|
});
|
||||||
|
const signedTx = Uint8Array.from(TxRaw.encode(txRaw).finish());
|
||||||
|
return this.broadcastTx(signedTx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Amino signer
|
||||||
|
const signMode = SignMode.SIGN_MODE_LEGACY_AMINO_JSON;
|
||||||
|
const msgs = messages.map((msg) => this.aminoTypes.toAmino(msg));
|
||||||
|
const signDoc = makeSignDocAmino(msgs, fee, chainId, memo, accountNumber, sequence);
|
||||||
|
const { signature, signed } = await this.signer.signAmino(signerAddress, signDoc);
|
||||||
|
const signedTxBody = {
|
||||||
|
messages: signed.msgs.map((msg) => this.aminoTypes.fromAmino(msg)),
|
||||||
|
memo: signed.memo,
|
||||||
|
};
|
||||||
|
const signedTxBodyBytes = this.registry.encode({
|
||||||
|
typeUrl: "/cosmos.tx.v1beta1.TxBody",
|
||||||
|
value: signedTxBody,
|
||||||
|
});
|
||||||
|
const signedGasLimit = Int53.fromString(signed.fee.gas).toNumber();
|
||||||
|
const signedSequence = Int53.fromString(signed.sequence).toNumber();
|
||||||
|
const signedAuthInfoBytes = makeAuthInfoBytes(
|
||||||
|
[pubkeyAny],
|
||||||
|
signed.fee.amount,
|
||||||
|
signedGasLimit,
|
||||||
|
signedSequence,
|
||||||
|
signMode,
|
||||||
|
);
|
||||||
const txRaw = TxRaw.create({
|
const txRaw = TxRaw.create({
|
||||||
bodyBytes: signed.bodyBytes,
|
bodyBytes: signedTxBodyBytes,
|
||||||
authInfoBytes: signed.authInfoBytes,
|
authInfoBytes: signedAuthInfoBytes,
|
||||||
signatures: [fromBase64(signature.signature)],
|
signatures: [fromBase64(signature.signature)],
|
||||||
});
|
});
|
||||||
const signedTx = Uint8Array.from(TxRaw.encode(txRaw).finish());
|
const signedTx = Uint8Array.from(TxRaw.encode(txRaw).finish());
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
import { Bip39, EnglishMnemonic, Random, Secp256k1, Slip10, Slip10Curve } from "@cosmjs/crypto";
|
import { Bip39, EnglishMnemonic, Random, Secp256k1, Slip10, Slip10Curve } from "@cosmjs/crypto";
|
||||||
import { Bech32, fromBase64 } from "@cosmjs/encoding";
|
import { Bech32, fromBase64 } from "@cosmjs/encoding";
|
||||||
import { coins, makeCosmoshubPath } from "@cosmjs/launchpad";
|
import {
|
||||||
|
AminoSignResponse,
|
||||||
|
coins,
|
||||||
|
makeCosmoshubPath,
|
||||||
|
Secp256k1HdWallet,
|
||||||
|
StdSignDoc,
|
||||||
|
} from "@cosmjs/launchpad";
|
||||||
import { DirectSecp256k1HdWallet, DirectSignResponse, makeAuthInfoBytes } from "@cosmjs/proto-signing";
|
import { DirectSecp256k1HdWallet, DirectSignResponse, makeAuthInfoBytes } from "@cosmjs/proto-signing";
|
||||||
import {
|
import {
|
||||||
AuthExtension,
|
AuthExtension,
|
||||||
@ -205,6 +211,41 @@ export async function makeWasmClient(
|
|||||||
return QueryClient.withExtensions(tmClient, setupAuthExtension, setupBankExtension, setupWasmExtension);
|
return QueryClient.withExtensions(tmClient, setupAuthExtension, setupBankExtension, setupWasmExtension);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class for testing clients using an Amino signer which modifies the transaction it receives before signing
|
||||||
|
*/
|
||||||
|
export class ModifyingSecp256k1HdWallet extends Secp256k1HdWallet {
|
||||||
|
public static async fromMnemonic(
|
||||||
|
mnemonic: string,
|
||||||
|
hdPath = makeCosmoshubPath(0),
|
||||||
|
prefix = "cosmos",
|
||||||
|
): Promise<ModifyingSecp256k1HdWallet> {
|
||||||
|
const mnemonicChecked = new EnglishMnemonic(mnemonic);
|
||||||
|
const seed = await Bip39.mnemonicToSeed(mnemonicChecked);
|
||||||
|
const { privkey } = Slip10.derivePath(Slip10Curve.Secp256k1, seed, hdPath);
|
||||||
|
const uncompressed = (await Secp256k1.makeKeypair(privkey)).pubkey;
|
||||||
|
return new ModifyingSecp256k1HdWallet(
|
||||||
|
mnemonicChecked,
|
||||||
|
hdPath,
|
||||||
|
privkey,
|
||||||
|
Secp256k1.compressPubkey(uncompressed),
|
||||||
|
prefix,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async signAmino(signerAddress: string, signDoc: StdSignDoc): Promise<AminoSignResponse> {
|
||||||
|
const modifiedSignDoc = {
|
||||||
|
...signDoc,
|
||||||
|
fee: {
|
||||||
|
amount: coins(3000, "ucosm"),
|
||||||
|
gas: "333333",
|
||||||
|
},
|
||||||
|
memo: "This was modified",
|
||||||
|
};
|
||||||
|
return super.signAmino(signerAddress, modifiedSignDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class for testing clients using a direct signer which modifies the transaction it receives before signing
|
* A class for testing clients using a direct signer which modifies the transaction it receives before signing
|
||||||
*/
|
*/
|
||||||
|
2
packages/cosmwasm-stargate/types/aminotypes.d.ts
vendored
Normal file
2
packages/cosmwasm-stargate/types/aminotypes.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import { AminoConverter } from "@cosmjs/stargate";
|
||||||
|
export declare const cosmWasmTypes: Record<string, AminoConverter>;
|
@ -9,25 +9,29 @@ import {
|
|||||||
UploadResult,
|
UploadResult,
|
||||||
} from "@cosmjs/cosmwasm-launchpad";
|
} from "@cosmjs/cosmwasm-launchpad";
|
||||||
import { Coin, CosmosFeeTable, GasLimits, GasPrice, StdFee } from "@cosmjs/launchpad";
|
import { Coin, CosmosFeeTable, GasLimits, GasPrice, StdFee } from "@cosmjs/launchpad";
|
||||||
import { EncodeObject, OfflineDirectSigner, Registry } from "@cosmjs/proto-signing";
|
import { EncodeObject, OfflineSigner, Registry } from "@cosmjs/proto-signing";
|
||||||
import { BroadcastTxResponse } from "@cosmjs/stargate";
|
import { AminoTypes, BroadcastTxResponse } from "@cosmjs/stargate";
|
||||||
import { CosmWasmClient } from "./cosmwasmclient";
|
import { CosmWasmClient } from "./cosmwasmclient";
|
||||||
export interface SigningCosmWasmClientOptions {
|
export interface SigningCosmWasmClientOptions {
|
||||||
readonly registry?: Registry;
|
readonly registry?: Registry;
|
||||||
|
readonly aminoTypes?: AminoTypes;
|
||||||
|
readonly prefix?: string;
|
||||||
readonly gasPrice?: GasPrice;
|
readonly gasPrice?: GasPrice;
|
||||||
readonly gasLimits?: GasLimits<CosmosFeeTable>;
|
readonly gasLimits?: GasLimits<CosmosFeeTable>;
|
||||||
}
|
}
|
||||||
/** Use for testing only */
|
/** Use for testing only */
|
||||||
export interface PrivateSigningCosmWasmClient {
|
export interface PrivateSigningCosmWasmClient {
|
||||||
readonly fees: CosmWasmFeeTable;
|
readonly fees: CosmWasmFeeTable;
|
||||||
|
readonly registry: Registry;
|
||||||
}
|
}
|
||||||
export declare class SigningCosmWasmClient extends CosmWasmClient {
|
export declare class SigningCosmWasmClient extends CosmWasmClient {
|
||||||
private readonly fees;
|
private readonly fees;
|
||||||
private readonly registry;
|
private readonly registry;
|
||||||
private readonly signer;
|
private readonly signer;
|
||||||
|
private readonly aminoTypes;
|
||||||
static connectWithSigner(
|
static connectWithSigner(
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
signer: OfflineDirectSigner,
|
signer: OfflineSigner,
|
||||||
options?: SigningCosmWasmClientOptions,
|
options?: SigningCosmWasmClientOptions,
|
||||||
): Promise<SigningCosmWasmClient>;
|
): Promise<SigningCosmWasmClient>;
|
||||||
private constructor();
|
private constructor();
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
import { fromBase64, toBase64 } from "@cosmjs/encoding";
|
import { fromBase64, toBase64 } from "@cosmjs/encoding";
|
||||||
import {
|
import {
|
||||||
Coin,
|
|
||||||
decodeBech32Pubkey,
|
decodeBech32Pubkey,
|
||||||
encodeBech32Pubkey,
|
encodeBech32Pubkey,
|
||||||
Msg,
|
Msg,
|
||||||
@ -14,11 +13,11 @@ import {
|
|||||||
MsgUndelegate,
|
MsgUndelegate,
|
||||||
} from "@cosmjs/launchpad";
|
} from "@cosmjs/launchpad";
|
||||||
import { EncodeObject } from "@cosmjs/proto-signing";
|
import { EncodeObject } from "@cosmjs/proto-signing";
|
||||||
import { assert } from "@cosmjs/utils";
|
import { assertDefinedAndNotNull } from "@cosmjs/utils";
|
||||||
|
|
||||||
import { cosmos } from "./codec";
|
import { cosmos } from "./codec";
|
||||||
|
import { coinFromProto } from "./stargateclient";
|
||||||
|
|
||||||
type ICoin = cosmos.base.v1beta1.ICoin;
|
|
||||||
type IMsgSend = cosmos.bank.v1beta1.IMsgSend;
|
type IMsgSend = cosmos.bank.v1beta1.IMsgSend;
|
||||||
type IMsgMultiSend = cosmos.bank.v1beta1.IMsgMultiSend;
|
type IMsgMultiSend = cosmos.bank.v1beta1.IMsgMultiSend;
|
||||||
type IMsgBeginRedelegate = cosmos.staking.v1beta1.IMsgBeginRedelegate;
|
type IMsgBeginRedelegate = cosmos.staking.v1beta1.IMsgBeginRedelegate;
|
||||||
@ -33,29 +32,18 @@ export interface AminoConverter {
|
|||||||
readonly fromAmino: (value: any) => any;
|
readonly fromAmino: (value: any) => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkAmount(amount: readonly ICoin[] | undefined | null): readonly Coin[] {
|
|
||||||
assert(amount, "missing amount");
|
|
||||||
return amount.map((a) => {
|
|
||||||
assert(a.amount, "missing amount");
|
|
||||||
assert(a.denom, "missing denom");
|
|
||||||
return {
|
|
||||||
amount: a.amount,
|
|
||||||
denom: a.denom,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createDefaultTypes(prefix: string): Record<string, AminoConverter> {
|
function createDefaultTypes(prefix: string): Record<string, AminoConverter> {
|
||||||
return {
|
return {
|
||||||
"/cosmos.bank.v1beta1.MsgSend": {
|
"/cosmos.bank.v1beta1.MsgSend": {
|
||||||
aminoType: "cosmos-sdk/MsgSend",
|
aminoType: "cosmos-sdk/MsgSend",
|
||||||
toAmino: ({ fromAddress, toAddress, amount }: IMsgSend): MsgSend["value"] => {
|
toAmino: ({ fromAddress, toAddress, amount }: IMsgSend): MsgSend["value"] => {
|
||||||
assert(fromAddress, "missing fromAddress");
|
assertDefinedAndNotNull(fromAddress, "missing fromAddress");
|
||||||
assert(toAddress, "missing toAddress");
|
assertDefinedAndNotNull(toAddress, "missing toAddress");
|
||||||
|
assertDefinedAndNotNull(amount, "missing amount");
|
||||||
return {
|
return {
|
||||||
from_address: fromAddress,
|
from_address: fromAddress,
|
||||||
to_address: toAddress,
|
to_address: toAddress,
|
||||||
amount: checkAmount(amount),
|
amount: amount.map(coinFromProto),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
fromAmino: ({ from_address, to_address, amount }: MsgSend["value"]): IMsgSend => ({
|
fromAmino: ({ from_address, to_address, amount }: MsgSend["value"]): IMsgSend => ({
|
||||||
@ -67,21 +55,23 @@ function createDefaultTypes(prefix: string): Record<string, AminoConverter> {
|
|||||||
"/cosmos.bank.v1beta1.MsgMultiSend": {
|
"/cosmos.bank.v1beta1.MsgMultiSend": {
|
||||||
aminoType: "cosmos-sdk/MsgMultiSend",
|
aminoType: "cosmos-sdk/MsgMultiSend",
|
||||||
toAmino: ({ inputs, outputs }: IMsgMultiSend): MsgMultiSend["value"] => {
|
toAmino: ({ inputs, outputs }: IMsgMultiSend): MsgMultiSend["value"] => {
|
||||||
assert(inputs, "missing inputs");
|
assertDefinedAndNotNull(inputs, "missing inputs");
|
||||||
assert(outputs, "missing outputs");
|
assertDefinedAndNotNull(outputs, "missing outputs");
|
||||||
return {
|
return {
|
||||||
inputs: inputs.map((input) => {
|
inputs: inputs.map((input) => {
|
||||||
assert(input.address, "missing input.address");
|
assertDefinedAndNotNull(input.address, "missing input.address");
|
||||||
|
assertDefinedAndNotNull(input.coins, "missing input.amount");
|
||||||
return {
|
return {
|
||||||
address: input.address,
|
address: input.address,
|
||||||
coins: checkAmount(input.coins),
|
coins: input.coins.map(coinFromProto),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
outputs: outputs.map((output) => {
|
outputs: outputs.map((output) => {
|
||||||
assert(output.address, "missing output.address");
|
assertDefinedAndNotNull(output.address, "missing output.address");
|
||||||
|
assertDefinedAndNotNull(output.coins, "missing output.coins");
|
||||||
return {
|
return {
|
||||||
address: output.address,
|
address: output.address,
|
||||||
coins: checkAmount(output.coins),
|
coins: output.coins.map(coinFromProto),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@ -105,20 +95,15 @@ function createDefaultTypes(prefix: string): Record<string, AminoConverter> {
|
|||||||
validatorDstAddress,
|
validatorDstAddress,
|
||||||
amount,
|
amount,
|
||||||
}: IMsgBeginRedelegate): MsgBeginRedelegate["value"] => {
|
}: IMsgBeginRedelegate): MsgBeginRedelegate["value"] => {
|
||||||
assert(delegatorAddress, "missing delegatorAddress");
|
assertDefinedAndNotNull(delegatorAddress, "missing delegatorAddress");
|
||||||
assert(validatorSrcAddress, "missing validatorSrcAddress");
|
assertDefinedAndNotNull(validatorSrcAddress, "missing validatorSrcAddress");
|
||||||
assert(validatorDstAddress, "missing validatorDstAddress");
|
assertDefinedAndNotNull(validatorDstAddress, "missing validatorDstAddress");
|
||||||
assert(amount, "missing amount");
|
assertDefinedAndNotNull(amount, "missing amount");
|
||||||
assert(amount.amount, "missing amount.amount");
|
|
||||||
assert(amount.denom, "missing amount.denom");
|
|
||||||
return {
|
return {
|
||||||
delegator_address: delegatorAddress,
|
delegator_address: delegatorAddress,
|
||||||
validator_src_address: validatorSrcAddress,
|
validator_src_address: validatorSrcAddress,
|
||||||
validator_dst_address: validatorDstAddress,
|
validator_dst_address: validatorDstAddress,
|
||||||
amount: {
|
amount: coinFromProto(amount),
|
||||||
amount: amount.amount,
|
|
||||||
denom: amount.denom,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
fromAmino: ({
|
fromAmino: ({
|
||||||
@ -144,24 +129,22 @@ function createDefaultTypes(prefix: string): Record<string, AminoConverter> {
|
|||||||
pubkey,
|
pubkey,
|
||||||
value,
|
value,
|
||||||
}: IMsgCreateValidator): MsgCreateValidator["value"] => {
|
}: IMsgCreateValidator): MsgCreateValidator["value"] => {
|
||||||
assert(description, "missing description");
|
assertDefinedAndNotNull(description, "missing description");
|
||||||
assert(description.moniker, "missing description.moniker");
|
assertDefinedAndNotNull(description.moniker, "missing description.moniker");
|
||||||
assert(description.identity, "missing description.identity");
|
assertDefinedAndNotNull(description.identity, "missing description.identity");
|
||||||
assert(description.website, "missing description.website");
|
assertDefinedAndNotNull(description.website, "missing description.website");
|
||||||
assert(description.securityContact, "missing description.securityContact");
|
assertDefinedAndNotNull(description.securityContact, "missing description.securityContact");
|
||||||
assert(description.details, "missing description.details");
|
assertDefinedAndNotNull(description.details, "missing description.details");
|
||||||
assert(commission, "missing commission");
|
assertDefinedAndNotNull(commission, "missing commission");
|
||||||
assert(commission.rate, "missing commission.rate");
|
assertDefinedAndNotNull(commission.rate, "missing commission.rate");
|
||||||
assert(commission.maxRate, "missing commission.maxRate");
|
assertDefinedAndNotNull(commission.maxRate, "missing commission.maxRate");
|
||||||
assert(commission.maxChangeRate, "missing commission.maxChangeRate");
|
assertDefinedAndNotNull(commission.maxChangeRate, "missing commission.maxChangeRate");
|
||||||
assert(minSelfDelegation, "missing minSelfDelegation");
|
assertDefinedAndNotNull(minSelfDelegation, "missing minSelfDelegation");
|
||||||
assert(delegatorAddress, "missing delegatorAddress");
|
assertDefinedAndNotNull(delegatorAddress, "missing delegatorAddress");
|
||||||
assert(validatorAddress, "missing validatorAddress");
|
assertDefinedAndNotNull(validatorAddress, "missing validatorAddress");
|
||||||
assert(pubkey, "missing pubkey");
|
assertDefinedAndNotNull(pubkey, "missing pubkey");
|
||||||
assert(pubkey.value, "missing pubkey.value");
|
assertDefinedAndNotNull(pubkey.value, "missing pubkey.value");
|
||||||
assert(value, "missing value");
|
assertDefinedAndNotNull(value, "missing value");
|
||||||
assert(value.amount, "missing value.amount");
|
|
||||||
assert(value.denom, "missing value.denom");
|
|
||||||
return {
|
return {
|
||||||
description: {
|
description: {
|
||||||
moniker: description.moniker,
|
moniker: description.moniker,
|
||||||
@ -185,10 +168,7 @@ function createDefaultTypes(prefix: string): Record<string, AminoConverter> {
|
|||||||
},
|
},
|
||||||
prefix,
|
prefix,
|
||||||
),
|
),
|
||||||
value: {
|
value: coinFromProto(value),
|
||||||
amount: value.amount,
|
|
||||||
denom: value.denom,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
fromAmino: ({
|
fromAmino: ({
|
||||||
@ -231,18 +211,13 @@ function createDefaultTypes(prefix: string): Record<string, AminoConverter> {
|
|||||||
"/cosmos.staking.v1beta1.MsgDelegate": {
|
"/cosmos.staking.v1beta1.MsgDelegate": {
|
||||||
aminoType: "cosmos-sdk/MsgDelegate",
|
aminoType: "cosmos-sdk/MsgDelegate",
|
||||||
toAmino: ({ delegatorAddress, validatorAddress, amount }: IMsgDelegate): MsgDelegate["value"] => {
|
toAmino: ({ delegatorAddress, validatorAddress, amount }: IMsgDelegate): MsgDelegate["value"] => {
|
||||||
assert(delegatorAddress, "missing delegatorAddress");
|
assertDefinedAndNotNull(delegatorAddress, "missing delegatorAddress");
|
||||||
assert(validatorAddress, "missing validatorAddress");
|
assertDefinedAndNotNull(validatorAddress, "missing validatorAddress");
|
||||||
assert(amount, "missing amount");
|
assertDefinedAndNotNull(amount, "missing amount");
|
||||||
assert(amount.amount, "missing amount.amount");
|
|
||||||
assert(amount.denom, "missing amount.denom");
|
|
||||||
return {
|
return {
|
||||||
delegator_address: delegatorAddress,
|
delegator_address: delegatorAddress,
|
||||||
validator_address: validatorAddress,
|
validator_address: validatorAddress,
|
||||||
amount: {
|
amount: coinFromProto(amount),
|
||||||
amount: amount.amount,
|
|
||||||
denom: amount.denom,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
fromAmino: ({ delegator_address, validator_address, amount }: MsgDelegate["value"]): IMsgDelegate => ({
|
fromAmino: ({ delegator_address, validator_address, amount }: MsgDelegate["value"]): IMsgDelegate => ({
|
||||||
@ -259,15 +234,15 @@ function createDefaultTypes(prefix: string): Record<string, AminoConverter> {
|
|||||||
minSelfDelegation,
|
minSelfDelegation,
|
||||||
validatorAddress,
|
validatorAddress,
|
||||||
}: IMsgEditValidator): MsgEditValidator["value"] => {
|
}: IMsgEditValidator): MsgEditValidator["value"] => {
|
||||||
assert(description, "missing description");
|
assertDefinedAndNotNull(description, "missing description");
|
||||||
assert(description.moniker, "missing description.moniker");
|
assertDefinedAndNotNull(description.moniker, "missing description.moniker");
|
||||||
assert(description.identity, "missing description.identity");
|
assertDefinedAndNotNull(description.identity, "missing description.identity");
|
||||||
assert(description.website, "missing description.website");
|
assertDefinedAndNotNull(description.website, "missing description.website");
|
||||||
assert(description.securityContact, "missing description.securityContact");
|
assertDefinedAndNotNull(description.securityContact, "missing description.securityContact");
|
||||||
assert(description.details, "missing description.details");
|
assertDefinedAndNotNull(description.details, "missing description.details");
|
||||||
assert(commissionRate, "missing commissionRate");
|
assertDefinedAndNotNull(commissionRate, "missing commissionRate");
|
||||||
assert(minSelfDelegation, "missing minSelfDelegation");
|
assertDefinedAndNotNull(minSelfDelegation, "missing minSelfDelegation");
|
||||||
assert(validatorAddress, "missing validatorAddress");
|
assertDefinedAndNotNull(validatorAddress, "missing validatorAddress");
|
||||||
return {
|
return {
|
||||||
description: {
|
description: {
|
||||||
moniker: description.moniker,
|
moniker: description.moniker,
|
||||||
@ -302,18 +277,13 @@ function createDefaultTypes(prefix: string): Record<string, AminoConverter> {
|
|||||||
"/cosmos.staking.v1beta1.MsgUndelegate": {
|
"/cosmos.staking.v1beta1.MsgUndelegate": {
|
||||||
aminoType: "cosmos-sdk/MsgUndelegate",
|
aminoType: "cosmos-sdk/MsgUndelegate",
|
||||||
toAmino: ({ delegatorAddress, validatorAddress, amount }: IMsgUndelegate): MsgUndelegate["value"] => {
|
toAmino: ({ delegatorAddress, validatorAddress, amount }: IMsgUndelegate): MsgUndelegate["value"] => {
|
||||||
assert(delegatorAddress, "missing delegatorAddress");
|
assertDefinedAndNotNull(delegatorAddress, "missing delegatorAddress");
|
||||||
assert(validatorAddress, "missing validatorAddress");
|
assertDefinedAndNotNull(validatorAddress, "missing validatorAddress");
|
||||||
assert(amount, "missing amount");
|
assertDefinedAndNotNull(amount, "missing amount");
|
||||||
assert(amount.amount, "missing amount.amount");
|
|
||||||
assert(amount.denom, "missing amount.denom");
|
|
||||||
return {
|
return {
|
||||||
delegator_address: delegatorAddress,
|
delegator_address: delegatorAddress,
|
||||||
validator_address: validatorAddress,
|
validator_address: validatorAddress,
|
||||||
amount: {
|
amount: coinFromProto(amount),
|
||||||
amount: amount.amount,
|
|
||||||
denom: amount.denom,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
fromAmino: ({
|
fromAmino: ({
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export * as codec from "./codec";
|
export * as codec from "./codec";
|
||||||
export { AminoTypes } from "./aminotypes";
|
export { AminoConverter, AminoTypes } from "./aminotypes";
|
||||||
export { parseRawLog } from "./logs";
|
export { parseRawLog } from "./logs";
|
||||||
export {
|
export {
|
||||||
AuthExtension,
|
AuthExtension,
|
||||||
|
@ -3,7 +3,7 @@ import { iavlSpec, ics23, tendermintSpec, verifyExistence, verifyNonExistence }
|
|||||||
import { toAscii, toHex } from "@cosmjs/encoding";
|
import { toAscii, toHex } from "@cosmjs/encoding";
|
||||||
import { firstEvent } from "@cosmjs/stream";
|
import { firstEvent } from "@cosmjs/stream";
|
||||||
import { Client as TendermintClient, Header, NewBlockHeaderEvent, ProofOp } from "@cosmjs/tendermint-rpc";
|
import { Client as TendermintClient, Header, NewBlockHeaderEvent, ProofOp } from "@cosmjs/tendermint-rpc";
|
||||||
import { arrayContentEquals, assert, assertDefined, isNonNullObject, sleep } from "@cosmjs/utils";
|
import { arrayContentEquals, assert, assertDefinedAndNotNull, isNonNullObject, sleep } from "@cosmjs/utils";
|
||||||
import { Stream } from "xstream";
|
import { Stream } from "xstream";
|
||||||
|
|
||||||
type QueryExtensionSetup<P> = (base: QueryClient) => P;
|
type QueryExtensionSetup<P> = (base: QueryClient) => P;
|
||||||
@ -233,7 +233,7 @@ export class QueryClient {
|
|||||||
// this must return the header for height+1
|
// this must return the header for height+1
|
||||||
// throws an error if height is 0 or undefined
|
// throws an error if height is 0 or undefined
|
||||||
private async getNextHeader(height?: number): Promise<Header> {
|
private async getNextHeader(height?: number): Promise<Header> {
|
||||||
assertDefined(height);
|
assertDefinedAndNotNull(height);
|
||||||
if (height === 0) {
|
if (height === 0) {
|
||||||
throw new Error("Query returned height 0, cannot prove it");
|
throw new Error("Query returned height 0, cannot prove it");
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,9 @@ import {
|
|||||||
validator,
|
validator,
|
||||||
} from "./testutils.spec";
|
} from "./testutils.spec";
|
||||||
|
|
||||||
|
type IMsgSend = cosmos.bank.v1beta1.IMsgSend;
|
||||||
|
type IMsgDelegate = cosmos.staking.v1beta1.IMsgDelegate;
|
||||||
|
|
||||||
const { MsgSend } = cosmos.bank.v1beta1;
|
const { MsgSend } = cosmos.bank.v1beta1;
|
||||||
const { MsgDelegate } = cosmos.staking.v1beta1;
|
const { MsgDelegate } = cosmos.staking.v1beta1;
|
||||||
const { Tx } = cosmos.tx.v1beta1;
|
const { Tx } = cosmos.tx.v1beta1;
|
||||||
@ -126,7 +129,7 @@ describe("SigningStargateClient", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("sendTokens", () => {
|
describe("sendTokens", () => {
|
||||||
it("works", async () => {
|
it("works with direct signer", async () => {
|
||||||
pendingWithoutSimapp();
|
pendingWithoutSimapp();
|
||||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||||
const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet);
|
const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet);
|
||||||
@ -149,6 +152,30 @@ describe("SigningStargateClient", () => {
|
|||||||
assert(after);
|
assert(after);
|
||||||
expect(after).toEqual(transferAmount[0]);
|
expect(after).toEqual(transferAmount[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("works with legacy Amino signer", async () => {
|
||||||
|
pendingWithoutSimapp();
|
||||||
|
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||||
|
const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet);
|
||||||
|
|
||||||
|
const transferAmount = coins(7890, "ucosm");
|
||||||
|
const beneficiaryAddress = makeRandomAddress();
|
||||||
|
const memo = "for dinner";
|
||||||
|
|
||||||
|
// no tokens here
|
||||||
|
const before = await client.getBalance(beneficiaryAddress, "ucosm");
|
||||||
|
expect(before).toBeNull();
|
||||||
|
|
||||||
|
// send
|
||||||
|
const result = await client.sendTokens(faucet.address0, beneficiaryAddress, transferAmount, memo);
|
||||||
|
assertIsBroadcastTxSuccess(result);
|
||||||
|
expect(result.rawLog).toBeTruthy();
|
||||||
|
|
||||||
|
// got tokens
|
||||||
|
const after = await client.getBalance(beneficiaryAddress, "ucosm");
|
||||||
|
assert(after);
|
||||||
|
expect(after).toEqual(transferAmount[0]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("signAndBroadcast", () => {
|
describe("signAndBroadcast", () => {
|
||||||
@ -235,7 +262,7 @@ describe("SigningStargateClient", () => {
|
|||||||
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||||
const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet);
|
const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet);
|
||||||
|
|
||||||
const msgSend = {
|
const msgSend: IMsgSend = {
|
||||||
fromAddress: faucet.address0,
|
fromAddress: faucet.address0,
|
||||||
toAddress: makeRandomAddress(),
|
toAddress: makeRandomAddress(),
|
||||||
amount: coins(1234, "ucosm"),
|
amount: coins(1234, "ucosm"),
|
||||||
@ -258,7 +285,7 @@ describe("SigningStargateClient", () => {
|
|||||||
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||||
const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet);
|
const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet);
|
||||||
|
|
||||||
const msgDelegate = {
|
const msgDelegate: IMsgDelegate = {
|
||||||
delegatorAddress: faucet.address0,
|
delegatorAddress: faucet.address0,
|
||||||
validatorAddress: validator.validatorAddress,
|
validatorAddress: validator.validatorAddress,
|
||||||
amount: coin(1234, "ustake"),
|
amount: coin(1234, "ustake"),
|
||||||
|
@ -40,6 +40,17 @@ const { TxRaw } = cosmos.tx.v1beta1;
|
|||||||
const defaultGasPrice = GasPrice.fromString("0.025ucosm");
|
const defaultGasPrice = GasPrice.fromString("0.025ucosm");
|
||||||
const defaultGasLimits: GasLimits<CosmosFeeTable> = { send: 80000 };
|
const defaultGasLimits: GasLimits<CosmosFeeTable> = { send: 80000 };
|
||||||
|
|
||||||
|
function createDefaultRegistry(): Registry {
|
||||||
|
return new Registry([
|
||||||
|
["/cosmos.bank.v1beta1.MsgMultiSend", MsgMultiSend],
|
||||||
|
["/cosmos.staking.v1beta1.MsgBeginRedelegate", MsgBeginRedelegate],
|
||||||
|
["/cosmos.staking.v1beta1.MsgCreateValidator", MsgCreateValidator],
|
||||||
|
["/cosmos.staking.v1beta1.MsgDelegate", MsgDelegate],
|
||||||
|
["/cosmos.staking.v1beta1.MsgEditValidator", MsgEditValidator],
|
||||||
|
["/cosmos.staking.v1beta1.MsgUndelegate", MsgUndelegate],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/** Use for testing only */
|
/** Use for testing only */
|
||||||
export interface PrivateSigningStargateClient {
|
export interface PrivateSigningStargateClient {
|
||||||
readonly fees: CosmosFeeTable;
|
readonly fees: CosmosFeeTable;
|
||||||
@ -49,6 +60,7 @@ export interface PrivateSigningStargateClient {
|
|||||||
export interface SigningStargateClientOptions {
|
export interface SigningStargateClientOptions {
|
||||||
readonly registry?: Registry;
|
readonly registry?: Registry;
|
||||||
readonly aminoTypes?: AminoTypes;
|
readonly aminoTypes?: AminoTypes;
|
||||||
|
readonly prefix?: string;
|
||||||
readonly gasPrice?: GasPrice;
|
readonly gasPrice?: GasPrice;
|
||||||
readonly gasLimits?: GasLimits<CosmosFeeTable>;
|
readonly gasLimits?: GasLimits<CosmosFeeTable>;
|
||||||
}
|
}
|
||||||
@ -57,7 +69,7 @@ export class SigningStargateClient extends StargateClient {
|
|||||||
private readonly fees: CosmosFeeTable;
|
private readonly fees: CosmosFeeTable;
|
||||||
private readonly registry: Registry;
|
private readonly registry: Registry;
|
||||||
private readonly signer: OfflineSigner;
|
private readonly signer: OfflineSigner;
|
||||||
private readonly aminoTypes;
|
private readonly aminoTypes: AminoTypes;
|
||||||
|
|
||||||
public static async connectWithSigner(
|
public static async connectWithSigner(
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
@ -75,15 +87,8 @@ export class SigningStargateClient extends StargateClient {
|
|||||||
) {
|
) {
|
||||||
super(tmClient);
|
super(tmClient);
|
||||||
const {
|
const {
|
||||||
registry = new Registry([
|
registry = createDefaultRegistry(),
|
||||||
["/cosmos.bank.v1beta1.MsgMultiSend", MsgMultiSend],
|
aminoTypes = new AminoTypes({ prefix: options.prefix }),
|
||||||
["/cosmos.staking.v1beta1.MsgBeginRedelegate", MsgBeginRedelegate],
|
|
||||||
["/cosmos.staking.v1beta1.MsgCreateValidator", MsgCreateValidator],
|
|
||||||
["/cosmos.staking.v1beta1.MsgDelegate", MsgDelegate],
|
|
||||||
["/cosmos.staking.v1beta1.MsgEditValidator", MsgEditValidator],
|
|
||||||
["/cosmos.staking.v1beta1.MsgUndelegate", MsgUndelegate],
|
|
||||||
]),
|
|
||||||
aminoTypes = new AminoTypes(),
|
|
||||||
gasPrice = defaultGasPrice,
|
gasPrice = defaultGasPrice,
|
||||||
gasLimits = defaultGasLimits,
|
gasLimits = defaultGasLimits,
|
||||||
} = options;
|
} = options;
|
||||||
@ -111,19 +116,19 @@ export class SigningStargateClient extends StargateClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async signAndBroadcast(
|
public async signAndBroadcast(
|
||||||
address: string,
|
signerAddress: string,
|
||||||
messages: readonly EncodeObject[],
|
messages: readonly EncodeObject[],
|
||||||
fee: StdFee,
|
fee: StdFee,
|
||||||
memo = "",
|
memo = "",
|
||||||
): Promise<BroadcastTxResponse> {
|
): Promise<BroadcastTxResponse> {
|
||||||
const accountFromSigner = (await this.signer.getAccounts()).find(
|
const accountFromSigner = (await this.signer.getAccounts()).find(
|
||||||
(account: AccountData) => account.address === address,
|
(account: AccountData) => account.address === signerAddress,
|
||||||
);
|
);
|
||||||
if (!accountFromSigner) {
|
if (!accountFromSigner) {
|
||||||
throw new Error("Failed to retrieve account from signer");
|
throw new Error("Failed to retrieve account from signer");
|
||||||
}
|
}
|
||||||
const pubkey = encodeSecp256k1Pubkey(accountFromSigner.pubkey);
|
const pubkey = encodeSecp256k1Pubkey(accountFromSigner.pubkey);
|
||||||
const accountFromChain = await this.getAccount(address);
|
const accountFromChain = await this.getAccount(signerAddress);
|
||||||
if (!accountFromChain) {
|
if (!accountFromChain) {
|
||||||
throw new Error("Account not found");
|
throw new Error("Account not found");
|
||||||
}
|
}
|
||||||
@ -146,7 +151,7 @@ export class SigningStargateClient extends StargateClient {
|
|||||||
if (isOfflineDirectSigner(this.signer)) {
|
if (isOfflineDirectSigner(this.signer)) {
|
||||||
const authInfoBytes = makeAuthInfoBytes([pubkeyAny], fee.amount, gasLimit, sequence);
|
const authInfoBytes = makeAuthInfoBytes([pubkeyAny], fee.amount, gasLimit, sequence);
|
||||||
const signDoc = makeSignDoc(txBodyBytes, authInfoBytes, chainId, accountNumber);
|
const signDoc = makeSignDoc(txBodyBytes, authInfoBytes, chainId, accountNumber);
|
||||||
const { signature, signed } = await this.signer.signDirect(address, signDoc);
|
const { signature, signed } = await this.signer.signDirect(signerAddress, signDoc);
|
||||||
const txRaw = TxRaw.create({
|
const txRaw = TxRaw.create({
|
||||||
bodyBytes: signed.bodyBytes,
|
bodyBytes: signed.bodyBytes,
|
||||||
authInfoBytes: signed.authInfoBytes,
|
authInfoBytes: signed.authInfoBytes,
|
||||||
@ -160,7 +165,7 @@ export class SigningStargateClient extends StargateClient {
|
|||||||
const signMode = cosmos.tx.signing.v1beta1.SignMode.SIGN_MODE_LEGACY_AMINO_JSON;
|
const signMode = cosmos.tx.signing.v1beta1.SignMode.SIGN_MODE_LEGACY_AMINO_JSON;
|
||||||
const msgs = messages.map((msg) => this.aminoTypes.toAmino(msg));
|
const msgs = messages.map((msg) => this.aminoTypes.toAmino(msg));
|
||||||
const signDoc = makeSignDocAmino(msgs, fee, chainId, memo, accountNumber, sequence);
|
const signDoc = makeSignDocAmino(msgs, fee, chainId, memo, accountNumber, sequence);
|
||||||
const { signature, signed } = await this.signer.signAmino(address, signDoc);
|
const { signature, signed } = await this.signer.signAmino(signerAddress, signDoc);
|
||||||
const signedTxBody = {
|
const signedTxBody = {
|
||||||
messages: signed.msgs.map((msg) => this.aminoTypes.fromAmino(msg)),
|
messages: signed.msgs.map((msg) => this.aminoTypes.fromAmino(msg)),
|
||||||
memo: signed.memo,
|
memo: signed.memo,
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
Client as TendermintClient,
|
Client as TendermintClient,
|
||||||
DateTime,
|
DateTime,
|
||||||
} from "@cosmjs/tendermint-rpc";
|
} from "@cosmjs/tendermint-rpc";
|
||||||
import { assert, assertDefined } from "@cosmjs/utils";
|
import { assert, assertDefinedAndNotNull } from "@cosmjs/utils";
|
||||||
import Long from "long";
|
import Long from "long";
|
||||||
|
|
||||||
import { cosmos } from "./codec";
|
import { cosmos } from "./codec";
|
||||||
@ -110,10 +110,8 @@ export function accountFromProto(input: IBaseAccount): Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function coinFromProto(input: ICoin): Coin {
|
export function coinFromProto(input: ICoin): Coin {
|
||||||
assertDefined(input.amount);
|
assertDefinedAndNotNull(input.amount);
|
||||||
assertDefined(input.denom);
|
assertDefinedAndNotNull(input.denom);
|
||||||
assert(input.amount !== null);
|
|
||||||
assert(input.denom !== null);
|
|
||||||
return {
|
return {
|
||||||
amount: input.amount,
|
amount: input.amount,
|
||||||
denom: input.denom,
|
denom: input.denom,
|
||||||
|
2
packages/stargate/types/index.d.ts
vendored
2
packages/stargate/types/index.d.ts
vendored
@ -1,5 +1,5 @@
|
|||||||
export * as codec from "./codec";
|
export * as codec from "./codec";
|
||||||
export { AminoTypes } from "./aminotypes";
|
export { AminoConverter, AminoTypes } from "./aminotypes";
|
||||||
export { parseRawLog } from "./logs";
|
export { parseRawLog } from "./logs";
|
||||||
export {
|
export {
|
||||||
AuthExtension,
|
AuthExtension,
|
||||||
|
@ -10,6 +10,7 @@ export interface PrivateSigningStargateClient {
|
|||||||
export interface SigningStargateClientOptions {
|
export interface SigningStargateClientOptions {
|
||||||
readonly registry?: Registry;
|
readonly registry?: Registry;
|
||||||
readonly aminoTypes?: AminoTypes;
|
readonly aminoTypes?: AminoTypes;
|
||||||
|
readonly prefix?: string;
|
||||||
readonly gasPrice?: GasPrice;
|
readonly gasPrice?: GasPrice;
|
||||||
readonly gasLimits?: GasLimits<CosmosFeeTable>;
|
readonly gasLimits?: GasLimits<CosmosFeeTable>;
|
||||||
}
|
}
|
||||||
@ -31,7 +32,7 @@ export declare class SigningStargateClient extends StargateClient {
|
|||||||
memo?: string,
|
memo?: string,
|
||||||
): Promise<BroadcastTxResponse>;
|
): Promise<BroadcastTxResponse>;
|
||||||
signAndBroadcast(
|
signAndBroadcast(
|
||||||
address: string,
|
signerAddress: string,
|
||||||
messages: readonly EncodeObject[],
|
messages: readonly EncodeObject[],
|
||||||
fee: StdFee,
|
fee: StdFee,
|
||||||
memo?: string,
|
memo?: string,
|
||||||
|
@ -1,52 +1,54 @@
|
|||||||
import { assertDefined } from "./assert";
|
import { assertDefinedAndNotNull } from "./assert";
|
||||||
|
|
||||||
describe("assert", () => {
|
describe("assert", () => {
|
||||||
describe("assertDefined", () => {
|
describe("assertDefinedAndNotNull", () => {
|
||||||
it("passes for simple values", () => {
|
it("passes for simple values", () => {
|
||||||
{
|
{
|
||||||
const value: number | undefined = 123;
|
const value: number | undefined | null = 123;
|
||||||
assertDefined(value);
|
assertDefinedAndNotNull(value);
|
||||||
expect(value).toEqual(123);
|
expect(value).toEqual(123);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const value: string | undefined = "abc";
|
const value: string | undefined | null = "abc";
|
||||||
assertDefined(value);
|
assertDefinedAndNotNull(value);
|
||||||
expect(value).toEqual("abc");
|
expect(value).toEqual("abc");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("passes for falsy values", () => {
|
it("passes for falsy values", () => {
|
||||||
{
|
{
|
||||||
const value: number | undefined = 0;
|
const value: number | undefined | null = 0;
|
||||||
assertDefined(value);
|
assertDefinedAndNotNull(value);
|
||||||
expect(value).toEqual(0);
|
expect(value).toEqual(0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const value: string | undefined = "";
|
const value: string | undefined | null = "";
|
||||||
assertDefined(value);
|
assertDefinedAndNotNull(value);
|
||||||
expect(value).toEqual("");
|
expect(value).toEqual("");
|
||||||
}
|
}
|
||||||
{
|
|
||||||
const value: null | undefined = null;
|
|
||||||
assertDefined(value);
|
|
||||||
expect(value).toEqual(null);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("throws for undefined values", () => {
|
it("throws for undefined values", () => {
|
||||||
{
|
{
|
||||||
const value: number | undefined = undefined;
|
const value: number | undefined | null = undefined;
|
||||||
expect(() => assertDefined(value)).toThrowError("value is undefined");
|
expect(() => assertDefinedAndNotNull(value)).toThrowError("value is undefined or null");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let value: string | undefined;
|
let value: string | undefined | null;
|
||||||
expect(() => assertDefined(value)).toThrowError("value is undefined");
|
expect(() => assertDefinedAndNotNull(value)).toThrowError("value is undefined or null");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("throws for null values", () => {
|
||||||
|
const value: number | undefined | null = null;
|
||||||
|
expect(() => assertDefinedAndNotNull(value)).toThrowError("value is undefined or null");
|
||||||
|
});
|
||||||
|
|
||||||
it("throws with custom message", () => {
|
it("throws with custom message", () => {
|
||||||
const value: number | undefined = undefined;
|
const value: number | undefined = undefined;
|
||||||
expect(() => assertDefined(value, "Bug in the data source")).toThrowError("Bug in the data source");
|
expect(() => assertDefinedAndNotNull(value, "Bug in the data source")).toThrowError(
|
||||||
|
"Bug in the data source",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -5,8 +5,8 @@ export function assert(condition: any, msg?: string): asserts condition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assertDefined<T>(value: T | undefined, msg?: string): asserts value is T {
|
export function assertDefinedAndNotNull<T>(value: T | undefined | null, msg?: string): asserts value is T {
|
||||||
if (value === undefined) {
|
if (value === undefined || value === null) {
|
||||||
throw new Error(msg || "value is undefined");
|
throw new Error(msg ?? "value is undefined or null");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export { arrayContentEquals } from "./arrays";
|
export { arrayContentEquals } from "./arrays";
|
||||||
export { assert, assertDefined } from "./assert";
|
export { assert, assertDefinedAndNotNull } from "./assert";
|
||||||
export { sleep } from "./sleep";
|
export { sleep } from "./sleep";
|
||||||
export { isNonNullObject, isUint8Array } from "./typechecks";
|
export { isNonNullObject, isUint8Array } from "./typechecks";
|
||||||
|
5
packages/utils/types/assert.d.ts
vendored
5
packages/utils/types/assert.d.ts
vendored
@ -1,2 +1,5 @@
|
|||||||
export declare function assert(condition: any, msg?: string): asserts condition;
|
export declare function assert(condition: any, msg?: string): asserts condition;
|
||||||
export declare function assertDefined<T>(value: T | undefined, msg?: string): asserts value is T;
|
export declare function assertDefinedAndNotNull<T>(
|
||||||
|
value: T | undefined | null,
|
||||||
|
msg?: string,
|
||||||
|
): asserts value is T;
|
||||||
|
2
packages/utils/types/index.d.ts
vendored
2
packages/utils/types/index.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
export { arrayContentEquals } from "./arrays";
|
export { arrayContentEquals } from "./arrays";
|
||||||
export { assert, assertDefined } from "./assert";
|
export { assert, assertDefinedAndNotNull } from "./assert";
|
||||||
export { sleep } from "./sleep";
|
export { sleep } from "./sleep";
|
||||||
export { isNonNullObject, isUint8Array } from "./typechecks";
|
export { isNonNullObject, isUint8Array } from "./typechecks";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user