Upgrade CosmWasm to 0.9 (#245)

* Upgrade chain to v0.9.0-alpha4

* Update expected build_tags

* Update wasmd init contracts

* Update hackatom test contract

* Update CosmWasm message descriptions

* Make some test code more compact

* Pull out InstantiateOptions

* Add admin field to ContractInfo

* Allow instantiating with admin

* Remove some noise

* Add SigningCosmWasmClient.updateAdmin

* Create return type ChangeAdminResult

* Add SigningCosmWasmClient.clearAdmin

* Add SigningCosmWasmClient.migrate

* Move message type testers close to type

* Export MsgUpdateAdmin/isMsgUpdateAdmin

* Fix typo in privillage

* Update some test code

* Test hackatom result data

* Add compatibility table

* Update wasmd to v0.9.0-beta

* Upgrade test contracts
This commit is contained in:
Simon Warta 2020-06-28 08:28:43 +02:00 committed by GitHub
parent 9f7b126044
commit 77980b60f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 547 additions and 102 deletions

View File

@ -4,6 +4,13 @@
An SDK to build CosmWasm clients.
## Compatibility
| CosmJS | CosmWasm | x/wasm |
| ------ | -------- | ------ |
| 0.21 | 0.9 | 0.9 |
| 0.20 | 0.8 | 0.8 |
## License
This package is part of the cosmjs repository, licensed under the Apache License

View File

@ -23,17 +23,25 @@ export {
export {
ExecuteResult,
FeeTable,
InstantiateOptions,
InstantiateResult,
MigrateResult,
SigningCallback,
SigningCosmWasmClient,
UploadMeta,
UploadResult,
} from "./signingcosmwasmclient";
export {
isMsgClearAdmin,
isMsgExecuteContract,
isMsgInstantiateContract,
isMsgMigrateContract,
isMsgUpdateAdmin,
isMsgStoreCode,
MsgStoreCode,
MsgClearAdmin,
MsgExecuteContract,
MsgInstantiateContract,
MsgMigrateContract,
MsgUpdateAdmin,
MsgStoreCode,
} from "./msgs";

View File

@ -1,9 +1,10 @@
import { Coin, Msg } from "@cosmjs/sdk38";
/**
* Uploads Wam code to the chain
* Uploads Wasm code to the chain.
* A numeric, auto-incrementing code ID will be generated as a result of the execution of this message.
*
* @see https://github.com/cosmwasm/wasmd/blob/9842678d89/x/wasm/internal/types/msg.go#L17
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L34
*/
export interface MsgStoreCode extends Msg {
readonly type: "wasm/store-code";
@ -19,10 +20,15 @@ export interface MsgStoreCode extends Msg {
};
}
export function isMsgStoreCode(msg: Msg): msg is MsgStoreCode {
return (msg as MsgStoreCode).type === "wasm/store-code";
}
/**
* Creates an instance of contract that was uploaded before.
* This will trigger a call to the "init" export.
*
* @see https://github.com/cosmwasm/wasmd/blob/9842678d89/x/wasm/internal/types/msg.go#L73
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L104
*/
export interface MsgInstantiateContract extends Msg {
readonly type: "wasm/instantiate";
@ -36,13 +42,60 @@ export interface MsgInstantiateContract extends Msg {
/** Init message as JavaScript object */
readonly init_msg: any;
readonly init_funds: ReadonlyArray<Coin>;
/** Bech32-encoded admin address */
readonly admin?: string;
};
}
export function isMsgInstantiateContract(msg: Msg): msg is MsgInstantiateContract {
return (msg as MsgInstantiateContract).type === "wasm/instantiate";
}
/**
* Creates an instance of contract that was uploaded before.
* Update the admin of a contract
*
* @see https://github.com/cosmwasm/wasmd/blob/9842678d89/x/wasm/internal/types/msg.go#L103
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-beta/x/wasm/internal/types/msg.go#L231
*/
export interface MsgUpdateAdmin extends Msg {
readonly type: "wasm/update-contract-admin";
readonly value: {
/** Bech32-encoded sender address. This must be the old admin. */
readonly sender: string;
/** Bech32-encoded contract address to be updated */
readonly contract: string;
/** Bech32-encoded address of the new admin */
readonly new_admin: string;
};
}
export function isMsgUpdateAdmin(msg: Msg): msg is MsgUpdateAdmin {
return (msg as MsgUpdateAdmin).type === "wasm/update-contract-admin";
}
/**
* Clears the admin of a contract, making it immutable.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-beta/x/wasm/internal/types/msg.go#L269
*/
export interface MsgClearAdmin extends Msg {
readonly type: "wasm/clear-contract-admin";
readonly value: {
/** Bech32-encoded sender address. This must be the old admin. */
readonly sender: string;
/** Bech32-encoded contract address to be updated */
readonly contract: string;
};
}
export function isMsgClearAdmin(msg: Msg): msg is MsgClearAdmin {
return (msg as MsgClearAdmin).type === "wasm/clear-contract-admin";
}
/**
* Execute a smart contract.
* This will trigger a call to the "handle" export.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L158
*/
export interface MsgExecuteContract extends Msg {
readonly type: "wasm/execute";
@ -57,14 +110,29 @@ export interface MsgExecuteContract extends Msg {
};
}
export function isMsgStoreCode(msg: Msg): msg is MsgStoreCode {
return (msg as MsgStoreCode).type === "wasm/store-code";
}
export function isMsgInstantiateContract(msg: Msg): msg is MsgInstantiateContract {
return (msg as MsgInstantiateContract).type === "wasm/instantiate";
}
export function isMsgExecuteContract(msg: Msg): msg is MsgExecuteContract {
return (msg as MsgExecuteContract).type === "wasm/execute";
}
/**
* Migrates a contract to a new Wasm code.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L195
*/
export interface MsgMigrateContract extends Msg {
readonly type: "wasm/migrate";
readonly value: {
/** Bech32 account address */
readonly sender: string;
/** Bech32 account address */
readonly contract: string;
/** The new code */
readonly code_id: string;
/** Migrate message as JavaScript object */
readonly msg: any;
};
}
export function isMsgMigrateContract(msg: Msg): msg is MsgMigrateContract {
return (msg as MsgMigrateContract).type === "wasm/migrate";
}

View File

@ -3,6 +3,8 @@ import { Sha256 } from "@cosmjs/crypto";
import { Bech32, fromAscii, fromBase64, fromHex, toAscii, toBase64, toHex } from "@cosmjs/encoding";
import {
Coin,
coin,
coins,
makeSignBytes,
Msg,
Pen,
@ -119,6 +121,7 @@ async function executeContract(
client: RestClient,
pen: Pen,
contractAddress: string,
msg: object,
): Promise<PostTxsResponse> {
const memo = "Time for action";
const theMsg: MsgExecuteContract = {
@ -126,17 +129,12 @@ async function executeContract(
value: {
sender: alice.address0,
contract: contractAddress,
msg: { release: {} },
msg: msg,
sent_funds: [],
},
};
const fee: StdFee = {
amount: [
{
amount: "5000000",
denom: "ucosm",
},
],
amount: coins(5000000, "ucosm"),
gas: "89000000",
};
@ -261,16 +259,7 @@ describe("RestClient", () => {
const pen = await Secp256k1Pen.fromMnemonic(alice.mnemonic);
const client = new RestClient(wasmd.endpoint);
const transferAmount: readonly Coin[] = [
{
amount: "1234",
denom: "ucosm",
},
{
amount: "321",
denom: "ustake",
},
];
const transferAmount = [coin(1234, "ucosm"), coin(321, "ustake")];
const beneficiaryAddress = makeRandomAddress();
let codeId: number;
@ -308,7 +297,8 @@ describe("RestClient", () => {
// execute
{
const result = await executeContract(client, pen, contractAddress);
const result = await executeContract(client, pen, contractAddress, { release: {} });
expect(result.data).toEqual("F00BAA");
expect(result.code).toBeFalsy();
// console.log("Raw log:", result.logs);
const logs = parseLogs(result.logs);
@ -424,9 +414,16 @@ describe("RestClient", () => {
// check out info
const myInfo = await client.getContractInfo(myAddress);
assert(myInfo);
expect(myInfo.code_id).toEqual(codeId);
expect(myInfo.creator).toEqual(alice.address0);
expect((myInfo.init_msg as any).beneficiary).toEqual(beneficiaryAddress);
expect(myInfo).toEqual(
jasmine.objectContaining({
code_id: codeId,
creator: alice.address0,
init_msg: jasmine.objectContaining({
beneficiary: beneficiaryAddress,
}),
}),
);
expect(myInfo.admin).toBeUndefined();
// make sure random addresses don't give useful info
const nonExistentAddress = makeRandomAddress();

View File

@ -39,6 +39,8 @@ export interface ContractInfo {
readonly code_id: number;
/** Bech32 account address */
readonly creator: string;
/** Bech32-encoded admin address */
readonly admin?: string;
readonly label: string;
}

View File

@ -1,12 +1,12 @@
import { Sha256 } from "@cosmjs/crypto";
import { toHex } from "@cosmjs/encoding";
import { Coin, Secp256k1Pen } from "@cosmjs/sdk38";
import { coin, coins, Secp256k1Pen } from "@cosmjs/sdk38";
import { assert } from "@cosmjs/utils";
import { isPostTxFailure, PrivateCosmWasmClient } from "./cosmwasmclient";
import { RestClient } from "./restclient";
import { SigningCosmWasmClient, UploadMeta } from "./signingcosmwasmclient";
import { alice, getHackatom, makeRandomAddress, pendingWithoutWasmd } from "./testutils.spec";
import { alice, getHackatom, makeRandomAddress, pendingWithoutWasmd, unused } from "./testutils.spec";
const httpUrl = "http://localhost:1317";
@ -82,16 +82,7 @@ describe("SigningCosmWasmClient", () => {
const client = new SigningCosmWasmClient(httpUrl, alice.address0, (signBytes) => pen.sign(signBytes));
const { codeId } = await client.upload(getHackatom().data);
const transferAmount: readonly Coin[] = [
{
amount: "1234",
denom: "ucosm",
},
{
amount: "321",
denom: "ustake",
},
];
const transferAmount = [coin(1234, "ucosm"), coin(321, "ustake")];
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId,
@ -100,8 +91,10 @@ describe("SigningCosmWasmClient", () => {
beneficiary: beneficiaryAddress,
},
"My cool label",
"Let's see if the memo is used",
transferAmount,
{
memo: "Let's see if the memo is used",
transferAmount,
},
);
const rest = new RestClient(httpUrl);
@ -109,6 +102,29 @@ describe("SigningCosmWasmClient", () => {
expect(balance).toEqual(transferAmount);
});
it("works with admin", async () => {
pendingWithoutWasmd();
const pen = await Secp256k1Pen.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(httpUrl, alice.address0, (signBytes) => pen.sign(signBytes));
const { codeId } = await client.upload(getHackatom().data);
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId,
{
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
"My cool label",
{ admin: unused.address },
);
const rest = new RestClient(httpUrl);
const contract = await rest.getContractInfo(contractAddress);
assert(contract);
expect(contract.admin).toEqual(unused.address);
});
it("can instantiate one code multiple times", async () => {
pendingWithoutWasmd();
const pen = await Secp256k1Pen.fromMnemonic(alice.mnemonic);
@ -135,6 +151,111 @@ describe("SigningCosmWasmClient", () => {
});
});
describe("updateAdmin", () => {
it("can update an admin", async () => {
pendingWithoutWasmd();
const pen = await Secp256k1Pen.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(httpUrl, alice.address0, (signBytes) => pen.sign(signBytes));
const { codeId } = await client.upload(getHackatom().data);
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId,
{
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
"My cool label",
{
admin: alice.address0,
},
);
const rest = new RestClient(httpUrl);
const state1 = await rest.getContractInfo(contractAddress);
assert(state1);
expect(state1.admin).toEqual(alice.address0);
await client.updateAdmin(contractAddress, unused.address);
const state2 = await rest.getContractInfo(contractAddress);
assert(state2);
expect(state2.admin).toEqual(unused.address);
});
});
describe("clearAdmin", () => {
it("can clear an admin", async () => {
pendingWithoutWasmd();
const pen = await Secp256k1Pen.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(httpUrl, alice.address0, (signBytes) => pen.sign(signBytes));
const { codeId } = await client.upload(getHackatom().data);
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId,
{
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
"My cool label",
{
admin: alice.address0,
},
);
const rest = new RestClient(httpUrl);
const state1 = await rest.getContractInfo(contractAddress);
assert(state1);
expect(state1.admin).toEqual(alice.address0);
await client.clearAdmin(contractAddress);
const state2 = await rest.getContractInfo(contractAddress);
assert(state2);
expect(state2.admin).toBeUndefined();
});
});
describe("migrate", () => {
it("can can migrate from one code ID to another", async () => {
pendingWithoutWasmd();
const pen = await Secp256k1Pen.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(httpUrl, alice.address0, (signBytes) => pen.sign(signBytes));
const { codeId: codeId1 } = await client.upload(getHackatom().data);
const { codeId: codeId2 } = await client.upload(getHackatom().data);
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId1,
{
verifier: alice.address0,
beneficiary: beneficiaryAddress,
},
"My cool label",
{
admin: alice.address0,
},
);
const rest = new RestClient(httpUrl);
const state1 = await rest.getContractInfo(contractAddress);
assert(state1);
expect(state1.admin).toEqual(alice.address0);
const newVerifier = makeRandomAddress();
await client.migrate(contractAddress, codeId2, { verifier: newVerifier });
const state2 = await rest.getContractInfo(contractAddress);
assert(state2);
expect(state2).toEqual({
...state1,
// eslint-disable-next-line @typescript-eslint/camelcase
code_id: codeId2,
});
});
});
describe("execute", () => {
it("works", async () => {
pendingWithoutWasmd();
@ -143,16 +264,7 @@ describe("SigningCosmWasmClient", () => {
const { codeId } = await client.upload(getHackatom().data);
// instantiate
const transferAmount: readonly Coin[] = [
{
amount: "233444",
denom: "ucosm",
},
{
amount: "5454",
denom: "ustake",
},
];
const transferAmount = [coin(233444, "ucosm"), coin(5454, "ustake")];
const beneficiaryAddress = makeRandomAddress();
const { contractAddress } = await client.instantiate(
codeId,
@ -161,8 +273,9 @@ describe("SigningCosmWasmClient", () => {
beneficiary: beneficiaryAddress,
},
"amazing random contract",
undefined,
transferAmount,
{
transferAmount,
},
);
// execute
@ -191,12 +304,7 @@ describe("SigningCosmWasmClient", () => {
const client = new SigningCosmWasmClient(httpUrl, alice.address0, (signBytes) => pen.sign(signBytes));
// instantiate
const transferAmount: readonly Coin[] = [
{
amount: "7890",
denom: "ucosm",
},
];
const transferAmount = coins(7890, "ucosm");
const beneficiaryAddress = makeRandomAddress();
// no tokens here

View File

@ -23,7 +23,14 @@ import {
PostTxResult,
} from "./cosmwasmclient";
import { findAttribute, Log } from "./logs";
import { MsgExecuteContract, MsgInstantiateContract, MsgStoreCode } from "./msgs";
import {
MsgClearAdmin,
MsgExecuteContract,
MsgInstantiateContract,
MsgMigrateContract,
MsgStoreCode,
MsgUpdateAdmin,
} from "./msgs";
export interface SigningCallback {
(signBytes: Uint8Array): Promise<StdSignature>;
@ -33,7 +40,10 @@ export interface FeeTable {
readonly upload: StdFee;
readonly init: StdFee;
readonly exec: StdFee;
readonly migrate: StdFee;
readonly send: StdFee;
/** Paid when setting the contract admin to a new address or unsetting it */
readonly changeAdmin: StdFee;
}
function prepareBuilder(buider: string | undefined): string {
@ -54,6 +64,10 @@ const defaultFees: FeeTable = {
amount: coins(12500, "ucosm"),
gas: "500000", // 500k
},
migrate: {
amount: coins(5000, "ucosm"),
gas: "200000", // 200k
},
exec: {
amount: coins(5000, "ucosm"),
gas: "200000", // 200k
@ -62,6 +76,10 @@ const defaultFees: FeeTable = {
amount: coins(2000, "ucosm"),
gas: "80000", // 80k
},
changeAdmin: {
amount: coins(2000, "ucosm"),
gas: "80000", // 80k
},
};
export interface UploadMeta {
@ -87,6 +105,20 @@ export interface UploadResult {
readonly transactionHash: string;
}
/**
* The options of an .instantiate() call.
* All properties are optional.
*/
export interface InstantiateOptions {
readonly memo?: string;
readonly transferAmount?: readonly Coin[];
/**
* A bech32 encoded address of an admin account.
* Caution: an admin has the privilege to upgrade a contract. If this is not desired, do not set this value.
*/
readonly admin?: string;
}
export interface InstantiateResult {
/** The address of the newly instantiated contract */
readonly contractAddress: string;
@ -95,6 +127,21 @@ export interface InstantiateResult {
readonly transactionHash: string;
}
/**
* Result type of updateAdmin and clearAdmin
*/
export interface ChangeAdminResult {
readonly logs: readonly Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
export interface MigrateResult {
readonly logs: readonly Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
export interface ExecuteResult {
readonly logs: readonly Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
@ -194,8 +241,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
codeId: number,
initMsg: object,
label: string,
memo = "",
transferAmount?: readonly Coin[],
options: InstantiateOptions = {},
): Promise<InstantiateResult> {
const instantiateMsg: MsgInstantiateContract = {
type: "wasm/instantiate",
@ -207,9 +253,11 @@ export class SigningCosmWasmClient extends CosmWasmClient {
// eslint-disable-next-line @typescript-eslint/camelcase
init_msg: initMsg,
// eslint-disable-next-line @typescript-eslint/camelcase
init_funds: transferAmount || [],
init_funds: options.transferAmount || [],
admin: options.admin,
},
};
const memo = options.memo || "";
const fee = this.fees.init;
const { accountNumber, sequence } = await this.getNonce();
const chainId = await this.getChainId();
@ -235,6 +283,106 @@ export class SigningCosmWasmClient extends CosmWasmClient {
};
}
public async updateAdmin(contractAddress: string, newAdmin: string, memo = ""): Promise<ChangeAdminResult> {
const updateAdminMsg: MsgUpdateAdmin = {
type: "wasm/update-contract-admin",
value: {
sender: this.senderAddress,
contract: contractAddress,
// eslint-disable-next-line @typescript-eslint/camelcase
new_admin: newAdmin,
},
};
const fee = this.fees.changeAdmin;
const { accountNumber, sequence } = await this.getNonce();
const chainId = await this.getChainId();
const signBytes = makeSignBytes([updateAdminMsg], fee, chainId, memo, accountNumber, sequence);
const signature = await this.signCallback(signBytes);
const signedTx: StdTx = {
msg: [updateAdminMsg],
fee: fee,
memo: memo,
signatures: [signature],
};
const result = await this.postTx(signedTx);
if (isPostTxFailure(result)) {
throw new Error(createPostTxErrorMessage(result));
}
return {
logs: result.logs,
transactionHash: result.transactionHash,
};
}
public async clearAdmin(contractAddress: string, memo = ""): Promise<ChangeAdminResult> {
const clearAdminMsg: MsgClearAdmin = {
type: "wasm/clear-contract-admin",
value: {
sender: this.senderAddress,
contract: contractAddress,
},
};
const fee = this.fees.changeAdmin;
const { accountNumber, sequence } = await this.getNonce();
const chainId = await this.getChainId();
const signBytes = makeSignBytes([clearAdminMsg], fee, chainId, memo, accountNumber, sequence);
const signature = await this.signCallback(signBytes);
const signedTx: StdTx = {
msg: [clearAdminMsg],
fee: fee,
memo: memo,
signatures: [signature],
};
const result = await this.postTx(signedTx);
if (isPostTxFailure(result)) {
throw new Error(createPostTxErrorMessage(result));
}
return {
logs: result.logs,
transactionHash: result.transactionHash,
};
}
public async migrate(
contractAddress: string,
codeId: number,
migrateMsg: object,
memo = "",
): Promise<MigrateResult> {
const msg: MsgMigrateContract = {
type: "wasm/migrate",
value: {
sender: this.senderAddress,
contract: contractAddress,
// eslint-disable-next-line @typescript-eslint/camelcase
code_id: new Uint53(codeId).toString(),
msg: migrateMsg,
},
};
const fee = this.fees.migrate;
const { accountNumber, sequence } = await this.getNonce();
const chainId = await this.getChainId();
const signBytes = makeSignBytes([msg], fee, chainId, memo, accountNumber, sequence);
const signature = await this.signCallback(signBytes);
const signedTx: StdTx = {
msg: [msg],
fee: fee,
memo: memo,
signatures: [signature],
};
const result = await this.postTx(signedTx);
if (isPostTxFailure(result)) {
throw new Error(createPostTxErrorMessage(result));
}
return {
logs: result.logs,
transactionHash: result.transactionHash,
};
}
public async execute(
contractAddress: string,
handleMsg: object,

File diff suppressed because one or more lines are too long

View File

@ -31,9 +31,9 @@ export const bech32AddressMatcher = /^[\x21-\x7e]{1,83}1[02-9ac-hj-np-z]{38}$/;
/** Deployed as part of scripts/wasmd/init.sh */
export const deployedErc20 = {
codeId: 1,
source: "https://crates.io/api/v1/crates/cw-erc20/0.4.0/download",
source: "https://crates.io/api/v1/crates/cw-erc20/0.5.1/download",
builder: "cosmwasm/rust-optimizer:0.8.0",
checksum: "41b3bafd7f9a3870bbfb0a0620508df564c52499cdcdc67bf9df72262f3958a6",
checksum: "3e97bf88bd960fee5e5959c77b972eb2927690bc10160792741b174f105ec0c5",
instances: [
"cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", // HASH
"cosmos1hqrdl6wstt8qzshwc6mrumpjk9338k0lr4dqxd", // ISA

View File

@ -22,17 +22,25 @@ export {
export {
ExecuteResult,
FeeTable,
InstantiateOptions,
InstantiateResult,
MigrateResult,
SigningCallback,
SigningCosmWasmClient,
UploadMeta,
UploadResult,
} from "./signingcosmwasmclient";
export {
isMsgClearAdmin,
isMsgExecuteContract,
isMsgInstantiateContract,
isMsgMigrateContract,
isMsgUpdateAdmin,
isMsgStoreCode,
MsgStoreCode,
MsgClearAdmin,
MsgExecuteContract,
MsgInstantiateContract,
MsgMigrateContract,
MsgUpdateAdmin,
MsgStoreCode,
} from "./msgs";

View File

@ -1,8 +1,9 @@
import { Coin, Msg } from "@cosmjs/sdk38";
/**
* Uploads Wam code to the chain
* Uploads Wasm code to the chain.
* A numeric, auto-incrementing code ID will be generated as a result of the execution of this message.
*
* @see https://github.com/cosmwasm/wasmd/blob/9842678d89/x/wasm/internal/types/msg.go#L17
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L34
*/
export interface MsgStoreCode extends Msg {
readonly type: "wasm/store-code";
@ -17,10 +18,12 @@ export interface MsgStoreCode extends Msg {
readonly builder: string;
};
}
export declare function isMsgStoreCode(msg: Msg): msg is MsgStoreCode;
/**
* Creates an instance of contract that was uploaded before.
* This will trigger a call to the "init" export.
*
* @see https://github.com/cosmwasm/wasmd/blob/9842678d89/x/wasm/internal/types/msg.go#L73
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L104
*/
export interface MsgInstantiateContract extends Msg {
readonly type: "wasm/instantiate";
@ -34,12 +37,48 @@ export interface MsgInstantiateContract extends Msg {
/** Init message as JavaScript object */
readonly init_msg: any;
readonly init_funds: ReadonlyArray<Coin>;
/** Bech32-encoded admin address */
readonly admin?: string;
};
}
export declare function isMsgInstantiateContract(msg: Msg): msg is MsgInstantiateContract;
/**
* Creates an instance of contract that was uploaded before.
* Update the admin of a contract
*
* @see https://github.com/cosmwasm/wasmd/blob/9842678d89/x/wasm/internal/types/msg.go#L103
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-beta/x/wasm/internal/types/msg.go#L231
*/
export interface MsgUpdateAdmin extends Msg {
readonly type: "wasm/update-contract-admin";
readonly value: {
/** Bech32-encoded sender address. This must be the old admin. */
readonly sender: string;
/** Bech32-encoded contract address to be updated */
readonly contract: string;
/** Bech32-encoded address of the new admin */
readonly new_admin: string;
};
}
export declare function isMsgUpdateAdmin(msg: Msg): msg is MsgUpdateAdmin;
/**
* Clears the admin of a contract, making it immutable.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-beta/x/wasm/internal/types/msg.go#L269
*/
export interface MsgClearAdmin extends Msg {
readonly type: "wasm/clear-contract-admin";
readonly value: {
/** Bech32-encoded sender address. This must be the old admin. */
readonly sender: string;
/** Bech32-encoded contract address to be updated */
readonly contract: string;
};
}
export declare function isMsgClearAdmin(msg: Msg): msg is MsgClearAdmin;
/**
* Execute a smart contract.
* This will trigger a call to the "handle" export.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L158
*/
export interface MsgExecuteContract extends Msg {
readonly type: "wasm/execute";
@ -53,6 +92,23 @@ export interface MsgExecuteContract extends Msg {
readonly sent_funds: ReadonlyArray<Coin>;
};
}
export declare function isMsgStoreCode(msg: Msg): msg is MsgStoreCode;
export declare function isMsgInstantiateContract(msg: Msg): msg is MsgInstantiateContract;
export declare function isMsgExecuteContract(msg: Msg): msg is MsgExecuteContract;
/**
* Migrates a contract to a new Wasm code.
*
* @see https://github.com/CosmWasm/wasmd/blob/v0.9.0-alpha4/x/wasm/internal/types/msg.go#L195
*/
export interface MsgMigrateContract extends Msg {
readonly type: "wasm/migrate";
readonly value: {
/** Bech32 account address */
readonly sender: string;
/** Bech32 account address */
readonly contract: string;
/** The new code */
readonly code_id: string;
/** Migrate message as JavaScript object */
readonly msg: any;
};
}
export declare function isMsgMigrateContract(msg: Msg): msg is MsgMigrateContract;

View File

@ -18,6 +18,8 @@ export interface ContractInfo {
readonly code_id: number;
/** Bech32 account address */
readonly creator: string;
/** Bech32-encoded admin address */
readonly admin?: string;
readonly label: string;
}
export interface ContractDetails extends ContractInfo {

View File

@ -8,7 +8,10 @@ export interface FeeTable {
readonly upload: StdFee;
readonly init: StdFee;
readonly exec: StdFee;
readonly migrate: StdFee;
readonly send: StdFee;
/** Paid when setting the contract admin to a new address or unsetting it */
readonly changeAdmin: StdFee;
}
export interface UploadMeta {
/** The source URL */
@ -31,6 +34,19 @@ export interface UploadResult {
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
/**
* The options of an .instantiate() call.
* All properties are optional.
*/
export interface InstantiateOptions {
readonly memo?: string;
readonly transferAmount?: readonly Coin[];
/**
* A bech32 encoded address of an admin account.
* Caution: an admin has the privilege to upgrade a contract. If this is not desired, do not set this value.
*/
readonly admin?: string;
}
export interface InstantiateResult {
/** The address of the newly instantiated contract */
readonly contractAddress: string;
@ -38,6 +54,19 @@ export interface InstantiateResult {
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
/**
* Result type of updateAdmin and clearAdmin
*/
export interface ChangeAdminResult {
readonly logs: readonly Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
export interface MigrateResult {
readonly logs: readonly Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
}
export interface ExecuteResult {
readonly logs: readonly Log[];
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
@ -74,9 +103,11 @@ export declare class SigningCosmWasmClient extends CosmWasmClient {
codeId: number,
initMsg: object,
label: string,
memo?: string,
transferAmount?: readonly Coin[],
options?: InstantiateOptions,
): Promise<InstantiateResult>;
updateAdmin(contractAddress: string, newAdmin: string, memo?: string): Promise<ChangeAdminResult>;
clearAdmin(contractAddress: string, memo?: string): Promise<ChangeAdminResult>;
migrate(contractAddress: string, codeId: number, migrateMsg: object, memo?: string): Promise<MigrateResult>;
execute(
contractAddress: string,
handleMsg: object,

View File

@ -192,7 +192,7 @@ describe("RestClient", () => {
client_name: "wasmcli",
version: jasmine.stringMatching(semverMatcher),
commit: jasmine.stringMatching(tendermintShortHashMatcher),
build_tags: "netgo,ledger",
build_tags: "netgo,ledger,muslc",
go: jasmine.stringMatching(/^go version go1\.[0-9]+\.[0-9]+ linux\/amd64$/),
});
});

View File

@ -1,3 +1,3 @@
41b3bafd7f9a3870bbfb0a0620508df564c52499cdcdc67bf9df72262f3958a6 cw-erc20.wasm
f4bba4289d150c0348ec42444fa142edd22ce5a024ad3314405c70314f3eb0fc cw-nameservice.wasm
0f08a890443dbf644f61a7dc3aa7b2a03e9d142dd1b718aa8b7f8a80b886bff1 staking.wasm
3e97bf88bd960fee5e5959c77b972eb2927690bc10160792741b174f105ec0c5 cw-erc20.wasm
851aa8bbc76bc2326a38b99e1432bb06a8ed36442a68e9e676d10ed8beedd1d1 cw-nameservice.wasm
44397b14c9ec35b3188d16b5ed46de2fb6397d7bf2d1f2755a9970054aa7abb0 staking.wasm

Binary file not shown.

View File

@ -22,7 +22,7 @@ const guest = {
};
const codeMeta = {
source: "https://crates.io/api/v1/crates/cw-erc20/0.4.0/download",
source: "https://crates.io/api/v1/crates/cw-erc20/0.5.1/download",
builder: "cosmwasm/rust-optimizer:0.8.0",
};
@ -133,8 +133,9 @@ async function main() {
console.info(`Upload succeeded. Receipt: ${JSON.stringify(uploadReceipt)}`);
for (const initMsg of [initMsgHash, initMsgIsa, initMsgJade]) {
const memo = `Create an ERC20 instance for ${initMsg.symbol}`;
const { contractAddress } = await client.instantiate(uploadReceipt.codeId, initMsg, initMsg.symbol, memo);
const { contractAddress } = await client.instantiate(uploadReceipt.codeId, initMsg, initMsg.symbol, {
memo: `Create an ERC20 instance for ${initMsg.symbol}`,
});
console.info(`Contract instantiated for ${initMsg.symbol} at ${contractAddress}`);
}
}

View File

@ -12,7 +12,7 @@ const alice = {
};
const codeMeta = {
source: "https://crates.io/api/v1/crates/cw-nameservice/0.4.0/download",
source: "https://crates.io/api/v1/crates/cw-nameservice/0.5.1/download",
builder: "cosmwasm/rust-optimizer:0.8.0",
};
@ -44,8 +44,9 @@ async function main() {
console.info(`Upload succeeded. Receipt: ${JSON.stringify(uploadReceipt)}`);
for (const { label, initMsg } of [free, luxury]) {
const memo = `Create an nameservice instance "${label}"`;
const { contractAddress } = await client.instantiate(uploadReceipt.codeId, initMsg, label, memo);
const { contractAddress } = await client.instantiate(uploadReceipt.codeId, initMsg, label, {
memo: `Create an nameservice instance "${label}"`,
});
console.info(`Contract "${label}" instantiated at ${contractAddress}`);
}
}

View File

@ -2,7 +2,7 @@
/* eslint-disable @typescript-eslint/camelcase */
const { SigningCosmWasmClient } = require("@cosmjs/cosmwasm");
const { Secp256k1Pen } = require("@cosmjs/sdk38");
const { coins, Secp256k1Pen } = require("@cosmjs/sdk38");
const fs = require("fs");
const httpUrl = "http://localhost:1317";
@ -30,17 +30,25 @@ const bounty = {
},
};
const fees = {
upload: {
amount: coins(25000, "ucosm"),
gas: "1500000", // 1.5 million
},
};
async function main() {
const pen = await Secp256k1Pen.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(httpUrl, alice.address0, (signBytes) => pen.sign(signBytes));
const client = new SigningCosmWasmClient(httpUrl, alice.address0, (signBytes) => pen.sign(signBytes), fees);
const wasm = fs.readFileSync(__dirname + "/contracts/staking.wasm");
const uploadReceipt = await client.upload(wasm, codeMeta, "Upload Staking code");
console.info(`Upload succeeded. Receipt: ${JSON.stringify(uploadReceipt)}`);
for (const { label, initMsg } of [bounty]) {
const memo = `Create an staking instance "${label}"`;
const { contractAddress } = await client.instantiate(uploadReceipt.codeId, initMsg, label, memo);
const { contractAddress } = await client.instantiate(uploadReceipt.codeId, initMsg, label, {
memo: `Create an staking instance "${label}"`,
});
console.info(`Contract "${label}" instantiated at ${contractAddress}`);
}
}

View File

@ -1,5 +1,5 @@
# Choose from https://hub.docker.com/r/cosmwasm/wasmd-demo/tags
REPOSITORY="cosmwasm/wasmd-demo"
VERSION="v0.8.0"
# Choose from https://hub.docker.com/r/cosmwasm/wasmd/tags
REPOSITORY="cosmwasm/wasmd"
VERSION="v0.9.0-beta"
CONTAINER_NAME="wasmd"