feat: add instantiate2 broadcast

This commit is contained in:
jinseong.cho 2023-04-04 13:49:03 +09:00
parent 849d134302
commit 3ce9005a2b
3 changed files with 132 additions and 0 deletions

View File

@ -3,6 +3,7 @@ import {
MsgClearAdmin,
MsgExecuteContract,
MsgInstantiateContract,
MsgInstantiateContract2,
MsgMigrateContract,
MsgStoreCode,
MsgUpdateAdmin,
@ -14,6 +15,7 @@ export const wasmTypes: ReadonlyArray<[string, GeneratedType]> = [
["/cosmwasm.wasm.v1.MsgMigrateContract", MsgMigrateContract],
["/cosmwasm.wasm.v1.MsgStoreCode", MsgStoreCode],
["/cosmwasm.wasm.v1.MsgInstantiateContract", MsgInstantiateContract],
["/cosmwasm.wasm.v1.MsgInstantiateContract2", MsgInstantiateContract2],
["/cosmwasm.wasm.v1.MsgUpdateAdmin", MsgUpdateAdmin],
];
@ -39,6 +41,19 @@ export function isMsgInstantiateContractEncodeObject(
);
}
export interface MsgInstantiateContract2EncodeObject extends EncodeObject {
readonly typeUrl: "/cosmwasm.wasm.v1.MsgInstantiateContract2";
readonly value: Partial<MsgInstantiateContract2>;
}
export function isMsgInstantiateContract2EncodeObject(
object: EncodeObject,
): object is MsgInstantiateContract2EncodeObject {
return (
(object as MsgInstantiateContract2EncodeObject).typeUrl === "/cosmwasm.wasm.v1.MsgInstantiateContract2"
);
}
export interface MsgUpdateAdminEncodeObject extends EncodeObject {
readonly typeUrl: "/cosmwasm.wasm.v1.MsgUpdateAdmin";
readonly value: Partial<MsgUpdateAdmin>;

View File

@ -23,6 +23,7 @@ import { MsgExecuteContract, MsgStoreCode } from "cosmjs-types/cosmwasm/wasm/v1/
import Long from "long";
import pako from "pako";
import protobuf from "protobufjs/minimal";
import { instantiate2Address } from "./instantiate2";
import { MsgExecuteContractEncodeObject, MsgStoreCodeEncodeObject } from "./modules";
import { SigningCosmWasmClient } from "./signingcosmwasmclient";
@ -250,6 +251,50 @@ describe("SigningCosmWasmClient", () => {
});
});
describe("instantiate2", () => {
it("can instantiate with predictable address", async () => {
pendingWithoutWasmd();
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, {
prefix: wasmd.prefix,
});
const options = { ...defaultSigningClientOptions, prefix: wasmd.prefix };
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, options);
const { codeId } = await client.upload(alice.address0, getHackatom().data, defaultUploadFee);
const funds = [coin(1234, "ucosm"), coin(321, "ustake")];
const beneficiaryAddress = makeRandomAddress();
const salt = Uint8Array.from([0x01]);
const wasm = getHackatom().data;
const msg = {
verifier: alice.address0,
beneficiary: beneficiaryAddress,
};
const expectedAddress = instantiate2Address(sha256(wasm), alice.address0, salt, wasmd.prefix);
const { contractAddress } = await client.instantiate2(
alice.address0,
codeId,
msg,
"My cool label--",
defaultInstantiateFee,
{
memo: "Let's see if the memo is used",
funds: funds,
salt: salt,
},
);
const wasmClient = await makeWasmClient(wasmd.endpoint);
const ucosmBalance = await wasmClient.bank.balance(contractAddress, "ucosm");
const ustakeBalance = await wasmClient.bank.balance(contractAddress, "ustake");
expect(ucosmBalance).toEqual(funds[0]);
expect(ustakeBalance).toEqual(funds[1]);
expect(contractAddress).toEqual(expectedAddress);
client.disconnect();
});
});
describe("updateAdmin", () => {
it("can update an admin", async () => {
pendingWithoutWasmd();

View File

@ -41,6 +41,7 @@ import {
MsgClearAdmin,
MsgExecuteContract,
MsgInstantiateContract,
MsgInstantiateContract2,
MsgMigrateContract,
MsgStoreCode,
MsgUpdateAdmin,
@ -60,6 +61,7 @@ import {
MsgUpdateAdminEncodeObject,
wasmTypes,
} from "./modules";
import { MsgInstantiateContract2EncodeObject } from "./modules/wasm/messages";
export interface UploadResult {
/** Size of the original wasm code in bytes */
@ -103,6 +105,38 @@ export interface InstantiateOptions {
readonly admin?: string;
}
/**
* The options of an .instantiate() call.
* All properties are optional.
*/
export interface Instantiate2Options {
readonly memo?: string;
/**
* The funds that are transferred from the sender to the newly created contract.
* The funds are transferred as part of the message execution after the contract address is
* created and before the instantiation message is executed by the contract.
*
* Only native tokens are supported.
*/
readonly funds?: 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;
/**
* salt is an arbitrary value provided by the sender. Size can be 1 to 64.
*/
readonly salt?: Uint8Array;
/**
* FixMsg include the msg value into the hash for the predictable address.
* Default is false
*/
readonly fixMsg?: boolean;
}
export interface InstantiateResult {
/** The address of the newly instantiated contract */
readonly contractAddress: string;
@ -335,6 +369,44 @@ export class SigningCosmWasmClient extends CosmWasmClient {
};
}
public async instantiate2(
senderAddress: string,
codeId: number,
msg: Record<string, unknown>,
label: string,
fee: StdFee | "auto" | number,
options: Instantiate2Options = {},
): Promise<InstantiateResult> {
const instantiateContract2Msg: MsgInstantiateContract2EncodeObject = {
typeUrl: "/cosmwasm.wasm.v1.MsgInstantiateContract2",
value: MsgInstantiateContract2.fromPartial({
sender: senderAddress,
codeId: Long.fromString(new Uint53(codeId).toString()),
label: label,
msg: toUtf8(JSON.stringify(msg)),
funds: [...(options.funds || [])],
admin: options.admin,
salt: options.salt,
fixMsg: options.fixMsg,
}),
};
const result = await this.signAndBroadcast(senderAddress, [instantiateContract2Msg], fee, options.memo);
if (isDeliverTxFailure(result)) {
throw new Error(createDeliverTxResponseErrorMessage(result));
}
const parsedLogs = logs.parseRawLog(result.rawLog);
const contractAddressAttr = logs.findAttribute(parsedLogs, "instantiate", "_contract_address");
return {
contractAddress: contractAddressAttr.value,
logs: parsedLogs,
height: result.height,
transactionHash: result.transactionHash,
events: result.events,
gasWanted: result.gasWanted,
gasUsed: result.gasUsed,
};
}
public async updateAdmin(
senderAddress: string,
contractAddress: string,