diff --git a/packages/faucet/src/faucet.ts b/packages/faucet/src/faucet.ts index d6a8846a79..c61a9890ad 100644 --- a/packages/faucet/src/faucet.ts +++ b/packages/faucet/src/faucet.ts @@ -1,14 +1,18 @@ import { - assertIsBroadcastTxSuccess, + assertIsBroadcastTxSuccess as assertIsBroadcastTxSuccessLaunchpad, CosmosClient, - OfflineSigner, SigningCosmosClient, } from "@cosmjs/launchpad"; +import { + assertIsBroadcastTxSuccess as assertIsBroadcastTxSuccessStargate, + SigningStargateClient, + StargateClient, +} from "@cosmjs/stargate"; import { sleep } from "@cosmjs/utils"; import * as constants from "./constants"; import { debugAccount, logAccountsState, logSendJob } from "./debugging"; -import { createWallets } from "./profile"; +import { createClients, createWallets } from "./profile"; import { TokenConfiguration, TokenManager } from "./tokenmanager"; import { MinimalAccount, SendJob } from "./types"; @@ -23,10 +27,13 @@ export class Faucet { config: TokenConfiguration, mnemonic: string, numberOfDistributors: number, + stargate = true, logging = false, ): Promise { - const wallets = await createWallets(mnemonic, addressPrefix, numberOfDistributors, logging); - return new Faucet(apiUrl, addressPrefix, config, wallets, logging); + const wallets = await createWallets(mnemonic, addressPrefix, numberOfDistributors, stargate, logging); + const clients = await createClients(apiUrl, wallets); + const readonlyClient = stargate ? await StargateClient.connect(apiUrl) : new CosmosClient(apiUrl); + return new Faucet(addressPrefix, config, clients, readonlyClient, logging); } public readonly addressPrefix: string; @@ -35,39 +42,28 @@ export class Faucet { private readonly tokenConfig: TokenConfiguration; private readonly tokenManager: TokenManager; - private readonly readOnlyClient: CosmosClient; - private readonly clients: { [senderAddress: string]: SigningCosmosClient }; + private readonly readOnlyClient: CosmosClient | StargateClient; + private readonly clients: { [senderAddress: string]: SigningCosmosClient | SigningStargateClient }; private readonly logging: boolean; private creditCount = 0; private constructor( - apiUrl: string, addressPrefix: string, config: TokenConfiguration, - wallets: ReadonlyArray, + clients: ReadonlyArray, + readonlyClient: CosmosClient | StargateClient, logging = false, ) { this.addressPrefix = addressPrefix; this.tokenConfig = config; this.tokenManager = new TokenManager(config); - this.readOnlyClient = new CosmosClient(apiUrl); - - this.holderAddress = wallets[0][0]; - this.distributorAddresses = wallets.slice(1).map((pair) => pair[0]); - - // we need one client per sender - const clients: { [senderAddress: string]: SigningCosmosClient } = {}; - for (const [senderAddress, wallet] of wallets) { - clients[senderAddress] = new SigningCosmosClient( - apiUrl, - senderAddress, - wallet, - constants.gasPrice, - constants.gasLimits, - ); - } - this.clients = clients; + this.readOnlyClient = readonlyClient; + [this.holderAddress, ...this.distributorAddresses] = clients.map(([address]) => address); + this.clients = clients.reduce( + (acc, [senderAddress, client]) => ({ ...acc, [senderAddress]: client }), + {}, + ); this.logging = logging; } @@ -75,9 +71,7 @@ export class Faucet { * Returns a list of denoms of tokens owned by the the holder and configured in the faucet */ public async availableTokens(): Promise { - const holderAccount = await this.readOnlyClient.getAccount(this.holderAddress); - const balance = holderAccount ? holderAccount.balance : []; - + const { balance } = await this.loadAccount(this.holderAddress); return balance .filter((b) => b.amount !== "0") .map((b) => this.tokenConfig.bankTokens.find((token) => token == b.denom)) @@ -89,8 +83,13 @@ export class Faucet { * Throws an error if the transaction failed. */ public async send(job: SendJob): Promise { - const result = await this.clients[job.sender].sendTokens(job.recipient, [job.amount], constants.memo); - assertIsBroadcastTxSuccess(result); + const client = this.clients[job.sender]; + if (client instanceof SigningCosmosClient) { + const result = await client.sendTokens(job.recipient, [job.amount], constants.memo); + return assertIsBroadcastTxSuccessLaunchpad(result); + } + const result = await client.sendTokens(job.sender, job.recipient, [job.amount], constants.memo); + assertIsBroadcastTxSuccessStargate(result); } /** Use one of the distributor accounts to send tokens to user */ @@ -111,24 +110,21 @@ export class Faucet { return Array.from(this.tokenConfig.bankTokens); } + public async loadAccount(address: string): Promise { + const balance = + this.readOnlyClient instanceof CosmosClient + ? (await this.readOnlyClient.getAccount(address))?.balance ?? [] + : await this.readOnlyClient.getAllBalancesUnverified(address); + + return { + address: address, + balance: balance, + }; + } + public async loadAccounts(): Promise { const addresses = [this.holderAddress, ...this.distributorAddresses]; - - return Promise.all( - addresses.map( - async (address): Promise => { - const response = await this.readOnlyClient.getAccount(address); - if (response) { - return response; - } else { - return { - address: address, - balance: [], - }; - } - }, - ), - ); + return Promise.all(addresses.map(this.loadAccount.bind(this))); } public async refill(): Promise { diff --git a/packages/faucet/src/profile.ts b/packages/faucet/src/profile.ts index 39d9ec05a2..2dacc56856 100644 --- a/packages/faucet/src/profile.ts +++ b/packages/faucet/src/profile.ts @@ -1,19 +1,25 @@ import { pathToString } from "@cosmjs/crypto"; -import { makeCosmoshubPath, OfflineSigner, Secp256k1HdWallet } from "@cosmjs/launchpad"; +import { makeCosmoshubPath, Secp256k1HdWallet, SigningCosmosClient } from "@cosmjs/launchpad"; +import { DirectSecp256k1Wallet, isOfflineDirectSigner, OfflineSigner } from "@cosmjs/proto-signing"; +import { SigningStargateClient } from "@cosmjs/stargate"; + +import * as constants from "./constants"; export async function createWallets( mnemonic: string, addressPrefix: string, numberOfDistributors: number, + stargate = true, logging = false, ): Promise> { + const createWallet = stargate ? DirectSecp256k1Wallet.fromMnemonic : Secp256k1HdWallet.fromMnemonic; const wallets = new Array(); // first account is the token holder const numberOfIdentities = 1 + numberOfDistributors; for (let i = 0; i < numberOfIdentities; i++) { const path = makeCosmoshubPath(i); - const wallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, path, addressPrefix); + const wallet = await createWallet(mnemonic, path, addressPrefix); const [{ address }] = await wallet.getAccounts(); if (logging) { const role = i === 0 ? "token holder " : `distributor ${i}`; @@ -24,3 +30,22 @@ export async function createWallets( return wallets; } + +export async function createClients( + apiUrl: string, + wallets: ReadonlyArray, +): Promise> { + // we need one client per sender + return Promise.all( + wallets.map( + async ([senderAddress, wallet]): Promise< + readonly [string, SigningCosmosClient | SigningStargateClient] + > => [ + senderAddress, + isOfflineDirectSigner(wallet) + ? await SigningStargateClient.connectWithWallet(apiUrl, wallet, {}) + : new SigningCosmosClient(apiUrl, senderAddress, wallet, constants.gasPrice, constants.gasLimits), + ], + ), + ); +}