diff --git a/package-lock.json b/package-lock.json index acf6238..e5a93a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@cosmjs/stargate": "^0.32.2", "@jackallabs/bech32": "^1.2.0", "@jackallabs/dogwood-tree": "^1.0.1", - "@jackallabs/jackal.js-protos": "2.3.0", + "@jackallabs/jackal.js-protos": "file:jackallabs-jackal.js-protos-2.3.0.tgz", "@karnthis/plzsu": "^1.0.0", "@keplr-wallet/types": "^0.12.44", "browserify-aes": "^1.2.0", @@ -929,8 +929,9 @@ }, "node_modules/@jackallabs/banshee": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@jackallabs/banshee/-/banshee-1.0.1.tgz", - "integrity": "sha512-ouhmRnjUK1JDoB2+wcEadUnsTm0y5obslTZyotzGXzfxHi5G8RWtfUuDAC2VQFWP6pbFkv+lJRZUXWyGnXXvTA==", + "resolved": "file:jackallabs-banshee-1.0.1.tgz", + "integrity": "sha512-s9R+9if9i+sawwrys2rbTgWFYCduu/7XQgsI1b9/ogvvwR3ZIFaF3lBBBtXtIvb5bVdW3Q4emyYHc4vKTgObAQ==", + "license": "MIT", "dependencies": { "@cosmjs/amino": "^0.32.3", "@cosmjs/launchpad": "^0.27.1", @@ -1020,8 +1021,9 @@ }, "node_modules/@jackallabs/jackal.js-protos": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@jackallabs/jackal.js-protos/-/jackal.js-protos-2.3.0.tgz", - "integrity": "sha512-3fw8nmYfkxIzBWMzhvrWO14yxeoxEznCyon/F4l18+J4/yunKXPdvOYmsY0seTmv0hwdWl+UtToxIAqEYBi5zw==", + "resolved": "file:jackallabs-jackal.js-protos-2.3.0.tgz", + "integrity": "sha512-qup7B9QhycWflFskU7LMblq83i3SrqTkOvXFE76JmnVvYml500bvssF4Y2AhovFzsLKzds2LCXbeYlNIwvDLig==", + "license": "MIT", "dependencies": { "@cosmjs/amino": "^0.32.3", "@cosmjs/encoding": "^0.32.3", @@ -1031,7 +1033,7 @@ "@cosmjs/stargate": "^0.32.3", "@cosmjs/tendermint-rpc": "^0.32.3", "@cosmjs/utils": "^0.32.3", - "@jackallabs/banshee": "1.0.1", + "@jackallabs/banshee": "file:jackallabs-banshee-1.0.1.tgz", "cosmjs-types": "^0.8.0", "grpc-web": "^1.5.0", "protobufjs": "^7.2.5", diff --git a/package.json b/package.json index 9f9c114..9f94b45 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "@cosmjs/stargate": "^0.32.2", "@jackallabs/bech32": "^1.2.0", "@jackallabs/dogwood-tree": "^1.0.1", - "@jackallabs/jackal.js-protos": "2.3.0", + "@jackallabs/jackal.js-protos": "file:jackallabs-jackal.js-protos-2.3.0.tgz", "@karnthis/plzsu": "^1.0.0", "@keplr-wallet/types": "^0.12.44", "browserify-aes": "^1.2.0", diff --git a/src/classes/clientHandler.ts b/src/classes/clientHandler.ts index 30ad2ff..b35fbf7 100644 --- a/src/classes/clientHandler.ts +++ b/src/classes/clientHandler.ts @@ -33,6 +33,7 @@ import { IWrappedEncodeObject, } from '@/interfaces' import { TSockets, TSocketSet } from '@/types' +import { Coin, DeliverTxResponse, StdFee } from '@cosmjs/stargate' export class ClientHandler implements IClientHandler { protected readonly jklQuery: TJackalQueryClient @@ -282,24 +283,45 @@ export class ClientHandler implements IClientHandler { async createWasmStorageHandler (details: IWasmDetails = {}): Promise { try { const { - addressIndex = 1, - codeId = 546, connIdA = 'connection-18', connIdB = 'connection-50', + contract = 'archway1z0wngtg6qwweqh3sfcz6l42srkhqly2guxp8enf9y6sny08c4gqq35jdc4', } = details this.myCosmwasm = await WasmHandler.init(this) - this.myContractAddress = await this.myCosmwasm.getICAContractAddress(addressIndex) - if (!this.myContractAddress) { + const ica = await this.myCosmwasm.getICAContractAddress(contract).catch(err => { + console.warn("can't get ica", err) + }) + console.log("ICA: ", ica) + if (ica) { + console.log("Set ICA correctly") + this.myContractAddress = ica + } else { + console.log("Failed to set ICA") await this.myCosmwasm.instantiateICA( + contract, connIdA, connIdB, - codeId, ) - this.myContractAddress = await this.myCosmwasm.getICAContractAddress(addressIndex) + await new Promise(r => setTimeout(r, 5000)); + this.myContractAddress = await this.myCosmwasm.getICAContractAddress(contract) } + console.log(this.myContractAddress) this.myIcaAddress = await this.myCosmwasm.getJackalAddressFromContract( this.myContractAddress, ) + const state = await this.myCosmwasm.getContractChannelState( + this.myContractAddress, + ) + console.log("State: ", state) + if (state === 'STATE_CLOSED') { + console.log("needs to re-open channel") + await this.myCosmwasm.reOpenChannel( + contract, + connIdA, + connIdB, + ) + } + return await StorageHandler.init(this, { accountAddress: this.myIcaAddress, }) @@ -433,17 +455,59 @@ export class ClientHandler implements IClientHandler { * @returns {Promise} */ async getJklBalance (): Promise { + return this.getJackalNetworkBalance(this.getICAJackalAddress()) + } + + async ibcSend (address: string, amount: Coin, sourceChannel: string): Promise { + if (!this.hostSigner) { + throw new Error(signerNotEnabled('ClientHandler', 'ibcSend')) + } + + + const fee: Coin = {amount: "35774392000000000", denom: "aarch"} + const f: StdFee = {amount: [fee], gas: "200000"} + try { + return await this.hostSigner.sendIbcTokens(this.hostAddress, address, amount, "transfer", sourceChannel, undefined, Date.now() * 1000 * 1000 + 2 * 60 * 60 * 1000 * 1000 * 1000, f, undefined) + } catch (err) { + throw warnError('clientHandler ibcSend()', err) + } + } + + /** + * + * @returns {Promise} + */ + async getJackalNetworkBalance (address: string): Promise { if (!this.jklSigner) { - throw new Error(signerNotEnabled('ClientHandler', 'getJklBalance')) + throw new Error(signerNotEnabled('ClientHandler', 'getJackalNetworkBalance')) } try { const res = await this.jklQuery.queries.bank.balance({ - address: this.getICAJackalAddress(), + address: address, denom: 'ujkl', }) return res.balance as DCoin } catch (err) { - throw warnError('clientHandler getJklBalance()', err) + throw warnError('clientHandler getJackalNetworkBalance()', err) + } + } + + /** + * + * @returns {Promise} + */ + async getHostNetworkBalance (address: string, denom: string): Promise { + if (!this.jklSigner) { + throw new Error(signerNotEnabled('ClientHandler', 'getHostNetworkBalance')) + } + if (!this.hostQuery) { + throw new Error(signerNotEnabled('ClientHandler', 'getHostNetworkBalance')) + } + try { + const res = await this.hostQuery.getBalance(address,denom) + return res + } catch (err) { + throw warnError('clientHandler getHostNetworkBalance()', err) } } @@ -544,6 +608,7 @@ export class ClientHandler implements IClientHandler { broadcastTimeoutHeight, monitorTimeout = 30, socketOverrides = {} as TSocketSet, + queryOverride, } = options const events: TxEvent[] = [] const ready: IWrappedEncodeObject[] = @@ -556,6 +621,7 @@ export class ClientHandler implements IClientHandler { events, msgs, this.myIcaAddress || this.hostAddress, + queryOverride, socketOverrides, ) console.log('connectionBundles:', connectionBundles) diff --git a/src/classes/encodingHandler.ts b/src/classes/encodingHandler.ts index 67c9698..027cabf 100644 --- a/src/classes/encodingHandler.ts +++ b/src/classes/encodingHandler.ts @@ -231,8 +231,8 @@ export class EncodingHandler { */ protected encodePostKey (key: string): DEncodeObject { const forKey: DMsgPostKey = { - creator: this.hostAddress, - key, + creator: this.jackalClient.getICAJackalAddress(), + key: key, } return this.jackalSigner.txLibrary.fileTree.msgPostKey(forKey) } diff --git a/src/classes/storageHandler.ts b/src/classes/storageHandler.ts index 9d07daa..15f316b 100644 --- a/src/classes/storageHandler.ts +++ b/src/classes/storageHandler.ts @@ -1506,6 +1506,21 @@ export class StorageHandler extends EncodingHandler implements IStorageHandler { } } + /** + * + * @returns {Promise} + * @protected + */ + protected async getAllProviders (): Promise { + try { + const providers = await this.getAvailableProviders() + // console.log(providers) + return await this.findProviderIps(providers) + } catch (err) { + throw warnError('storageHandler loadProvidersFromChain()', err) + } + } + /** * * @param {IWrappedEncodeObject[]} msgs diff --git a/src/classes/wasmHandler.ts b/src/classes/wasmHandler.ts index 297c0ee..7cd9cc7 100644 --- a/src/classes/wasmHandler.ts +++ b/src/classes/wasmHandler.ts @@ -43,44 +43,107 @@ export class WasmHandler extends EncodingHandler implements IWasmHandler { } /** - * Instantiate a CosmWasm contract. + * Instantiate an outpost contract. + * @param {string} contractAddress * @param {string} connectionIdA * @param {string} connectionIdB - * @param {number} codeId * @returns {Promise} */ async instantiateICA ( + contractAddress: string, connectionIdA: string, - connectionIdB: string, - codeId: number, + connectionIdB: string ): Promise { try { - const wrapped: IWrappedEncodeObject[] = this.instantiateToMsgs( - connectionIdA, - connectionIdB, - codeId, - ) + + const msg = { + create_outpost: { + channel_open_init_options: { + connection_id: connectionIdA, + counterparty_connection_id: connectionIdB, + tx_encoding: "proto3" + } + } + } + + const eo = this.jackalClient.getTxs().cosmwasm.msgExecuteContract({ + contract: contractAddress, + msg: stringToUint8Array(JSON.stringify(msg)), + funds: [], + sender: this.jackalClient.getHostAddress(), + }) + const wrapped: IWrappedEncodeObject = { encodedObject: eo, modifier: 0 } + const postBroadcast = - await this.jackalClient.broadcastAndMonitorMsgs(wrapped) + //{queryOverride: `execute._contract_address = '${contractAddress}'`} + await this.jackalClient.broadcastAndMonitorMsgs(wrapped, {queryOverride: `message.action = '/cosmwasm.wasm.v1.MsgExecuteContract' AND message.sender = '${this.hostAddress}'`}) return postBroadcast.txResponse } catch (err) { throw warnError('wasmHandler instantiateICA()', err) } } + async reOpenChannel ( + contractAddress: string, + connectionIdA: string, + connectionIdB: string + ): Promise { + try { + const msg = { + create_channel: { + channel_open_init_options: { + connection_id: connectionIdA, + counterparty_connection_id: connectionIdB, + tx_encoding: "proto3" + } + } + } + + const eo = this.jackalClient.getTxs().cosmwasm.msgExecuteContract({ + contract: contractAddress, + msg: stringToUint8Array(JSON.stringify(msg)), + funds: [], + sender: this.jackalClient.getHostAddress(), + }) + const wrapped: IWrappedEncodeObject = { encodedObject: eo, modifier: 0 } + + const postBroadcast = + await this.jackalClient.broadcastAndMonitorMsgs(wrapped, {queryOverride: `execute._contract_address = '${contractAddress}'`}) + return postBroadcast.txResponse + } catch (err) { + throw warnError('wasmHandler reOpenChannel()', err) + } + } + /** * Get Interchain wasm contract address. - * @param {number} [index] - Optional contract index, defaults to 0. + * @param {string} contractAddress - Contract to query from * @returns {Promise} - Contract address. */ - async getICAContractAddress (index: number = 0): Promise { + async getICAContractAddress (contractAddress: string): Promise { try { - const contractsByCreator = - await this.hostSigner.queries.cosmwasm.contractsByCreator({ - creatorAddress: this.hostAddress, - }) - const contracts = contractsByCreator.contractAddresses - return contracts[index] || '' + + const query = { + get_user_outpost_address: { + user_address: this.hostAddress, + }, + } + + const q = stringToUint8Array(JSON.stringify(query)) + + + const req: DQuerySmartContractStateRequest = { + address: contractAddress, + queryData: q, + } + + const state = + await this.hostSigner.queries.cosmwasm.smartContractState(req) + + const uint8Array = state.data instanceof Uint8Array ? state.data : new Uint8Array(state.data); + + return uintArrayToString(uint8Array).replaceAll('"', '') + } catch (err) { throw warnError('wasmHandler getICAContractAddress()', err) } @@ -88,11 +151,12 @@ export class WasmHandler extends EncodingHandler implements IWasmHandler { /** * Get jkl address from unknown Interchain contract. + * @param {string} contractAddress - Contract to query from * @returns {Promise} */ - async getICAJackalAddress (): Promise { + async getICAJackalAddress (contractAddress: string): Promise { try { - const address = await this.getICAContractAddress() + const address = await this.getICAContractAddress(contractAddress) return this.getJackalAddressFromContract(address) } catch (err) { throw warnError('wasmHandler getICAJackalAddress()', err) @@ -105,21 +169,54 @@ export class WasmHandler extends EncodingHandler implements IWasmHandler { * @returns {Promise} - Jkl address. */ async getJackalAddressFromContract (contractAddress: string): Promise { + const retries = 30 + let attempt = 0 + while (attempt < retries) { + try { + const q = { get_contract_state: {} } + + const req: DQuerySmartContractStateRequest = { + address: contractAddress, + queryData: stringToUint8Array(JSON.stringify(q)), + } + + console.log(req) + const res = await this.hostSigner.queries.cosmwasm.smartContractState(req) + const str = uintArrayToString(res.data as Uint8Array) + console.log(str) + const data = JSON.parse(str) + if ("ica_info" in data) { + return data.ica_info.ica_address + } + attempt ++ + await new Promise(r => setTimeout(r, 5000)); + } catch (err) { + console.warn('wasmHandler getJackalAddressFromContract()', err) + } + } + + throw warnError('wasmHandler getJackalAddressFromContract()', "can't get details from contract") + } + + + async getContractChannelState (contractAddress: string): Promise { try { - const q = { get_contract_state: {} } + const q = { get_channel: {} } const req: DQuerySmartContractStateRequest = { address: contractAddress, queryData: stringToUint8Array(JSON.stringify(q)), } + console.log(req) const res = await this.hostSigner.queries.cosmwasm.smartContractState(req) const str = uintArrayToString(res.data as Uint8Array) + console.log(str) const data = JSON.parse(str) - return data.ica_info.ica_address + return data.channel_status } catch (err) { - throw warnError('wasmHandler getJackalAddressFromContract()', err) + throw warnError('wasmHandler getContractChannelState()', err) } } diff --git a/src/interfaces/IWasmDetails.ts b/src/interfaces/IWasmDetails.ts index 51b0077..8543f0d 100644 --- a/src/interfaces/IWasmDetails.ts +++ b/src/interfaces/IWasmDetails.ts @@ -1,6 +1,5 @@ export interface IWasmDetails { - addressIndex?: number - codeId?: number connIdA?: string connIdB?: string + contract?: string } diff --git a/src/interfaces/classes/IClientHandler.ts b/src/interfaces/classes/IClientHandler.ts index 03a3d2e..1682f7a 100644 --- a/src/interfaces/classes/IClientHandler.ts +++ b/src/interfaces/classes/IClientHandler.ts @@ -15,6 +15,7 @@ import { IWasmDetails, IWrappedEncodeObject, } from '@/interfaces' +import { Coin, DeliverTxResponse } from '@cosmjs/stargate' export interface IClientHandler { createStorageHandler (): Promise @@ -49,6 +50,12 @@ export interface IClientHandler { getJklBalance (): Promise + getJackalNetworkBalance (address: string): Promise + + getHostNetworkBalance (address: string, denom: string): Promise + + ibcSend (address: string, amount: Coin, sourceChannel: string): Promise + getJackalAddress (): string getHostAddress (): string diff --git a/src/interfaces/classes/IWasmHandler.ts b/src/interfaces/classes/IWasmHandler.ts index 4b96998..9f6dfca 100644 --- a/src/interfaces/classes/IWasmHandler.ts +++ b/src/interfaces/classes/IWasmHandler.ts @@ -2,16 +2,24 @@ import type { DDeliverTxResponse, DEncodeObject } from '@jackallabs/jackal.js-pr export interface IWasmHandler { instantiateICA ( + contractAddress: string, connectionIdA: string, - connectionIdB: string, - codeId: number, + connectionIdB: string ): Promise - getICAContractAddress (index?: number): Promise + reOpenChannel ( + contractAddress: string, + connectionIdA: string, + connectionIdB: string + ): Promise - getICAJackalAddress (): Promise + getICAContractAddress (contractAddress: string): Promise + + getICAJackalAddress (contractAddress: string): Promise getJackalAddressFromContract (contractAddress: string): Promise + getContractChannelState (contractAddress: string): Promise + wrapEncodeObjectsForBroadcast (contract: string, msgs: DEncodeObject[]): DEncodeObject[] } diff --git a/src/interfaces/options/IBroadcastOptions.ts b/src/interfaces/options/IBroadcastOptions.ts index 254e10d..0610ab1 100644 --- a/src/interfaces/options/IBroadcastOptions.ts +++ b/src/interfaces/options/IBroadcastOptions.ts @@ -6,4 +6,5 @@ export interface IBroadcastOptions { broadcastTimeoutHeight?: bigint monitorTimeout?: number socketOverrides?: TSocketSet + queryOverride?: string } diff --git a/src/utils/gas.ts b/src/utils/gas.ts index d6d09a3..b470394 100644 --- a/src/utils/gas.ts +++ b/src/utils/gas.ts @@ -5,7 +5,7 @@ const gasBaselineRate = 56 const gasFallbackTxCost = 142 const gasMap: Record = { /** Filetree */ - '/canine_chain.filetree.MsgPostFile': 270, + '/canine_chain.filetree.MsgPostFile': 570, '/canine_chain.filetree.MsgPostKey': 12, '/canine_chain.filetree.MsgDeleteFile': 9, /** Notifications */ diff --git a/src/utils/misc.ts b/src/utils/misc.ts index d2bcea7..19c0515 100644 --- a/src/utils/misc.ts +++ b/src/utils/misc.ts @@ -178,6 +178,7 @@ export function makeConnectionBundles ( feed: TxEvent[], msgs: DEncodeObject[], addr: string, + queryOverride: string | undefined, socketOverrides: TSocketSet, ): IIbcEngageBundle[] { const bundles: IIbcEngageBundle[] = [] @@ -200,7 +201,7 @@ export function makeConnectionBundles ( } } - const query = `${findQueryKey(url)} = '${addr}'` + const query = queryOverride || `${findQueryKey(url)} = '${addr}'` for (let id of networks) { const { chainId, endpoint } = socketOverrides[id] || sockets[id] console.log('makeConnectionBundles')