Merge pull request #96 from confio/expose-send
Expose sendToken() on CosmWasmClient
This commit is contained in:
@@ -222,50 +222,22 @@ describe("CosmWasmClient", () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
if (cosmosEnabled()) {
|
if (cosmosEnabled()) {
|
||||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
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 recipient = makeRandomAddress();
|
||||||
const sendMsg: MsgSend = {
|
const transferAmount = [
|
||||||
type: "cosmos-sdk/MsgSend",
|
{
|
||||||
value: {
|
denom: "ucosm",
|
||||||
from_address: faucet.address,
|
amount: "1234567",
|
||||||
to_address: makeRandomAddress(),
|
|
||||||
amount: [
|
|
||||||
{
|
|
||||||
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
|
await sleep(50); // wait until tx is indexed
|
||||||
const txDetails = await new RestClient(httpUrl).txsById(result.transactionHash);
|
const txDetails = await new RestClient(httpUrl).txsById(result.transactionHash);
|
||||||
posted = {
|
posted = {
|
||||||
sender: sendMsg.value.from_address,
|
sender: faucet.address,
|
||||||
recipient: sendMsg.value.to_address,
|
recipient: recipient,
|
||||||
hash: result.transactionHash,
|
hash: result.transactionHash,
|
||||||
height: Number.parseInt(txDetails.height, 10),
|
height: Number.parseInt(txDetails.height, 10),
|
||||||
tx: txDetails.tx,
|
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", () => {
|
describe("queryContractRaw", () => {
|
||||||
const configKey = toAscii("config");
|
const configKey = toAscii("config");
|
||||||
const otherKey = toAscii("this_does_not_exist");
|
const otherKey = toAscii("this_does_not_exist");
|
||||||
|
|||||||
@@ -10,39 +10,40 @@ import {
|
|||||||
CosmosSdkTx,
|
CosmosSdkTx,
|
||||||
MsgExecuteContract,
|
MsgExecuteContract,
|
||||||
MsgInstantiateContract,
|
MsgInstantiateContract,
|
||||||
|
MsgSend,
|
||||||
MsgStoreCode,
|
MsgStoreCode,
|
||||||
StdFee,
|
StdFee,
|
||||||
StdSignature,
|
StdSignature,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
const defaultUploadFee: StdFee = {
|
export interface FeeTable {
|
||||||
amount: [
|
readonly upload: StdFee;
|
||||||
{
|
readonly init: StdFee;
|
||||||
amount: "5000",
|
readonly exec: StdFee;
|
||||||
denom: "ucosm",
|
readonly send: StdFee;
|
||||||
},
|
}
|
||||||
],
|
|
||||||
gas: "1000000", // one million
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultInitFee: StdFee = {
|
function singleAmount(amount: number, denom: string): readonly Coin[] {
|
||||||
amount: [
|
return [{ amount: amount.toString(), denom: denom }];
|
||||||
{
|
}
|
||||||
amount: "5000",
|
|
||||||
denom: "ucosm",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
gas: "500000", // 500k
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultExecFee: StdFee = {
|
const defaultFees: FeeTable = {
|
||||||
amount: [
|
upload: {
|
||||||
{
|
amount: singleAmount(25000, "ucosm"),
|
||||||
amount: "5000",
|
gas: "1000000", // one million
|
||||||
denom: "ucosm",
|
},
|
||||||
},
|
init: {
|
||||||
],
|
amount: singleAmount(12500, "ucosm"),
|
||||||
gas: "200000", // 200k
|
gas: "500000", // 500k
|
||||||
|
},
|
||||||
|
exec: {
|
||||||
|
amount: singleAmount(5000, "ucosm"),
|
||||||
|
gas: "200000", // 200k
|
||||||
|
},
|
||||||
|
send: {
|
||||||
|
amount: singleAmount(2000, "ucosm"),
|
||||||
|
gas: "80000", // 80k
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface SigningCallback {
|
export interface SigningCallback {
|
||||||
@@ -98,22 +99,28 @@ export interface ExecuteResult {
|
|||||||
|
|
||||||
export class CosmWasmClient {
|
export class CosmWasmClient {
|
||||||
public static makeReadOnly(url: string): CosmWasmClient {
|
public static makeReadOnly(url: string): CosmWasmClient {
|
||||||
return new CosmWasmClient(url);
|
return new CosmWasmClient(url, undefined, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static makeWritable(
|
public static makeWritable(
|
||||||
url: string,
|
url: string,
|
||||||
senderAddress: string,
|
senderAddress: string,
|
||||||
signCallback: SigningCallback,
|
signCallback: SigningCallback,
|
||||||
|
feeTable?: Partial<FeeTable>,
|
||||||
): CosmWasmClient {
|
): CosmWasmClient {
|
||||||
return new CosmWasmClient(url, {
|
return new CosmWasmClient(
|
||||||
senderAddress: senderAddress,
|
url,
|
||||||
signCallback: signCallback,
|
{
|
||||||
});
|
senderAddress: senderAddress,
|
||||||
|
signCallback: signCallback,
|
||||||
|
},
|
||||||
|
feeTable || {},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly restClient: RestClient;
|
private readonly restClient: RestClient;
|
||||||
private readonly signingData: SigningData | undefined;
|
private readonly signingData: SigningData | undefined;
|
||||||
|
private readonly fees: FeeTable;
|
||||||
|
|
||||||
private get senderAddress(): string {
|
private get senderAddress(): string {
|
||||||
if (!this.signingData) throw new Error("Signing data not set in this client");
|
if (!this.signingData) throw new Error("Signing data not set in this client");
|
||||||
@@ -125,9 +132,10 @@ export class CosmWasmClient {
|
|||||||
return this.signingData.signCallback;
|
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.restClient = new RestClient(url);
|
||||||
this.signingData = signingData;
|
this.signingData = signingData;
|
||||||
|
this.fees = { ...defaultFees, ...customFees };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async chainId(): Promise<string> {
|
public async chainId(): Promise<string> {
|
||||||
@@ -234,7 +242,7 @@ export class CosmWasmClient {
|
|||||||
builder: "",
|
builder: "",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const fee = defaultUploadFee;
|
const fee = this.fees.upload;
|
||||||
const { accountNumber, sequence } = await this.getNonce();
|
const { accountNumber, sequence } = await this.getNonce();
|
||||||
const chainId = await this.chainId();
|
const chainId = await this.chainId();
|
||||||
const signBytes = makeSignBytes([storeCodeMsg], fee, chainId, memo, accountNumber, sequence);
|
const signBytes = makeSignBytes([storeCodeMsg], fee, chainId, memo, accountNumber, sequence);
|
||||||
@@ -270,7 +278,7 @@ export class CosmWasmClient {
|
|||||||
init_funds: transferAmount || [],
|
init_funds: transferAmount || [],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const fee = defaultInitFee;
|
const fee = this.fees.init;
|
||||||
const { accountNumber, sequence } = await this.getNonce();
|
const { accountNumber, sequence } = await this.getNonce();
|
||||||
const chainId = await this.chainId();
|
const chainId = await this.chainId();
|
||||||
const signBytes = makeSignBytes([instantiateMsg], fee, chainId, memo, accountNumber, sequence);
|
const signBytes = makeSignBytes([instantiateMsg], fee, chainId, memo, accountNumber, sequence);
|
||||||
@@ -304,7 +312,7 @@ export class CosmWasmClient {
|
|||||||
sent_funds: transferAmount || [],
|
sent_funds: transferAmount || [],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const fee = defaultExecFee;
|
const fee = this.fees.exec;
|
||||||
const { accountNumber, sequence } = await this.getNonce();
|
const { accountNumber, sequence } = await this.getNonce();
|
||||||
const chainId = await this.chainId();
|
const chainId = await this.chainId();
|
||||||
const signBytes = makeSignBytes([executeMsg], fee, chainId, memo, accountNumber, sequence);
|
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)
|
* Returns the data at the key if present (raw contract dependent storage data)
|
||||||
* or null if no data at this key.
|
* or null if no data at this key.
|
||||||
|
|||||||
+15
-2
@@ -1,6 +1,12 @@
|
|||||||
import { Log } from "./logs";
|
import { Log } from "./logs";
|
||||||
import { BlockResponse, TxsResponse } from "./restclient";
|
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 {
|
export interface SigningCallback {
|
||||||
(signBytes: Uint8Array): Promise<StdSignature>;
|
(signBytes: Uint8Array): Promise<StdSignature>;
|
||||||
}
|
}
|
||||||
@@ -29,9 +35,15 @@ export interface ExecuteResult {
|
|||||||
}
|
}
|
||||||
export declare class CosmWasmClient {
|
export declare class CosmWasmClient {
|
||||||
static makeReadOnly(url: string): 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 restClient;
|
||||||
private readonly signingData;
|
private readonly signingData;
|
||||||
|
private readonly fees;
|
||||||
private get senderAddress();
|
private get senderAddress();
|
||||||
private get signCallback();
|
private get signCallback();
|
||||||
private constructor();
|
private constructor();
|
||||||
@@ -71,6 +83,7 @@ export declare class CosmWasmClient {
|
|||||||
memo?: string,
|
memo?: string,
|
||||||
transferAmount?: readonly Coin[],
|
transferAmount?: readonly Coin[],
|
||||||
): Promise<ExecuteResult>;
|
): 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)
|
* Returns the data at the key if present (raw contract dependent storage data)
|
||||||
* or null if no data at this key.
|
* or null if no data at this key.
|
||||||
|
|||||||
Reference in New Issue
Block a user