Merge pull request #96 from confio/expose-send

Expose sendToken() on CosmWasmClient
This commit is contained in:
merge-when-green[bot] 2020-02-17 12:14:43 +00:00 committed by GitHub
commit fda2df453f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 129 additions and 75 deletions

View File

@ -222,50 +222,22 @@ describe("CosmWasmClient", () => {
beforeAll(async () => {
if (cosmosEnabled()) {
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
const client = CosmWasmClient.makeReadOnly(httpUrl);
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
const memo = "My first contract on chain";
const sendMsg: MsgSend = {
type: "cosmos-sdk/MsgSend",
value: {
from_address: faucet.address,
to_address: makeRandomAddress(),
amount: [
{
denom: "ucosm",
amount: "1234567",
},
],
const recipient = makeRandomAddress();
const transferAmount = [
{
denom: "ucosm",
amount: "1234567",
},
};
];
const result = await client.sendTokens(recipient, transferAmount);
const fee: StdFee = {
amount: [
{
amount: "5000",
denom: "ucosm",
},
],
gas: "890000",
};
const chainId = await client.chainId();
const { accountNumber, sequence } = await client.getNonce(faucet.address);
const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence);
const signature = await pen.sign(signBytes);
const signedTx = {
msg: [sendMsg],
fee: fee,
memo: memo,
signatures: [signature],
};
const result = await client.postTx(marshalTx(signedTx));
await sleep(50); // wait until tx is indexed
const txDetails = await new RestClient(httpUrl).txsById(result.transactionHash);
posted = {
sender: sendMsg.value.from_address,
recipient: sendMsg.value.to_address,
sender: faucet.address,
recipient: recipient,
hash: result.transactionHash,
height: Number.parseInt(txDetails.height, 10),
tx: txDetails.tx,
@ -446,6 +418,37 @@ describe("CosmWasmClient", () => {
});
});
describe("sendTokens", () => {
it("works", async () => {
pendingWithoutCosmos();
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
const client = CosmWasmClient.makeWritable(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
// instantiate
const transferAmount: readonly Coin[] = [
{
amount: "7890",
denom: "ucosm",
},
];
const beneficiaryAddress = makeRandomAddress();
// no tokens here
const before = await client.getAccount(beneficiaryAddress);
expect(before).toBeUndefined();
// send
const result = await client.sendTokens(beneficiaryAddress, transferAmount, "for dinner");
const [firstLog] = result.logs;
expect(firstLog).toBeTruthy();
// got tokens
const after = await client.getAccount(beneficiaryAddress);
assert(after);
expect(after.coins).toEqual(transferAmount);
});
});
describe("queryContractRaw", () => {
const configKey = toAscii("config");
const otherKey = toAscii("this_does_not_exist");

View File

@ -10,39 +10,40 @@ import {
CosmosSdkTx,
MsgExecuteContract,
MsgInstantiateContract,
MsgSend,
MsgStoreCode,
StdFee,
StdSignature,
} from "./types";
const defaultUploadFee: StdFee = {
amount: [
{
amount: "5000",
denom: "ucosm",
},
],
gas: "1000000", // one million
};
export interface FeeTable {
readonly upload: StdFee;
readonly init: StdFee;
readonly exec: StdFee;
readonly send: StdFee;
}
const defaultInitFee: StdFee = {
amount: [
{
amount: "5000",
denom: "ucosm",
},
],
gas: "500000", // 500k
};
function singleAmount(amount: number, denom: string): readonly Coin[] {
return [{ amount: amount.toString(), denom: denom }];
}
const defaultExecFee: StdFee = {
amount: [
{
amount: "5000",
denom: "ucosm",
},
],
gas: "200000", // 200k
const defaultFees: FeeTable = {
upload: {
amount: singleAmount(25000, "ucosm"),
gas: "1000000", // one million
},
init: {
amount: singleAmount(12500, "ucosm"),
gas: "500000", // 500k
},
exec: {
amount: singleAmount(5000, "ucosm"),
gas: "200000", // 200k
},
send: {
amount: singleAmount(2000, "ucosm"),
gas: "80000", // 80k
},
};
export interface SigningCallback {
@ -98,22 +99,28 @@ export interface ExecuteResult {
export class CosmWasmClient {
public static makeReadOnly(url: string): CosmWasmClient {
return new CosmWasmClient(url);
return new CosmWasmClient(url, undefined, {});
}
public static makeWritable(
url: string,
senderAddress: string,
signCallback: SigningCallback,
feeTable?: Partial<FeeTable>,
): CosmWasmClient {
return new CosmWasmClient(url, {
senderAddress: senderAddress,
signCallback: signCallback,
});
return new CosmWasmClient(
url,
{
senderAddress: senderAddress,
signCallback: signCallback,
},
feeTable || {},
);
}
private readonly restClient: RestClient;
private readonly signingData: SigningData | undefined;
private readonly fees: FeeTable;
private get senderAddress(): string {
if (!this.signingData) throw new Error("Signing data not set in this client");
@ -125,9 +132,10 @@ export class CosmWasmClient {
return this.signingData.signCallback;
}
private constructor(url: string, signingData?: SigningData) {
private constructor(url: string, signingData: SigningData | undefined, customFees: Partial<FeeTable>) {
this.restClient = new RestClient(url);
this.signingData = signingData;
this.fees = { ...defaultFees, ...customFees };
}
public async chainId(): Promise<string> {
@ -234,7 +242,7 @@ export class CosmWasmClient {
builder: "",
},
};
const fee = defaultUploadFee;
const fee = this.fees.upload;
const { accountNumber, sequence } = await this.getNonce();
const chainId = await this.chainId();
const signBytes = makeSignBytes([storeCodeMsg], fee, chainId, memo, accountNumber, sequence);
@ -270,7 +278,7 @@ export class CosmWasmClient {
init_funds: transferAmount || [],
},
};
const fee = defaultInitFee;
const fee = this.fees.init;
const { accountNumber, sequence } = await this.getNonce();
const chainId = await this.chainId();
const signBytes = makeSignBytes([instantiateMsg], fee, chainId, memo, accountNumber, sequence);
@ -304,7 +312,7 @@ export class CosmWasmClient {
sent_funds: transferAmount || [],
},
};
const fee = defaultExecFee;
const fee = this.fees.exec;
const { accountNumber, sequence } = await this.getNonce();
const chainId = await this.chainId();
const signBytes = makeSignBytes([executeMsg], fee, chainId, memo, accountNumber, sequence);
@ -322,6 +330,36 @@ export class CosmWasmClient {
};
}
public async sendTokens(
recipientAddress: string,
transferAmount: readonly Coin[],
memo = "",
): Promise<PostTxResult> {
const sendMsg: MsgSend = {
type: "cosmos-sdk/MsgSend",
value: {
// eslint-disable-next-line @typescript-eslint/camelcase
from_address: this.senderAddress,
// eslint-disable-next-line @typescript-eslint/camelcase
to_address: recipientAddress,
amount: transferAmount,
},
};
const fee = this.fees.send;
const { accountNumber, sequence } = await this.getNonce();
const chainId = await this.chainId();
const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence);
const signature = await this.signCallback(signBytes);
const signedTx = {
msg: [sendMsg],
fee: fee,
memo: memo,
signatures: [signature],
};
return this.postTx(marshalTx(signedTx));
}
/**
* Returns the data at the key if present (raw contract dependent storage data)
* or null if no data at this key.

View File

@ -1,6 +1,12 @@
import { Log } from "./logs";
import { BlockResponse, TxsResponse } from "./restclient";
import { Coin, CosmosSdkAccount, CosmosSdkTx, StdSignature } from "./types";
import { Coin, CosmosSdkAccount, CosmosSdkTx, StdFee, StdSignature } from "./types";
export interface FeeTable {
readonly upload: StdFee;
readonly init: StdFee;
readonly exec: StdFee;
readonly send: StdFee;
}
export interface SigningCallback {
(signBytes: Uint8Array): Promise<StdSignature>;
}
@ -29,9 +35,15 @@ export interface ExecuteResult {
}
export declare class CosmWasmClient {
static makeReadOnly(url: string): CosmWasmClient;
static makeWritable(url: string, senderAddress: string, signCallback: SigningCallback): CosmWasmClient;
static makeWritable(
url: string,
senderAddress: string,
signCallback: SigningCallback,
feeTable?: Partial<FeeTable>,
): CosmWasmClient;
private readonly restClient;
private readonly signingData;
private readonly fees;
private get senderAddress();
private get signCallback();
private constructor();
@ -71,6 +83,7 @@ export declare class CosmWasmClient {
memo?: string,
transferAmount?: readonly Coin[],
): Promise<ExecuteResult>;
sendTokens(recipientAddress: string, transferAmount: readonly Coin[], memo?: string): Promise<PostTxResult>;
/**
* Returns the data at the key if present (raw contract dependent storage data)
* or null if no data at this key.