mirror of
https://github.com/cosmos/cosmjs.git
synced 2025-03-10 21:49:15 +00:00
Merge pull request #849 from cosmos/add-cosmwasm-example
Add new CosmWasm/Stargate example for CLI
This commit is contained in:
commit
6d99d32350
@ -159,11 +159,10 @@ jobs:
|
||||
environment:
|
||||
SKIP_BUILD: 1
|
||||
command: |
|
||||
yarn node ./bin/cosmwasm-cli --init examples/coralnet.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/cosmwasm.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/delegate.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/faucet_addresses.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/generate_address.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/helpers.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/local_faucet.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/mask.ts --code "process.exit(0)"
|
||||
- run:
|
||||
|
@ -1,32 +0,0 @@
|
||||
import { HdPath } from "@cosmjs/crypto";
|
||||
import { CosmWasmFeeTable, SigningCosmWasmClient } from "@cosmjs/cosmwasm-launchpad";
|
||||
import { GasPrice, GasLimits, makeCosmoshubPath, Secp256k1HdWallet } from "@cosmjs/launchpad";
|
||||
|
||||
interface Options {
|
||||
readonly httpUrl: string;
|
||||
readonly bech32prefix: string;
|
||||
readonly hdPaths: readonly HdPath[];
|
||||
readonly gasPrice: GasPrice;
|
||||
readonly gasLimits: Partial<GasLimits<CosmWasmFeeTable>>; // only set the ones you want to override
|
||||
}
|
||||
|
||||
const coralnetOptions: Options = {
|
||||
httpUrl: "https://lcd.coralnet.cosmwasm.com",
|
||||
gasPrice: GasPrice.fromString("0.025ushell"),
|
||||
bech32prefix: "coral",
|
||||
hdPaths: [makeCosmoshubPath(0)],
|
||||
gasLimits: {
|
||||
upload: 1500000,
|
||||
},
|
||||
};
|
||||
|
||||
const wallet = await Secp256k1HdWallet.generate(12, coralnetOptions);
|
||||
const [{ address }] = await wallet.getAccounts();
|
||||
|
||||
const client = new SigningCosmWasmClient(
|
||||
coralnetOptions.httpUrl,
|
||||
address,
|
||||
wallet,
|
||||
coralnetOptions.gasPrice,
|
||||
coralnetOptions.gasLimits,
|
||||
);
|
66
packages/cli/examples/cosmwasm.ts
Executable file
66
packages/cli/examples/cosmwasm.ts
Executable file
@ -0,0 +1,66 @@
|
||||
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
|
||||
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
|
||||
import { calculateFee, GasPrice } from "@cosmjs/stargate";
|
||||
import * as fs from "fs";
|
||||
|
||||
const rpcEndpoint = "http://localhost:26659";
|
||||
|
||||
// Example user from scripts/wasmd/README.md
|
||||
const alice = {
|
||||
mnemonic: "enlist hip relief stomach skate base shallow young switch frequent cry park",
|
||||
address0: "wasm14qemq0vw6y3gc3u3e0aty2e764u4gs5lndxgyk",
|
||||
address1: "wasm1hhg2rlu9jscacku2wwckws7932qqqu8xm5ca8y",
|
||||
address2: "wasm1xv9tklw7d82sezh9haa573wufgy59vmwnxhnsl",
|
||||
address3: "wasm17yg9mssjenmc3jkqth6ulcwj9cxujrxxg9nmzk",
|
||||
address4: "wasm1f7j7ryulwjfe9ljplvhtcaxa6wqgula3nh873j",
|
||||
};
|
||||
|
||||
async function main(hackatomWasmPath: string) {
|
||||
const gasPrice = GasPrice.fromString("0.025ucosm");
|
||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: "wasm" });
|
||||
const client = await SigningCosmWasmClient.connectWithSigner(rpcEndpoint, wallet);
|
||||
|
||||
// Upload contract
|
||||
const wasm = fs.readFileSync(hackatomWasmPath);
|
||||
const uploadFee = calculateFee(1_500_000, gasPrice);
|
||||
const codeMeta = {
|
||||
source: "https://crates.io/api/v1/crates/hackatom/not-yet-released/download",
|
||||
builder: "cosmwasm/rust-optimizer:0.10.8",
|
||||
};
|
||||
const uploadReceipt = await client.upload(
|
||||
alice.address0,
|
||||
wasm,
|
||||
uploadFee,
|
||||
codeMeta,
|
||||
"Upload hackatom contract",
|
||||
);
|
||||
console.info("Upload succeeded. Receipt:", uploadReceipt);
|
||||
|
||||
// Instantiate
|
||||
const instantiateFee = calculateFee(500_000, gasPrice);
|
||||
// This contract specific message is passed to the contract
|
||||
const msg = {
|
||||
beneficiary: alice.address1,
|
||||
verifier: alice.address0,
|
||||
};
|
||||
const { contractAddress } = await client.instantiate(
|
||||
alice.address0,
|
||||
uploadReceipt.codeId,
|
||||
msg,
|
||||
"My instance",
|
||||
instantiateFee,
|
||||
{ memo: `Create a hackatom instance` },
|
||||
);
|
||||
console.info(`Contract instantiated at: `, contractAddress);
|
||||
|
||||
// Execute contract
|
||||
const executeFee = calculateFee(300_000, gasPrice);
|
||||
const result = await client.execute(alice.address0, contractAddress, { release: {} }, executeFee);
|
||||
const wasmEvent = result.logs[0].events.find((e) => e.type === "wasm");
|
||||
console.info("The `wasm` event emitted by the contract execution:", wasmEvent);
|
||||
}
|
||||
|
||||
const repoRoot = process.cwd() + "/../.."; // This assumes you are in `packages/cli`
|
||||
const hackatom = `${repoRoot}/scripts/wasmd/contracts/hackatom.wasm`;
|
||||
await main(hackatom);
|
||||
console.info("The show is over.");
|
@ -1,4 +1,12 @@
|
||||
import { coin, coins, makeSignDoc, makeStdTx, CosmosClient, MsgDelegate, Secp256k1HdWallet } from "@cosmjs/launchpad";
|
||||
import {
|
||||
coin,
|
||||
coins,
|
||||
makeSignDoc,
|
||||
makeStdTx,
|
||||
CosmosClient,
|
||||
MsgDelegate,
|
||||
Secp256k1HdWallet,
|
||||
} from "@cosmjs/launchpad";
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(
|
||||
"enlist hip relief stomach skate base shallow young switch frequent cry park",
|
||||
|
@ -1,84 +0,0 @@
|
||||
import axios from "axios";
|
||||
import * as fs from "fs";
|
||||
|
||||
import { Bip39, Random } from "@cosmjs/crypto";
|
||||
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-launchpad";
|
||||
import { logs, GasPrice, Secp256k1HdWallet } from "@cosmjs/launchpad";
|
||||
|
||||
interface Options {
|
||||
httpUrl: string;
|
||||
networkId: string;
|
||||
feeToken: string;
|
||||
gasPrice: number;
|
||||
bech32prefix: string;
|
||||
}
|
||||
|
||||
const defaultOptions: Options = {
|
||||
httpUrl: "https://lcd.demo-10.cosmwasm.com",
|
||||
networkId: "testing",
|
||||
feeToken: "ucosm",
|
||||
gasPrice: 0.025,
|
||||
bech32prefix: "cosmos",
|
||||
};
|
||||
|
||||
const defaultFaucetUrl = "https://faucet.demo-10.cosmwasm.com/credit";
|
||||
|
||||
const connect = async (
|
||||
mnemonic: string,
|
||||
opts: Partial<Options>,
|
||||
): Promise<{
|
||||
client: SigningCosmWasmClient;
|
||||
address: string;
|
||||
}> => {
|
||||
const options: Options = {
|
||||
bech32prefix: opts.bech32prefix ?? defaultOptions.bech32prefix,
|
||||
feeToken: opts.feeToken ?? defaultOptions.feeToken,
|
||||
gasPrice: opts.gasPrice ?? defaultOptions.gasPrice,
|
||||
httpUrl: opts.httpUrl ?? defaultOptions.httpUrl,
|
||||
networkId: opts.networkId ?? defaultOptions.networkId,
|
||||
};
|
||||
const gasPrice = GasPrice.fromString(`${options.gasPrice}${options.feeToken}`);
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(mnemonic);
|
||||
const [{ address }] = await wallet.getAccounts();
|
||||
|
||||
const client = new SigningCosmWasmClient(options.httpUrl, address, wallet, gasPrice);
|
||||
return { client, address };
|
||||
};
|
||||
|
||||
// loadOrCreateMnemonic will try to load a mnemonic from the file.
|
||||
// If missing, it will generate a random one and save to the file.
|
||||
//
|
||||
// This is not secure, but does allow simple developer access to persist a
|
||||
// mnemonic between sessions
|
||||
const loadOrCreateMnemonic = (filename: string): string => {
|
||||
try {
|
||||
const mnemonic = fs.readFileSync(filename, "utf8");
|
||||
return mnemonic.trim();
|
||||
} catch (err) {
|
||||
const mnemonic = Bip39.encode(Random.getBytes(16)).toString();
|
||||
fs.writeFileSync(filename, mnemonic, "utf8");
|
||||
return mnemonic;
|
||||
}
|
||||
};
|
||||
|
||||
const randomAddress = async (prefix: string): Promise<string> => {
|
||||
const mnemonic = Bip39.encode(Random.getBytes(16)).toString();
|
||||
return mnemonicToAddress(prefix, mnemonic);
|
||||
};
|
||||
|
||||
const mnemonicToAddress = async (prefix: string, mnemonic: string): Promise<string> => {
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(mnemonic);
|
||||
const [{ address }] = await wallet.getAccounts();
|
||||
return address;
|
||||
};
|
||||
|
||||
const downloadWasm = async (url: string): Promise<Uint8Array> => {
|
||||
const r = await axios.get(url, { responseType: "arraybuffer" });
|
||||
if (r.status !== 200) {
|
||||
throw new Error(`Download error: ${r.status}`);
|
||||
}
|
||||
return r.data;
|
||||
};
|
||||
|
||||
const getAttibute = (logs: readonly logs.Log[], key: string): string | undefined =>
|
||||
logs[0].events[0].attributes.find((x) => x.key == key)?.value;
|
@ -2,28 +2,28 @@ import { MultisigThresholdPubkey, pubkeyToAddress } from "@cosmjs/amino";
|
||||
|
||||
// https://github.com/cosmos/cosmjs/issues/673#issuecomment-779847238
|
||||
const multisigPubkey: MultisigThresholdPubkey = {
|
||||
"type": "tendermint/PubKeyMultisigThreshold",
|
||||
"value": {
|
||||
"threshold": "3",
|
||||
"pubkeys": [
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "3",
|
||||
pubkeys: [
|
||||
{
|
||||
"type": "tendermint/PubKeySecp256k1",
|
||||
"value": "A4KZH7VSRwW/6RTExROivRYKsQP63LnGcBlXFo+eKGpQ"
|
||||
type: "tendermint/PubKeySecp256k1",
|
||||
value: "A4KZH7VSRwW/6RTExROivRYKsQP63LnGcBlXFo+eKGpQ",
|
||||
},
|
||||
{
|
||||
"type": "tendermint/PubKeySecp256k1",
|
||||
"value": "A8/Cq4VigOnDgl6RSdcx97fjrdCo/qwAX6C34n7ZDZLs"
|
||||
type: "tendermint/PubKeySecp256k1",
|
||||
value: "A8/Cq4VigOnDgl6RSdcx97fjrdCo/qwAX6C34n7ZDZLs",
|
||||
},
|
||||
{
|
||||
"type": "tendermint/PubKeySecp256k1",
|
||||
"value": "ApKgZuwy03xgdRnXqG6yEHATomsWDOPacy7nbpsuUCSS"
|
||||
type: "tendermint/PubKeySecp256k1",
|
||||
value: "ApKgZuwy03xgdRnXqG6yEHATomsWDOPacy7nbpsuUCSS",
|
||||
},
|
||||
{
|
||||
"type": "tendermint/PubKeySecp256k1",
|
||||
"value": "Aptm8E3WSSFS0RTAIUW+bLi/slYnTEE+h4qPTG28CHfq"
|
||||
}
|
||||
]
|
||||
}
|
||||
type: "tendermint/PubKeySecp256k1",
|
||||
value: "Aptm8E3WSSFS0RTAIUW+bLi/slYnTEE+h4qPTG28CHfq",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const address = pubkeyToAddress(multisigPubkey, "cosmos");
|
||||
|
@ -16,6 +16,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier --write --loglevel warn \"./src/**/*.ts\"",
|
||||
"format-examples": "prettier --write --loglevel warn \"./examples/**/*.ts\"",
|
||||
"format-text": "prettier --write \"./*.md\"",
|
||||
"lint": "eslint --max-warnings 0 \"./**/*.ts\" \"./*.js\"",
|
||||
"lint-fix": "eslint --fix --max-warnings 0 \"./**/*.ts\" \"./*.js\"",
|
||||
|
@ -2,13 +2,14 @@
|
||||
set -o errexit -o nounset -o pipefail
|
||||
command -v shellcheck >/dev/null && shellcheck "$0"
|
||||
|
||||
yarn node ./bin/cosmwasm-cli --init examples/coralnet.ts --code "process.exit(0)"
|
||||
if [ -n "${SIMAPP_ENABLED:-}" ]; then
|
||||
yarn node ./bin/cosmwasm-cli --init examples/cosmwasm.ts --code "process.exit(0)"
|
||||
fi
|
||||
if [ -n "${LAUNCHPAD_ENABLED:-}" ]; then
|
||||
yarn node ./bin/cosmwasm-cli --init examples/delegate.ts --code "process.exit(0)"
|
||||
fi
|
||||
yarn node ./bin/cosmwasm-cli --init examples/faucet_addresses.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/generate_address.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/helpers.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/local_faucet.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/mask.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmwasm-cli --init examples/multisig_address.ts --code "process.exit(0)"
|
||||
|
Loading…
x
Reference in New Issue
Block a user