diff --git a/packages/bcp/src/cosmwasmconnection.spec.ts b/packages/bcp/src/cosmwasmconnection.spec.ts index 9bf71d95..6baa9f01 100644 --- a/packages/bcp/src/cosmwasmconnection.spec.ts +++ b/packages/bcp/src/cosmwasmconnection.spec.ts @@ -11,8 +11,8 @@ import { TokenTicker, TransactionState, } from "@iov/bcp"; -import { Secp256k1 } from "@iov/crypto"; -import { Encoding } from "@iov/encoding"; +import { Random, Secp256k1 } from "@iov/crypto"; +import { Bech32, Encoding } from "@iov/encoding"; import { HdPaths, Secp256k1HdWallet, UserProfile } from "@iov/keycontrol"; import { assert } from "@iov/utils"; @@ -29,6 +29,12 @@ function pendingWithoutCosmos(): void { } } +const defaultPrefix = "cosmos" as CosmosAddressBech32Prefix; + +function makeRandomAddress(): Address { + return Bech32.encode(defaultPrefix, Random.getBytes(20)) as Address; +} + describe("CosmWasmConnection", () => { const cosm = "COSM" as TokenTicker; const httpUrl = "http://localhost:1317"; @@ -53,8 +59,6 @@ describe("CosmWasmConnection", () => { address: "cosmos1cjsxept9rkggzxztslae9ndgpdyt2408lk850u" as Address, }; - const defaultPrefix = "cosmos" as CosmosAddressBech32Prefix; - // this is for wasmd blockchain const defaultConfig: TokenConfiguration = { bankTokens: [ @@ -447,5 +451,47 @@ describe("CosmWasmConnection", () => { connection.disconnect(); }); + + it("can send ERC20 tokens", async () => { + pendingWithoutCosmos(); + const codec = new CosmWasmCodec(defaultPrefix, defaultConfig.bankTokens, defaultConfig.erc20Tokens); + const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, defaultConfig); + const profile = new UserProfile(); + const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucetMnemonic)); + const faucet = await profile.createIdentity(wallet.id, defaultChainId, faucetPath); + const faucetAddress = codec.identityToAddress(faucet); + const recipient = makeRandomAddress(); + + const unsigned = await connection.withDefaultFee({ + kind: "bcp/send", + chainId: defaultChainId, + sender: faucetAddress, + recipient: recipient, + memo: "My first payment", + amount: { + quantity: "75", + fractionalDigits: 3, // todo: BROKEN! + tokenTicker: "BASH" as TokenTicker, + }, + }); + const nonce = await connection.getNonce({ address: faucetAddress }); + const signed = await profile.signTransaction(faucet, unsigned, codec, nonce); + const postableBytes = codec.bytesToPost(signed); + const response = await connection.postTx(postableBytes); + const blockInfo = await response.blockInfo.waitFor(info => !isBlockInfoPending(info)); + expect(blockInfo.state).toEqual(TransactionState.Succeeded); + + const recipientAccount = await connection.getAccount({ address: recipient }); + assert(recipientAccount, "Recipient account must have BASH tokens"); + expect(recipientAccount.balance).toEqual([ + { + tokenTicker: "BASH" as TokenTicker, + quantity: "75", + fractionalDigits: 0, + }, + ]); + + connection.disconnect(); + }); }); }); diff --git a/packages/bcp/src/cosmwasmconnection.ts b/packages/bcp/src/cosmwasmconnection.ts index 7a3e50e2..bb52c528 100644 --- a/packages/bcp/src/cosmwasmconnection.ts +++ b/packages/bcp/src/cosmwasmconnection.ts @@ -158,12 +158,10 @@ export class CosmWasmConnection implements BlockchainConnection { public async getAccount(query: AccountQuery): Promise { const address = isPubkeyQuery(query) ? pubkeyToAddress(query.pubkey, this.addressPrefix) : query.address; const { result } = await this.restClient.authAccounts(address); - const account = result.value; - if (!account.address) { - return undefined; - } + const bankAccount = result.value; + const hasBankAccount = !!bankAccount.address; - const supportedBankCoins = account.coins.filter(({ denom }) => + const supportedBankCoins = bankAccount.coins.filter(({ denom }) => this.bankTokens.find(token => token.denom === denom), ); const erc20Amounts = await Promise.all( @@ -184,17 +182,20 @@ export class CosmWasmConnection implements BlockchainConnection { ); const nonZeroErc20Amounts = erc20Amounts.filter(amount => amount.quantity !== "0"); - const balance = [ - ...supportedBankCoins.map(coin => decodeAmount(this.bankTokens, coin)), - ...nonZeroErc20Amounts, - ].sort((a, b) => a.tokenTicker.localeCompare(b.tokenTicker)); - - const pubkey = !account.public_key ? undefined : decodeCosmosPubkey(account.public_key); - return { - address: address, - balance: balance, - pubkey: pubkey, - }; + if (!hasBankAccount && nonZeroErc20Amounts.length === 0) { + return undefined; + } else { + const balance = [ + ...supportedBankCoins.map(coin => decodeAmount(this.bankTokens, coin)), + ...nonZeroErc20Amounts, + ].sort((a, b) => a.tokenTicker.localeCompare(b.tokenTicker)); + const pubkey = !bankAccount.public_key ? undefined : decodeCosmosPubkey(bankAccount.public_key); + return { + address: address, + balance: balance, + pubkey: pubkey, + }; + } } public watchAccount(_account: AccountQuery): Stream {