import { SigningCosmWasmClient, SigningCosmWasmClientOptions } from "@cosmjs/cosmwasm-stargate"; import { Delegation, GatewayOwnershipResponse, MixOwnershipResponse, PagedGatewayDelegationsResponse, PagedGatewayResponse, PagedMixDelegationsResponse, PagedMixnodeResponse, StateParams } from "./types"; import { DirectSecp256k1HdWallet, EncodeObject } from "@cosmjs/proto-signing"; import { Coin, StdFee } from "@cosmjs/stargate"; import { BroadcastTxResponse } from "@cosmjs/stargate" import { nymGasLimits, nymGasPrice } from "./stargate-helper" import { ExecuteResult, InstantiateOptions, InstantiateResult, MigrateResult, UploadMeta, UploadResult } from "@cosmjs/cosmwasm-stargate"; export interface INetClient { clientAddress: string; getBalance(address: string, denom: string): Promise; getMixNodes(contractAddress: string, limit: number, start_after?: string): Promise; getGateways(contractAddress: string, limit: number, start_after?: string): Promise; getMixDelegations(contractAddress: string, mixIdentity: string, limit: number, start_after?: string): Promise getMixDelegation(contractAddress: string, mixIdentity: string, delegatorAddress: string): Promise getGatewayDelegations(contractAddress: string, gatewayIdentity: string, limit: number, start_after?: string): Promise getGatewayDelegation(contractAddress: string, gatewayIdentity: string, delegatorAddress: string): Promise ownsMixNode(contractAddress: string, address: string): Promise; ownsGateway(contractAddress: string, address: string): Promise; getStateParams(contractAddress: string): Promise; signAndBroadcast(signerAddress: string, messages: readonly EncodeObject[], fee: StdFee, memo?: string): Promise; executeContract(senderAddress: string, contractAddress: string, handleMsg: Record, memo?: string, transferAmount?: readonly Coin[]): Promise; instantiate(senderAddress: string, codeId: number, initMsg: Record, label: string, options?: InstantiateOptions): Promise; sendTokens(senderAddress: string, recipientAddress: string, transferAmount: readonly Coin[], memo?: string): Promise; upload(senderAddress: string, wasmCode: Uint8Array, meta?: UploadMeta, memo?: string): Promise; changeValidator(newUrl: string): Promise } /** * Takes care of network communication between this code and the validator. * Depends on `SigningCosmWasClient`, which signs all requests using keypairs * derived from on bech32 mnemonics. * * Wraps several methods from CosmWasmSigningClient so we can mock them for * unit testing. */ export default class NetClient implements INetClient { clientAddress: string; private cosmClient: SigningCosmWasmClient; // helpers for changing validators without having to remake the wallet private readonly wallet: DirectSecp256k1HdWallet; private readonly signerOptions: SigningCosmWasmClientOptions; private constructor(clientAddress: string, cosmClient: SigningCosmWasmClient, wallet: DirectSecp256k1HdWallet, signerOptions: SigningCosmWasmClientOptions) { this.clientAddress = clientAddress; this.cosmClient = cosmClient; this.wallet = wallet; this.signerOptions = signerOptions; } public static async connect(wallet: DirectSecp256k1HdWallet, url: string, prefix: string): Promise { const [{address}] = await wallet.getAccounts(); const signerOptions: SigningCosmWasmClientOptions = { gasPrice: nymGasPrice(prefix), gasLimits: nymGasLimits, }; const client = await SigningCosmWasmClient.connectWithSigner(url, wallet, signerOptions); return new NetClient(address, client, wallet, signerOptions); } async changeValidator(url: string): Promise { this.cosmClient = await SigningCosmWasmClient.connectWithSigner(url, this.wallet, this.signerOptions); } public getMixNodes(contractAddress: string, limit: number, start_after?: string): Promise { if (start_after == undefined) { // TODO: check if we can take this out, I'm not sure what will happen if we send an "undefined" so I'm playing it safe here. return this.cosmClient.queryContractSmart(contractAddress, {get_mix_nodes: {limit}}); } else { return this.cosmClient.queryContractSmart(contractAddress, {get_mix_nodes: {limit, start_after}}); } } public getGateways(contractAddress: string, limit: number, start_after?: string): Promise { if (start_after == undefined) { // TODO: check if we can take this out, I'm not sure what will happen if we send an "undefined" so I'm playing it safe here. return this.cosmClient.queryContractSmart(contractAddress, {get_gateways: {limit}}); } else { return this.cosmClient.queryContractSmart(contractAddress, {get_gateways: {limit, start_after}}); } } public getMixDelegations(contractAddress: string, mixIdentity: string, limit: number, start_after?: string): Promise { if (start_after == undefined) { // TODO: check if we can take this out, I'm not sure what will happen if we send an "undefined" so I'm playing it safe here. return this.cosmClient.queryContractSmart(contractAddress, { get_mix_delegations: { mix_identity: mixIdentity, limit } }); } else { return this.cosmClient.queryContractSmart(contractAddress, { get_mix_delegations: { mix_identity: mixIdentity, limit, start_after } }); } } public getMixDelegation(contractAddress: string, mixIdentity: string, delegatorAddress: string): Promise { return this.cosmClient.queryContractSmart(contractAddress, { get_mix_delegation: { mix_identity: mixIdentity, address: delegatorAddress } }); } public getGatewayDelegations(contractAddress: string, gatewayIdentity: string, limit: number, start_after?: string): Promise { if (start_after == undefined) { // TODO: check if we can take this out, I'm not sure what will happen if we send an "undefined" so I'm playing it safe here. return this.cosmClient.queryContractSmart(contractAddress, { get_gateway_delegations: { gateway_identity: gatewayIdentity, limit } }); } else { return this.cosmClient.queryContractSmart(contractAddress, { get_gateway_delegations: { gateway_identity: gatewayIdentity, limit, start_after } }); } } public getGatewayDelegation(contractAddress: string, gatewayIdentity: string, delegatorAddress: string): Promise { return this.cosmClient.queryContractSmart(contractAddress, { get_gateway_delegation: { gateway_identity: gatewayIdentity, address: delegatorAddress } }); } public ownsMixNode(contractAddress: string, address: string): Promise { return this.cosmClient.queryContractSmart(contractAddress, {owns_mixnode: {address}}); } public ownsGateway(contractAddress: string, address: string): Promise { return this.cosmClient.queryContractSmart(contractAddress, {owns_gateway: {address}}); } public getBalance(address: string, denom: string): Promise { return this.cosmClient.getBalance(address, denom); } public getStateParams(contractAddress: string): Promise { return this.cosmClient.queryContractSmart(contractAddress, {state_params: {}}); } public executeContract(senderAddress: string, contractAddress: string, handleMsg: Record, memo?: string, transferAmount?: readonly Coin[]): Promise { return this.cosmClient.execute(senderAddress, contractAddress, handleMsg, memo, transferAmount); } public signAndBroadcast(signerAddress: string, messages: readonly EncodeObject[], fee: StdFee, memo?: string): Promise { return this.cosmClient.signAndBroadcast(signerAddress, messages, fee, memo) } public sendTokens(senderAddress: string, recipientAddress: string, transferAmount: readonly Coin[], memo?: string): Promise { return this.cosmClient.sendTokens(senderAddress, recipientAddress, transferAmount, memo); } public upload(senderAddress: string, wasmCode: Uint8Array, meta?: UploadMeta, memo?: string): Promise { return this.cosmClient.upload(senderAddress, wasmCode, meta, memo); } public instantiate(senderAddress: string, codeId: number, initMsg: Record, label: string, options?: InstantiateOptions): Promise { return this.cosmClient.instantiate(senderAddress, codeId, initMsg, label, options); } public migrate(senderAddress: string, contractAddress: string, codeId: number, migrateMsg: Record, memo?: string): Promise { return this.cosmClient.migrate(senderAddress, contractAddress, codeId, migrateMsg, memo) } }