From 220a8ddd989f5737c0cf13fcdd1b39ef1eb2ab3f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 10 Feb 2020 17:06:25 +0100 Subject: [PATCH] Add erc20 support to buildUnsignedTx --- packages/bcp/src/encode.spec.ts | 69 +++++++++++++++++++++++- packages/bcp/src/encode.ts | 96 ++++++++++++++++++++++++--------- packages/bcp/types/encode.d.ts | 14 +++-- 3 files changed, 150 insertions(+), 29 deletions(-) diff --git a/packages/bcp/src/encode.spec.ts b/packages/bcp/src/encode.spec.ts index 436430d5..220d6d2e 100644 --- a/packages/bcp/src/encode.spec.ts +++ b/packages/bcp/src/encode.spec.ts @@ -21,7 +21,7 @@ import { encodeFullSignature, encodePubkey, } from "./encode"; -import { BankTokens } from "./types"; +import { BankTokens, Erc20Token } from "./types"; const { fromBase64 } = Encoding; @@ -48,6 +48,23 @@ describe("encode", () => { denom: "uatom", }, ]; + const defaultErc20Tokens: Erc20Token[] = [ + { + contractAddress: "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", + fractionalDigits: 5, + ticker: "ASH", + }, + { + contractAddress: "cosmos1hqrdl6wstt8qzshwc6mrumpjk9338k0lr4dqxd", + fractionalDigits: 0, + ticker: "BASH", + }, + { + contractAddress: "cosmos18r5szma8hm93pvx6lwpjwyxruw27e0k5uw835c", + fractionalDigits: 18, + ticker: "CASH", + }, + ]; describe("encodePubKey", () => { it("encodes a Secp256k1 pubkey", () => { @@ -262,6 +279,56 @@ describe("encode", () => { }, }); }); + + it("works for ERC20 send", () => { + const bashSendTx: SendTransaction = { + kind: "bcp/send", + chainId: defaultChainId, + sender: "cosmos1txqfn5jmcts0x0q7krdxj8tgf98tj0965vqlmq" as Address, + recipient: "cosmos1dddd" as Address, + memo: defaultMemo, + amount: { + fractionalDigits: 6, + quantity: "345", + tokenTicker: "BASH" as TokenTicker, + }, + fee: { + tokens: { + fractionalDigits: 6, + quantity: "3333", + tokenTicker: "ATOM" as TokenTicker, + }, + gasLimit: "234000", + }, + }; + expect(buildUnsignedTx(bashSendTx, defaultTokens, defaultErc20Tokens)).toEqual({ + type: "cosmos-sdk/StdTx", + value: { + msg: [ + { + type: "wasm/execute", + value: { + sender: "cosmos1txqfn5jmcts0x0q7krdxj8tgf98tj0965vqlmq", + contract: "cosmos1hqrdl6wstt8qzshwc6mrumpjk9338k0lr4dqxd", + msg: { + transfer: { + recipient: "cosmos1dddd", + amount: "345", + }, + }, + sent_funds: [], + }, + }, + ], + fee: { + amount: [{ denom: "uatom", amount: "3333" }], + gas: "234000", + }, + signatures: [], + memo: defaultMemo, + }, + }); + }); }); describe("buildSignedTx", () => { diff --git a/packages/bcp/src/encode.ts b/packages/bcp/src/encode.ts index a0a84d8e..52dd0670 100644 --- a/packages/bcp/src/encode.ts +++ b/packages/bcp/src/encode.ts @@ -12,7 +12,7 @@ import { } from "@iov/bcp"; import { Decimal, Encoding } from "@iov/encoding"; -import { BankTokens } from "./types"; +import { BankTokens, Erc20Token } from "./types"; const { toBase64 } = Encoding; @@ -79,37 +79,83 @@ export function encodeFullSignature(fullSignature: FullSignature): types.StdSign } } -export function buildUnsignedTx(tx: UnsignedTransaction, tokens: BankTokens): types.AminoTx { +export function buildUnsignedTx( + tx: UnsignedTransaction, + bankTokens: BankTokens, + erc20Tokens: readonly Erc20Token[] = [], +): types.AminoTx { if (!isSendTransaction(tx)) { throw new Error("Received transaction of unsupported kind"); } - return { - type: "cosmos-sdk/StdTx", - value: { - msg: [ - { - type: "cosmos-sdk/MsgSend", - value: { - from_address: tx.sender, - to_address: tx.recipient, - amount: [encodeAmount(tx.amount, tokens)], + + const matchingBankToken = bankTokens.find(t => t.ticker === tx.amount.tokenTicker); + const matchingErc20Token = erc20Tokens.find(t => t.ticker === tx.amount.tokenTicker); + + if (matchingBankToken) { + return { + type: "cosmos-sdk/StdTx", + value: { + msg: [ + { + type: "cosmos-sdk/MsgSend", + value: { + from_address: tx.sender, + to_address: tx.recipient, + amount: [encodeAmount(tx.amount, bankTokens)], + }, }, - }, - ], - memo: tx.memo || "", - signatures: [], - fee: tx.fee - ? encodeFee(tx.fee, tokens) - : { - amount: [], - gas: "", + ], + memo: tx.memo || "", + signatures: [], + fee: tx.fee + ? encodeFee(tx.fee, bankTokens) + : { + amount: [], + gas: "", + }, + }, + }; + } else if (matchingErc20Token) { + return { + type: "cosmos-sdk/StdTx", + value: { + msg: [ + { + type: "wasm/execute", + value: { + sender: tx.sender, + contract: matchingErc20Token.contractAddress, + msg: { + transfer: { + amount: tx.amount.quantity, + recipient: tx.recipient, + }, + }, + sent_funds: [], + }, }, - }, - }; + ], + memo: tx.memo || "", + signatures: [], + fee: tx.fee + ? encodeFee(tx.fee, bankTokens) + : { + amount: [], + gas: "", + }, + }, + }; + } else { + throw new Error("Cannot encode this type of transaction"); + } } -export function buildSignedTx(tx: SignedTransaction, tokens: BankTokens): types.AminoTx { - const built = buildUnsignedTx(tx.transaction, tokens); +export function buildSignedTx( + tx: SignedTransaction, + bankTokens: BankTokens, + erc20Tokens: readonly Erc20Token[] = [], +): types.AminoTx { + const built = buildUnsignedTx(tx.transaction, bankTokens, erc20Tokens); return { ...built, value: { diff --git a/packages/bcp/types/encode.d.ts b/packages/bcp/types/encode.d.ts index c55e4240..2c84e8e9 100644 --- a/packages/bcp/types/encode.d.ts +++ b/packages/bcp/types/encode.d.ts @@ -1,11 +1,19 @@ import { types } from "@cosmwasm/sdk"; import { Amount, Fee, FullSignature, PubkeyBundle, SignedTransaction, UnsignedTransaction } from "@iov/bcp"; import { Decimal } from "@iov/encoding"; -import { BankTokens } from "./types"; +import { BankTokens, Erc20Token } from "./types"; export declare function encodePubkey(pubkey: PubkeyBundle): types.PubKey; export declare function decimalToCoin(lookup: BankTokens, value: Decimal, ticker: string): types.Coin; export declare function encodeAmount(amount: Amount, tokens: BankTokens): types.Coin; export declare function encodeFee(fee: Fee, tokens: BankTokens): types.StdFee; export declare function encodeFullSignature(fullSignature: FullSignature): types.StdSignature; -export declare function buildUnsignedTx(tx: UnsignedTransaction, tokens: BankTokens): types.AminoTx; -export declare function buildSignedTx(tx: SignedTransaction, tokens: BankTokens): types.AminoTx; +export declare function buildUnsignedTx( + tx: UnsignedTransaction, + bankTokens: BankTokens, + erc20Tokens?: readonly Erc20Token[], +): types.AminoTx; +export declare function buildSignedTx( + tx: SignedTransaction, + bankTokens: BankTokens, + erc20Tokens?: readonly Erc20Token[], +): types.AminoTx;