From 8563fe38be98ed82142221db39684b52997a0ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arda=20Nak=C4=B1s=CC=A7c=CC=A7=C4=B1?= Date: Tue, 16 Nov 2021 13:21:23 +0300 Subject: [PATCH 1/3] Refactor code --- contracts/cw4-group/helpers.ts | 149 ++++++--------------------------- 1 file changed, 27 insertions(+), 122 deletions(-) diff --git a/contracts/cw4-group/helpers.ts b/contracts/cw4-group/helpers.ts index ba141841b..eec809663 100644 --- a/contracts/cw4-group/helpers.ts +++ b/contracts/cw4-group/helpers.ts @@ -1,17 +1,11 @@ -import axios from "axios"; -import fs from "fs"; -import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; -import { GasPrice, calculateFee, StdFee } from "@cosmjs/stargate"; -import { DirectSecp256k1HdWallet, makeCosmoshubPath } from "@cosmjs/proto-signing"; -import { Slip10RawIndex } from "@cosmjs/crypto"; -import { toUtf8, toBase64 } from "@cosmjs/encoding"; -import path from "path"; +import { calculateFee } from "@cosmjs/stargate" /* * This is a set of helpers meant for use with @cosmjs/cli + * Look at https://raw.githubusercontent.com/CosmWasm/cw-plus/master/contracts/base-helpers.ts on how to setup a wallet * With these you can easily use the cw20 contract without worrying about forming messages and parsing queries. * - * Usage: npx @cosmjs/cli@^0.26 --init https://raw.githubusercontent.com/CosmWasm/cw-plus/master/contracts/cw4-group/helpers.ts + * Usage: npx @cosmjs/cli@^0.26 --init https://raw.githubusercontent.com/CosmWasm/cw-plus/master/contracts/base-helpers.ts --init https://raw.githubusercontent.com/CosmWasm/cw-plus/master/contracts/cw4-group/helpers.ts * * Create a client: * const [addr, client] = await useOptions(pebblenetOptions).setup('password'); @@ -20,10 +14,10 @@ import path from "path"; * await useOptions(pebblenetOptions).recoverMnemonic(password); * * Create contract: - * const contract = CW4Group(client, pebblenetOptions.fees); + * const contract = CW4Group(client, pebblenetOptions); * * Upload contract: - * const codeId = await contract.upload(addr); + * const codeId = await contract.upload(addr, pebblenetOptions); * * Instantiate contract example: * const initMsg = { @@ -39,110 +33,11 @@ import path from "path"; * }, * ] * }; - * const instance = await contract.instantiate(addr, codeId, initMsg, 'WORKFORCE1'); + * const instance = await contract.instantiate(addr, codeId, initMsg, 'Potato Coin!', pebblenetOptions); * * If you want to use this code inside an app, you will need several imports from https://github.com/CosmWasm/cosmjs */ -interface Options { - readonly httpUrl: string - readonly networkId: string - readonly feeToken: string - readonly bech32prefix: string - readonly hdPath: readonly Slip10RawIndex[] - readonly faucetUrl?: string - readonly defaultKeyFile: string, - readonly fees: { - upload: StdFee, - init: StdFee, - exec: StdFee - } -} - -const pebblenetGasPrice = GasPrice.fromString("0.01upebble"); -const pebblenetOptions: Options = { - httpUrl: 'https://rpc.pebblenet.cosmwasm.com', - networkId: 'pebblenet-1', - bech32prefix: 'wasm', - feeToken: 'upebble', - faucetUrl: 'https://faucet.pebblenet.cosmwasm.com/credit', - hdPath: makeCosmoshubPath(0), - defaultKeyFile: path.join(process.env.HOME, ".pebblenet.key"), - fees: { - upload: calculateFee(1500000, pebblenetGasPrice), - init: calculateFee(500000, pebblenetGasPrice), - exec: calculateFee(200000, pebblenetGasPrice), - }, -} - -interface Network { - setup: (password: string, filename?: string) => Promise<[string, SigningCosmWasmClient]> - recoverMnemonic: (password: string, filename?: string) => Promise -} - -const useOptions = (options: Options): Network => { - - const loadOrCreateWallet = async (options: Options, filename: string, password: string): Promise => { - let encrypted: string; - try { - encrypted = fs.readFileSync(filename, 'utf8'); - } catch (err) { - // generate if no file exists - const wallet = await DirectSecp256k1HdWallet.generate(12, {hdPaths: [options.hdPath], prefix: options.bech32prefix}); - const encrypted = await wallet.serialize(password); - fs.writeFileSync(filename, encrypted, 'utf8'); - return wallet; - } - // otherwise, decrypt the file (we cannot put deserialize inside try or it will over-write on a bad password) - const wallet = await DirectSecp256k1HdWallet.deserialize(encrypted, password); - return wallet; - }; - - const connect = async ( - wallet: DirectSecp256k1HdWallet, - options: Options - ): Promise => { - const clientOptions = { - prefix: options.bech32prefix - } - return await SigningCosmWasmClient.connectWithSigner(options.httpUrl, wallet, clientOptions) - }; - - const hitFaucet = async ( - faucetUrl: string, - address: string, - denom: string - ): Promise => { - await axios.post(faucetUrl, {denom, address}); - } - - const setup = async (password: string, filename?: string): Promise<[string, SigningCosmWasmClient]> => { - const keyfile = filename || options.defaultKeyFile; - const wallet = await loadOrCreateWallet(pebblenetOptions, keyfile, password); - const client = await connect(wallet, pebblenetOptions); - - const [account] = await wallet.getAccounts(); - // ensure we have some tokens - if (options.faucetUrl) { - const tokens = await client.getBalance(account.address, options.feeToken) - if (tokens.amount === '0') { - console.log(`Getting ${options.feeToken} from faucet`); - await hitFaucet(options.faucetUrl, account.address, options.feeToken); - } - } - - return [account.address, client]; - } - - const recoverMnemonic = async (password: string, filename?: string): Promise => { - const keyfile = filename || options.defaultKeyFile; - const wallet = await loadOrCreateWallet(pebblenetOptions, keyfile, password); - return wallet.mnemonic; - } - - return {setup, recoverMnemonic}; -} - interface AdminResponse { readonly admin?: string } @@ -188,12 +83,12 @@ interface CW4GroupInstance { } interface CW4GroupContract { - upload: (txSigner: string) => Promise - instantiate: (txSigner: string, codeId: number, initMsg: Record, label: string, admin?: string) => Promise + upload: (txSigner: string, options: Options) => Promise + instantiate: (txSigner: string, codeId: number, initMsg: Record, label: string, options: Options, admin?: string) => Promise use: (contractAddress: string) => CW4GroupInstance } -export const CW4Group = (client: SigningCosmWasmClient, fees: Options['fees']): CW4GroupContract => { +export const CW4Group = (client: SigningCosmWasmClient, options: Options): CW4GroupContract => { const use = (contractAddress: string): CW4GroupInstance => { const admin = async (): Promise => { @@ -217,22 +112,30 @@ export const CW4Group = (client: SigningCosmWasmClient, fees: Options['fees']): }; const updateAdmin = async (txSigner: string, admin?: string): Promise => { - const result = await client.execute(txSigner, contractAddress, {update_admin: {admin}}, fees.exec); + const fee = calculateFee(options.fees.exec, options.gasPrice) + + const result = await client.execute(txSigner, contractAddress, {update_admin: {admin}}, fee); return result.transactionHash; } const updateMembers = async (txSigner: string, remove: Member[], add: Member[]): Promise => { - const result = await client.execute(txSigner, contractAddress, {update_members: {remove, add}}, fees.exec); + const fee = calculateFee(options.fees.exec, options.gasPrice) + + const result = await client.execute(txSigner, contractAddress, {update_members: {remove, add}}, fee); return result.transactionHash; } const _addHook = async (txSigner: string, addr: string): Promise => { - const result = await client.execute(txSigner, contractAddress, {add_hook: {addr}}, fees.exec); + const fee = calculateFee(options.fees.exec, options.gasPrice) + + const result = await client.execute(txSigner, contractAddress, {add_hook: {addr}}, fee); return result.transactionHash; } const _removeHook = async (txSigner: string, addr: string): Promise => { - const result = await client.execute(txSigner, contractAddress, {remove_hook: {addr}}, fees.exec); + const fee = calculateFee(options.fees.exec, options.gasPrice) + + const result = await client.execute(txSigner, contractAddress, {remove_hook: {addr}}, fee); return result.transactionHash; } @@ -258,15 +161,17 @@ export const CW4Group = (client: SigningCosmWasmClient, fees: Options['fees']): return r.data } - const upload = async (senderAddress: string): Promise => { + const upload = async (senderAddress: string, options: Options): Promise => { const sourceUrl = "https://github.com/CosmWasm/cosmwasm-plus/releases/download/v0.9.0/cw4_group.wasm"; const wasm = await downloadWasm(sourceUrl); - const result = await client.upload(senderAddress, wasm, fees.upload); + const fee = calculateFee(options.fees.upload, options.gasPrice) + const result = await client.upload(senderAddress, wasm, fee); return result.codeId; } - const instantiate = async (senderAddress: string, codeId: number, initMsg: Record, label: string, admin?: string): Promise => { - const result = await client.instantiate(senderAddress, codeId, initMsg, label, fees.init, { memo: `Init ${label}`, admin }); + const instantiate = async (senderAddress: string, codeId: number, initMsg: Record, label: string, options: Options, admin?: string): Promise => { + const fee = calculateFee(options.fees.init, options.gasPrice) + const result = await client.instantiate(senderAddress, codeId, initMsg, label, fee, { memo: `Init ${label}`, admin }); return use(result.contractAddress); } From 98c907496cbf1e17948bc2f69257d2c62c5fd6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arda=20Nak=C4=B1s=CC=A7c=CC=A7=C4=B1?= Date: Tue, 16 Nov 2021 13:21:45 +0300 Subject: [PATCH 2/3] Lint code --- contracts/cw4-group/helpers.ts | 94 ++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/contracts/cw4-group/helpers.ts b/contracts/cw4-group/helpers.ts index eec809663..c0a2b94ff 100644 --- a/contracts/cw4-group/helpers.ts +++ b/contracts/cw4-group/helpers.ts @@ -36,31 +36,31 @@ import { calculateFee } from "@cosmjs/stargate" * const instance = await contract.instantiate(addr, codeId, initMsg, 'Potato Coin!', pebblenetOptions); * * If you want to use this code inside an app, you will need several imports from https://github.com/CosmWasm/cosmjs -*/ + */ interface AdminResponse { readonly admin?: string } interface MemberResponse { - readonly weight?: number; + readonly weight?: number } interface MemberListResponse { - readonly members: Member[]; + readonly members: Member[] } interface Member { - readonly addr: string; - readonly weight: number; + readonly addr: string + readonly weight: number } interface TotalWeightResponse { - readonly weight: number; + readonly weight: number } interface HooksResponse { - readonly hooks: readonly string[]; + readonly hooks: readonly string[] } interface CW4GroupInstance { @@ -75,7 +75,7 @@ interface CW4GroupInstance { // actions updateAdmin: (txSigner: string, admin?: string) => Promise - updateMembers: (txSigner: string, remove: Member[], add: Member[] ) => Promise + updateMembers: (txSigner: string, remove: Member[], add: Member[]) => Promise // will not used by end user for testing purposes _addHook: (txSigner: string, addr: string) => Promise @@ -84,59 +84,65 @@ interface CW4GroupInstance { interface CW4GroupContract { upload: (txSigner: string, options: Options) => Promise - instantiate: (txSigner: string, codeId: number, initMsg: Record, label: string, options: Options, admin?: string) => Promise + instantiate: ( + txSigner: string, + codeId: number, + initMsg: Record, + label: string, + options: Options, + admin?: string, + ) => Promise use: (contractAddress: string) => CW4GroupInstance } export const CW4Group = (client: SigningCosmWasmClient, options: Options): CW4GroupContract => { const use = (contractAddress: string): CW4GroupInstance => { - const admin = async (): Promise => { - return client.queryContractSmart(contractAddress, {admin: {}}); - }; + return client.queryContractSmart(contractAddress, { admin: {} }) + } const totalWeight = async (): Promise => { - return client.queryContractSmart(contractAddress, {total_weight: {}}); - }; + return client.queryContractSmart(contractAddress, { total_weight: {} }) + } const member = async (addr: string, atHeight?: number): Promise => { - return client.queryContractSmart(contractAddress, {member: {addr, at_height: atHeight}}); - }; + return client.queryContractSmart(contractAddress, { member: { addr, at_height: atHeight } }) + } const listMembers = async (startAfter?: string, limit?: number): Promise => { - return client.queryContractSmart(contractAddress, {list_members: {start_after: startAfter, limit}}); - }; + return client.queryContractSmart(contractAddress, { list_members: { start_after: startAfter, limit } }) + } const hooks = async (): Promise => { - return client.queryContractSmart(contractAddress, {hooks: {}}); - }; + return client.queryContractSmart(contractAddress, { hooks: {} }) + } const updateAdmin = async (txSigner: string, admin?: string): Promise => { const fee = calculateFee(options.fees.exec, options.gasPrice) - const result = await client.execute(txSigner, contractAddress, {update_admin: {admin}}, fee); - return result.transactionHash; + const result = await client.execute(txSigner, contractAddress, { update_admin: { admin } }, fee) + return result.transactionHash } const updateMembers = async (txSigner: string, remove: Member[], add: Member[]): Promise => { const fee = calculateFee(options.fees.exec, options.gasPrice) - const result = await client.execute(txSigner, contractAddress, {update_members: {remove, add}}, fee); - return result.transactionHash; + const result = await client.execute(txSigner, contractAddress, { update_members: { remove, add } }, fee) + return result.transactionHash } const _addHook = async (txSigner: string, addr: string): Promise => { const fee = calculateFee(options.fees.exec, options.gasPrice) - const result = await client.execute(txSigner, contractAddress, {add_hook: {addr}}, fee); - return result.transactionHash; + const result = await client.execute(txSigner, contractAddress, { add_hook: { addr } }, fee) + return result.transactionHash } const _removeHook = async (txSigner: string, addr: string): Promise => { const fee = calculateFee(options.fees.exec, options.gasPrice) - const result = await client.execute(txSigner, contractAddress, {remove_hook: {addr}}, fee); - return result.transactionHash; + const result = await client.execute(txSigner, contractAddress, { remove_hook: { addr } }, fee) + return result.transactionHash } return { @@ -149,12 +155,12 @@ export const CW4Group = (client: SigningCosmWasmClient, options: Options): CW4Gr updateAdmin, updateMembers, _addHook, - _removeHook - }; + _removeHook, + } } const downloadWasm = async (url: string): Promise => { - const r = await axios.get(url, { responseType: 'arraybuffer' }) + const r = await axios.get(url, { responseType: "arraybuffer" }) if (r.status !== 200) { throw new Error(`Download error: ${r.status}`) } @@ -162,18 +168,28 @@ export const CW4Group = (client: SigningCosmWasmClient, options: Options): CW4Gr } const upload = async (senderAddress: string, options: Options): Promise => { - const sourceUrl = "https://github.com/CosmWasm/cosmwasm-plus/releases/download/v0.9.0/cw4_group.wasm"; - const wasm = await downloadWasm(sourceUrl); + const sourceUrl = "https://github.com/CosmWasm/cosmwasm-plus/releases/download/v0.9.0/cw4_group.wasm" + const wasm = await downloadWasm(sourceUrl) const fee = calculateFee(options.fees.upload, options.gasPrice) - const result = await client.upload(senderAddress, wasm, fee); - return result.codeId; + const result = await client.upload(senderAddress, wasm, fee) + return result.codeId } - const instantiate = async (senderAddress: string, codeId: number, initMsg: Record, label: string, options: Options, admin?: string): Promise => { + const instantiate = async ( + senderAddress: string, + codeId: number, + initMsg: Record, + label: string, + options: Options, + admin?: string, + ): Promise => { const fee = calculateFee(options.fees.init, options.gasPrice) - const result = await client.instantiate(senderAddress, codeId, initMsg, label, fee, { memo: `Init ${label}`, admin }); - return use(result.contractAddress); + const result = await client.instantiate(senderAddress, codeId, initMsg, label, fee, { + memo: `Init ${label}`, + admin, + }) + return use(result.contractAddress) } - return { upload, instantiate, use }; + return { upload, instantiate, use } } From d1cfa66ae4d0e6e26b1d0766a138952b699cc0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arda=20Nak=C4=B1s=CC=A7c=CC=A7=C4=B1?= Date: Fri, 19 Nov 2021 10:16:20 +0300 Subject: [PATCH 3/3] Update wasm binary version and example code --- contracts/cw4-group/helpers.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/contracts/cw4-group/helpers.ts b/contracts/cw4-group/helpers.ts index c0a2b94ff..f22aec27f 100644 --- a/contracts/cw4-group/helpers.ts +++ b/contracts/cw4-group/helpers.ts @@ -8,32 +8,32 @@ import { calculateFee } from "@cosmjs/stargate" * Usage: npx @cosmjs/cli@^0.26 --init https://raw.githubusercontent.com/CosmWasm/cw-plus/master/contracts/base-helpers.ts --init https://raw.githubusercontent.com/CosmWasm/cw-plus/master/contracts/cw4-group/helpers.ts * * Create a client: - * const [addr, client] = await useOptions(pebblenetOptions).setup('password'); + * const [addr, client] = await useOptions(uniOptions).setup('password'); * * Get the mnemonic: - * await useOptions(pebblenetOptions).recoverMnemonic(password); + * await useOptions(uniOptions).recoverMnemonic(password); * * Create contract: - * const contract = CW4Group(client, pebblenetOptions); + * const contract = CW4Group(client, uniOptions); * * Upload contract: - * const codeId = await contract.upload(addr, pebblenetOptions); + * const codeId = await contract.upload(addr, uniOptions); * * Instantiate contract example: * const initMsg = { * admin: addr, * members: [ * { - * addr: "wasm1hkxhcvw6sfyu6ztkce3dlz5nnk8kwjmcd7ettt", + * addr: "juno17r7l8v2nlxpf53p4zgdlq9trw0ndw5x3jp98yh", * weight: 10, * }, * { - * addr: "wasm1z6ms6cejaj8jz8zwkntx9ua0klhtptvz8elaxp", + * addr: "juno10h52xd7gec64zp6ct6qfu3lhhnuv4lgz7srs8g", * weight: 15, * }, * ] * }; - * const instance = await contract.instantiate(addr, codeId, initMsg, 'Potato Coin!', pebblenetOptions); + * const instance = await contract.instantiate(addr, codeId, initMsg, 'Potato Coin!', uniOptions); * * If you want to use this code inside an app, you will need several imports from https://github.com/CosmWasm/cosmjs */ @@ -168,7 +168,7 @@ export const CW4Group = (client: SigningCosmWasmClient, options: Options): CW4Gr } const upload = async (senderAddress: string, options: Options): Promise => { - const sourceUrl = "https://github.com/CosmWasm/cosmwasm-plus/releases/download/v0.9.0/cw4_group.wasm" + const sourceUrl = "https://github.com/CosmWasm/cw-plus/releases/download/v0.10.2/cw4_group.wasm" const wasm = await downloadWasm(sourceUrl) const fee = calculateFee(options.fees.upload, options.gasPrice) const result = await client.upload(senderAddress, wasm, fee)