From 1ea235fb2b1837b81ea9df356ff5455fbff3095b Mon Sep 17 00:00:00 2001 From: jovonni Date: Fri, 16 Aug 2024 15:28:50 -0400 Subject: [PATCH 01/14] fix(Makefile): removed outdates dependency fixes from Makefile --- contract/Makefile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/contract/Makefile b/contract/Makefile index 37be559..0261e8c 100644 --- a/contract/Makefile +++ b/contract/Makefile @@ -258,11 +258,6 @@ e2e: yarn run build:deployer make copy-project kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn install" - kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn add @endo/patterns@1.3.0" - kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn add @agoric/orchestration@0.1.1-dev-9c9e5cf.0" - kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn add @agoric/vow@0.1.1-dev-9c9e5cf.0" - kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn add @agoric/async-flow@0.1.1-dev-9c9e5cf.0" - make copy-bn-js kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn build:deployer" kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn node scripts/deploy-contract.js --install src/orca.contract.js --eval src/orca.proposal.js" kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn node scripts/deploy-contract.js --install src/orca.contract.js --eval src/orca.proposal.js" From c462214f7db6668d23c6608f6fb687341a7f2f36 Mon Sep 17 00:00:00 2001 From: jovonni Date: Fri, 16 Aug 2024 15:29:56 -0400 Subject: [PATCH 02/14] fix(orca.contract.js): removed retriable wrapper --- contract/src/orca.contract.js | 96 ----------------------------------- 1 file changed, 96 deletions(-) diff --git a/contract/src/orca.contract.js b/contract/src/orca.contract.js index ce06ea6..0c5858d 100644 --- a/contract/src/orca.contract.js +++ b/contract/src/orca.contract.js @@ -78,105 +78,9 @@ const contract = async ( trace('inside start function: v1.1.95'); trace('privateArgs', privateArgs); - const wrapper = () => { - const transfer = vowTools.retriable( - zone, - 'transfer', - /** - * @type {Transfer} - */ - async ( - srcSeat, - localAccount, - remoteAccount, - give, - amt, - localAddress, - remoteAddress, - ) => { - !srcSeat.hasExited() || Fail`The seat cannot have exited.`; - const { zcfSeat: tempSeat, userSeat: userSeatP } = - zcf.makeEmptySeatKit(); - trace('tempSeat:', tempSeat); - const userSeat = await userSeatP; - trace('userSeat:', userSeat); - trace('storageNode', privateArgs.storageNode); - atomicTransfer(zcf, srcSeat, tempSeat, give); - tempSeat.exit(); - - const pmt = await E(userSeat).getPayout('Deposit'); - trace('pmt:', pmt); - trace('amt:', amt); - - // NOTE: with watch - // const promises = Object.entries(give).map(async ([kw, _amount]) => { - // trace("kw::", kw) - // trace("_amount", _amount) - // trace("amt", amt) - // }); - // const watcher = zone.exo( - // `watcher-transfer-${localAddress.value}-to-${remoteAddress.value}`, // Error: key (a string) has already been used in this zone and incarnation -- perhaps use timestamp or offerid as well? - // M.interface('watcher for transfer', { - // onFulfilled: M.call(M.any()).optional(M.any()).returns(VowShape), - // } - // ), - // { - // /** - // * @param {any} _result - // * @param {bigint} value - // */ - // onFulfilled( - // _result, - // value - // ) { - // trace("inside onFulfilled:", value) - // return watch(localAccount.transfer( - // { - // denom: "ubld", - // value: value/2n, - // }, - // remoteAddress - // )) - // }, - // }, - // ); - // trace("about to watch transfer, watcher v0.16") - // trace("watcher", watcher) - // watch( - // E(localAccount).deposit(pmt), - // watcher, - // BigInt(amt.value), - // ); - // await Promise.all(promises); - - // NOTE: without watcher - await E(localAccount).deposit(pmt); - await localAccount.transfer( - { - denom: 'ubld', - value: amt.value / 2n, - }, - remoteAddress, - ); - - // const localAccountBalance = await localAccount.getBalance(amt.brand) - // const remoteAccountbalance = await remoteAccount.getBalance(amt.brand) - // trace("localaccount balance: ", localAccountBalance); - // trace("remoteaccount balance: ", remoteAccountbalance); - }, - ); - return harden({ - transfer, - }); - }; - - const wrap = wrapper(); - trace('wrapper.transfer', wrapper); - // @ts-expect-error XXX ZCFSeat not Passable const { makeAccount, makeCreateAndFund } = orchestrateAll(flows, { localTransfer: zoeTools.localTransfer, - transfer: wrap.transfer, // write: E(storageNode).write), // makeChildNode: E(storageNode).makeChildNode, // setValue: E(storageNode).setValue, From edcafa9c0089d0d571a328fd4d6e9bbe200e7cf6 Mon Sep 17 00:00:00 2001 From: jovonni Date: Fri, 16 Aug 2024 15:30:59 -0400 Subject: [PATCH 03/14] fix(orca.flows.js): removed transfer retriable from createAndFund orchestration handler --- contract/src/orca.flows.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/contract/src/orca.flows.js b/contract/src/orca.flows.js index 2d1d373..110de3c 100644 --- a/contract/src/orca.flows.js +++ b/contract/src/orca.flows.js @@ -44,7 +44,7 @@ harden(makeAccount); * * @param {Orchestrator} orch * @param {object} ctx - * @param {Transfer} ctx.transfer + * @param {ZoeTools['localTransfer']} ctx.localTransfer * @param {StorageNode['setValue']} ctx.setValue * @param {ZCFSeat} seat * @param {{ chainName: string }} offerArgs @@ -52,7 +52,7 @@ harden(makeAccount); export const makeCreateAndFund = async ( orch, { - transfer, + localTransfer, // write, // makeChildNode, setValue, @@ -100,14 +100,12 @@ export const makeCreateAndFund = async ( trace('remoteAddress', remoteAddress); trace('fund new orch account'); trace('seat', seat); - trace('transfer', transfer); - await transfer( - seat, - localAccount, - remoteAccount, - give, - amt, - localAddress, + await localTransfer(seat, localAccount, give); + await localAccount.transfer( + { + denom: "ubld", + value: amt.value / 2n, + }, remoteAddress, ); seat.exit(); From cbd221371c37609c2853798f23801b28cfefe3e2 Mon Sep 17 00:00:00 2001 From: jovonni Date: Fri, 16 Aug 2024 15:34:23 -0400 Subject: [PATCH 04/14] fix(contract): fixed linting issues from changes --- contract/src/orca.contract.js | 5 +---- contract/src/orca.flows.js | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/contract/src/orca.contract.js b/contract/src/orca.contract.js index 0c5858d..9d64538 100644 --- a/contract/src/orca.contract.js +++ b/contract/src/orca.contract.js @@ -1,10 +1,7 @@ import { AmountShape } from '@agoric/ertp'; import { makeTracer } from '@agoric/internal'; import { withOrchestration } from '@agoric/orchestration/src/utils/start-helper.js'; -import { atomicTransfer } from '@agoric/zoe/src/contractSupport/index.js'; import { InvitationShape } from '@agoric/zoe/src/typeGuards.js'; -import { Fail } from '@endo/errors'; -import { E } from '@endo/far'; import { M } from '@endo/patterns'; import * as flows from './orca.flows.js'; @@ -73,7 +70,7 @@ const contract = async ( zcf, privateArgs, zone, - { orchestrateAll, vowTools, zoeTools }, + { orchestrateAll, zoeTools }, ) => { trace('inside start function: v1.1.95'); trace('privateArgs', privateArgs); diff --git a/contract/src/orca.flows.js b/contract/src/orca.flows.js index 110de3c..e1bfeec 100644 --- a/contract/src/orca.flows.js +++ b/contract/src/orca.flows.js @@ -103,7 +103,7 @@ export const makeCreateAndFund = async ( await localTransfer(seat, localAccount, give); await localAccount.transfer( { - denom: "ubld", + denom: 'ubld', value: amt.value / 2n, }, remoteAddress, From 4097624a9ac79e3efed8146f4a7ed4102a50bf0c Mon Sep 17 00:00:00 2001 From: jovonni Date: Tue, 20 Aug 2024 03:40:10 -0400 Subject: [PATCH 05/14] added osmosis funding ibc transfer step for testing delegations flow --- contract/Makefile | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contract/Makefile b/contract/Makefile index 0261e8c..31827bd 100644 --- a/contract/Makefile +++ b/contract/Makefile @@ -7,7 +7,7 @@ ATOM_DENOM=ibc/BA313C4A19DFBF943586C0387E6B11286F9E416B4DD27574E6909CABE0E342FA ATOM=000000$(ATOM_DENOM) # your deployer address made from make add-address -ADDR=agoric1mqvg26gpv6xzch2v0wpv569md3c2z4cdxq9clz +ADDR=agoric1aj5atgepztuv6qpl4a6993tvzthq4gdtvmgptj PROVISION_POOL_ADDR=agoric1megzytg65cyrgzs6fvzxgrcqvwwl7ugpt62346 PROPOSAL=1 @@ -152,8 +152,13 @@ fund: fund-provision-pool check-balance kubectl exec -i agoriclocal-genesis-0 -c validator -- agd tx bank send faucet ${CLIENTADDR} 10000000000000uist -y; make fund-osmo -fund-osmo: +fund-osmo: fund-osmo-ibc kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd tx bank send faucet ${CLIENT_OSMO_ADDR} 9870000000uosmo --fees 1000uosmo -y; + +fund-osmo-ibc: + kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd tx ibc-transfer transfer transfer channel-0 ${CLIENTADDR} 1000000uosmo --from faucet --chain-id osmosislocal --node http://127.0.0.1:26657 --fees 5000uosmo -y; + kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd tx ibc-transfer transfer transfer channel-1 ${CLIENTADDR} 1000000uosmo --from faucet --chain-id osmosislocal --node http://127.0.0.1:26657 --fees 5000uosmo -y; + check-balance: kubectl exec -i agoriclocal-genesis-0 -c validator -- agd q bank balances $(ADDR) fund-wallet: @@ -258,6 +263,10 @@ e2e: yarn run build:deployer make copy-project kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn install" + kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn add @endo/patterns@1.3.0" + # kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn add @agoric/orchestration@0.1.1-dev-9c9e5cf.0" + # kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn add @agoric/vow@0.1.1-dev-9c9e5cf.0" + # kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn add @agoric/async-flow@0.1.1-dev-9c9e5cf.0" kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn build:deployer" kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn node scripts/deploy-contract.js --install src/orca.contract.js --eval src/orca.proposal.js" kubectl exec -i agoriclocal-genesis-0 -c validator -- bash -c "yarn node scripts/deploy-contract.js --install src/orca.contract.js --eval src/orca.proposal.js" From 9455ae584de7d5c88e984daaff3b14bb381a593e Mon Sep 17 00:00:00 2001 From: jovonni Date: Tue, 20 Aug 2024 03:41:25 -0400 Subject: [PATCH 06/14] created make fund and delegation exo method, and guard, and added to orchestrateall --- contract/src/orca.contract.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/contract/src/orca.contract.js b/contract/src/orca.contract.js index 9d64538..7221420 100644 --- a/contract/src/orca.contract.js +++ b/contract/src/orca.contract.js @@ -76,7 +76,7 @@ const contract = async ( trace('privateArgs', privateArgs); // @ts-expect-error XXX ZCFSeat not Passable - const { makeAccount, makeCreateAndFund } = orchestrateAll(flows, { + const { makeAccount, makeCreateAndFund, makeFundAndDelegate } = orchestrateAll(flows, { localTransfer: zoeTools.localTransfer, // write: E(storageNode).write), // makeChildNode: E(storageNode).makeChildNode, @@ -89,6 +89,7 @@ const contract = async ( M.interface('Orca PF', { makeAccountInvitation: M.callWhen().returns(InvitationShape), makeCreateAndFundInvitation: M.callWhen().returns(InvitationShape), + makeFundAndDelegateInvitation: M.callWhen().returns(InvitationShape) }), { makeAccountInvitation() { @@ -102,6 +103,14 @@ const contract = async ( M.splitRecord({ give: SingleAmountRecord }), ); }, + makeFundAndDelegateInvitation() { + return zcf.makeInvitation( + makeFundAndDelegate, + 'Make an Orchestration Account, and Fund it', + undefined, + M.splitRecord({ give: SingleAmountRecord }) + ) + } }, ); From c159ead0aa52b1f93e615a5c433b425af16bde03 Mon Sep 17 00:00:00 2001 From: jovonni Date: Tue, 20 Aug 2024 03:42:10 -0400 Subject: [PATCH 07/14] added test skeleton for makeFundAndDelegate --- contract/test/orca-contract.test.js | 114 ++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/contract/test/orca-contract.test.js b/contract/test/orca-contract.test.js index 36d5706..e667b8d 100644 --- a/contract/test/orca-contract.test.js +++ b/contract/test/orca-contract.test.js @@ -589,5 +589,119 @@ const orchestrationAccountAndFundScenario = test.macro({ }, }); + +const orchestrationFundAndDelegateScenario = test.macro({ + title: (_, chainName) => + `orchestrate - ${chainName} makeAccount, fund local account, transfer to remote, and delegate to validator`, + exec: async (t, chainName) => { + const config = chainConfigs[chainName]; + if (!config) { + return t.fail(`unknown chain: ${chainName}`); + } + + const { + zoe, + bundle, + cosmosInterchainService, + agoricNames, + storageNode, + marshaller, + } = t.context; + t.log('installing the contract...'); + const installation = E(zoe).install(bundle); + + const privateArgs = harden({ + cosmosInterchainService, + orchestrationService: cosmosInterchainService, + storageNode, + marshaller, + timer: Far('DummyTimer'), + timerService: Far('DummyTimer'), + localchain: Far('DummyLocalchain'), + agoricNames, + }); + + const { mint, issuer, brand } = makeIssuerKit('BLD'); + + const issuers = { + BLDIssuer: issuer, + }; + + t.log('starting the instance...'); + const { instance } = await E(zoe).startInstance( + installation, + issuers, + {}, + privateArgs, + ); + t.log('instance started:', instance); + t.truthy(instance); + + t.log('getting public facet...'); + const publicFacet = await E(zoe).getPublicFacet(instance); + t.log('public facet obtained:', publicFacet); + + t.log('creating invitation for fund and delegate'); + const initialInvitation = + await E(publicFacet).makeFundAndDelegateInvitation(); + t.log('invitation created:', initialInvitation); + + t.log('brand', brand); + const amount = AmountMath.make(brand, 1n); + const makeAccountOffer = { + give: { Deposit: amount }, + want: {}, + exit: { onDemand: null }, + }; + + const bldPurse = issuer.makeEmptyPurse(); + const payment = mint.mintPayment(amount); + bldPurse.deposit(payment); + const withdrawnDeposit = await E(bldPurse).withdraw(amount); + t.log('withdrawnDeposit', withdrawnDeposit); + t.log('making offer...'); + const offerId = 'offerId'; + const initialUserSeat = await E(zoe).offer( + initialInvitation, + makeAccountOffer, + { + Deposit: withdrawnDeposit, + }, + { + id: offerId, + }, + ); + t.log('initial user seat:', initialUserSeat); + + t.log('getting offer result...'); + const offerResult = await E(initialUserSeat).getOfferResult(); + t.log('offer result:', offerResult); + t.truthy(offerResult, 'Offer result should exist'); + + const qt = makeQueryToolMock(); + const wallet = 'test-wallet'; + await logVstorageState(t, qt, 'published.agoricNames'); + + const { address, currentWalletRecord } = await queryVstorage( + t, + qt, + wallet, + offerId, + ); + + t.log('got address:', address); + t.regex( + address, + new RegExp(`^${config.expectedAddressPrefix}1`), + `Address for ${chainName} is valid`, + ); + t.log('current wallet record', currentWalletRecord); + + // todo: check delegation success? maybe invoke query? + }, +}); + test(orchestrationAccountScenario, 'osmosis'); test(orchestrationAccountAndFundScenario, 'osmosis'); +test(orchestrationFundAndDelegateScenario, 'osmosis'); + From fd22b03d66d4fa28121e341da918c9f3a52b0777 Mon Sep 17 00:00:00 2001 From: jovonni Date: Tue, 20 Aug 2024 03:43:16 -0400 Subject: [PATCH 08/14] added offer handler for fundAndDelegate to create->deposit->transfer->delegate --- contract/src/orca.flows.js | 60 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/contract/src/orca.flows.js b/contract/src/orca.flows.js index e1bfeec..bf002d9 100644 --- a/contract/src/orca.flows.js +++ b/contract/src/orca.flows.js @@ -112,3 +112,63 @@ export const makeCreateAndFund = async ( return remoteAccount.asContinuingOffer(); }; harden(makeCreateAndFund); + +/** + * Create an account on a Cosmos chain, transfer funds to it, and delegate + * + * @param {Orchestrator} orch + * @param {object} ctx + * @param {ZoeTools['localTransfer']} ctx.localTransfer + * @param {StorageNode['setValue']} ctx.setValue + * @param {ZCFSeat} seat + * @param {{ chainName: string, validator: string }} offerArgs + */ +export const makeFundAndDelegate = async ( + orch, + { + localTransfer, + // write, + // makeChildNode, + setValue, + }, + seat, + { chainName, validator }, +) => { + + const { give } = seat.getProposal(); + const [[_kw, amt]] = Object.entries(give); + + const [agoric, chain] = await Promise.all([ + orch.getChain('agoric'), + orch.getChain(chainName), + ]); + + const info = await chain.getChainInfo(); + trace('chain info', info); + const assets = await agoric.getVBankAssetInfo(); + trace('fetched assets:', assets); + const localAccount = await agoric.makeAccount(); + trace('localAccount', localAccount); + const remoteAccount = await chain.makeAccount(); + trace('remoteAccount', remoteAccount); + const [localAddress, remoteAddress] = await Promise.all([ + localAccount.getAddress(), + remoteAccount.getAddress(), + ]); + + await localTransfer(seat, localAccount, give); + await localAccount.transfer( + { + denom: 'ubld', + value: amt.value / 2n, + }, + remoteAddress, + ); + await remoteAccount.delegate(validator, { + brand: amt.brand, + value: 1n + }); + seat.exit(); + return remoteAccount.asContinuingOffer(); +}; +harden(makeFundAndDelegate); From c7f0b8bc0685d16681d78bf55c6bd1c9d5f133bc Mon Sep 17 00:00:00 2001 From: jovonni Date: Tue, 20 Aug 2024 04:29:58 -0400 Subject: [PATCH 09/14] chore: some tracing, debugging brand --- contract/src/orca.flows.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/contract/src/orca.flows.js b/contract/src/orca.flows.js index bf002d9..1f08f32 100644 --- a/contract/src/orca.flows.js +++ b/contract/src/orca.flows.js @@ -135,9 +135,14 @@ export const makeFundAndDelegate = async ( { chainName, validator }, ) => { + trace('inside makeFundAndDelegate') const { give } = seat.getProposal(); const [[_kw, amt]] = Object.entries(give); - + trace('_kw', _kw); + trace('amt', amt); + trace('give:', give); + trace("chainName:", chainName) + trace("validator:", validator) const [agoric, chain] = await Promise.all([ orch.getChain('agoric'), orch.getChain(chainName), @@ -159,7 +164,7 @@ export const makeFundAndDelegate = async ( await localTransfer(seat, localAccount, give); await localAccount.transfer( { - denom: 'ubld', + denom: amt.brand, value: amt.value / 2n, }, remoteAddress, From dfdaedaf2dcedaed04cec930159f3a0946506b6b Mon Sep 17 00:00:00 2001 From: jovonni Date: Tue, 20 Aug 2024 04:32:21 -0400 Subject: [PATCH 10/14] feat: passing delegations in props, and layout --- .../components/Orchestration/AccountList.tsx | 126 ++++++++---------- .../Orchestration/Orchestration.tsx | 48 +++++++ 2 files changed, 105 insertions(+), 69 deletions(-) diff --git a/ui/src/components/Orchestration/AccountList.tsx b/ui/src/components/Orchestration/AccountList.tsx index dd5527a..157e821 100644 --- a/ui/src/components/Orchestration/AccountList.tsx +++ b/ui/src/components/Orchestration/AccountList.tsx @@ -7,6 +7,7 @@ const tokenLogos = { const AccountList = ({ balances, + delegations, loadingDeposit, handleDeposit, loadingWithdraw, @@ -17,88 +18,75 @@ const AccountList = ({ handleUnstake, guidelines, }) => { + + console.log("delegations", delegations); + return ( -
+

Accounts

- {balances.map((balance, idx) => ( -
-
-
-
Address
-
- {balance.address.slice(0, 10)}...{balance.address.slice(-10)} + {balances.map((balance, idx) => { + const delegation = delegations.find(d => d.address === balance.address); + + return ( +
+
+
+
Address
+
+ {balance.address.slice(0, 10)}...{balance.address.slice(-10)} +
-
-
- {balance.balances.map((bal, idx) => ( -
-
-
-
- {`${bal.denom} +
+ {balance.balances.map((bal, idx) => ( +
+
+
+
+ {`${bal.denom} +
+
+ {bal.denom.toUpperCase()} +
+
{bal.amount}
-
- {bal.denom.toUpperCase()} -
-
{bal.amount}
+ ))} +
+ + {/* Amount Staked Section */} +
+
Amount Staked
+
+ {delegation && delegation.delegations.length > 0 + ? delegation.delegations.map(d => `${d.amount} ${d.denom}`).join(', ') + : '0.00 ubld'}
- ))} +
-
-
-
- - - - +
+
+ + + + +
-
- ))} + ); + })}
); }; -export default AccountList; +export default AccountList; \ No newline at end of file diff --git a/ui/src/components/Orchestration/Orchestration.tsx b/ui/src/components/Orchestration/Orchestration.tsx index 909d5e5..f64532f 100644 --- a/ui/src/components/Orchestration/Orchestration.tsx +++ b/ui/src/components/Orchestration/Orchestration.tsx @@ -247,6 +247,54 @@ const Orchestration = () => { setLoadingUnstake(prevState => ({ ...prevState, [address]: false })); }; + const executeFundAndDelegate = () => { + setLoadingCreateAndFund(true); + setStatusText('Submitted'); + if (walletConnection) { + // const { brands } = useContractStore.getState(); + + const give = { Deposit: { brand: fundDenom, value: BigInt(fundAmount)} }; + + makeOffer( + walletConnection, + addNotification!, + selectedChain, + 'makeFundAndDelegateInvitation', + { + chainName: selectedChain, + validator: "osmovaloper1qjtcxl86z0zua2egcsz4ncff2gzlcndzs93m43" + }, + setLoadingCreateAndFund, + handleToggle, + setStatusText, + give + ).catch(error => { + addNotification!({ + text: `Transaction failed: ${error.message}`, + status: 'error', + }); + setLoadingCreateAndFund(false); + handleToggle(); + }); + } else { + addNotification!({ + text: 'Error: Please connect your wallet or check your connection to RPC endpoints', + status: 'error', + }); + setLoadingCreateAndFund(false); + handleToggle(); + } + }; + + const openFundModal = async () => { + setModalContent('Fund and Delegate'); + const client = walletConnection.signingClient; + const accountAddress = walletConnection.address; + const balances = await client.getAllBalances(accountAddress); + setWalletBalances([...balances]); + handleToggle(); + }; + return (
From 5afc21b7e513803dc3e5afbbfdcaa32c2f725709 Mon Sep 17 00:00:00 2001 From: jovonni Date: Tue, 20 Aug 2024 04:33:00 -0400 Subject: [PATCH 11/14] feat: passing openFundModal and loadingFundAndDelegate as props to create button group --- .../Orchestration/CreateAccountButton.tsx | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/ui/src/components/Orchestration/CreateAccountButton.tsx b/ui/src/components/Orchestration/CreateAccountButton.tsx index 1e8f80b..79c338b 100644 --- a/ui/src/components/Orchestration/CreateAccountButton.tsx +++ b/ui/src/components/Orchestration/CreateAccountButton.tsx @@ -1,12 +1,16 @@ -import { FaUserPlus, FaWallet } from 'react-icons/fa'; // Importing icons from react-icons +import { FaUserPlus, FaWallet, FaMoneyCheckAlt, FaChartLine } from 'react-icons/fa'; const CreateAccountButton = ({ handleCreateAccount, handleCreateAndFund, + openFundModal, loadingCreateAccount, loadingCreateAndFund, + loadingFundAndDelegate }) => ( -
+ //
+
+ + + +
); From 8e82be36c998b57fcbe3b2fac43f73af30b7a022 Mon Sep 17 00:00:00 2001 From: jovonni Date: Tue, 20 Aug 2024 04:33:38 -0400 Subject: [PATCH 12/14] chore: passing give as argument, debugging brand issue --- ui/src/components/Orchestration/MakeOffer.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ui/src/components/Orchestration/MakeOffer.tsx b/ui/src/components/Orchestration/MakeOffer.tsx index 1959382..37c43e9 100644 --- a/ui/src/components/Orchestration/MakeOffer.tsx +++ b/ui/src/components/Orchestration/MakeOffer.tsx @@ -11,6 +11,7 @@ export const makeOffer = async ( setLoading: React.Dispatch>, handleToggle: () => void, setStatusText: React.Dispatch>, + give?: Record, ) => { if (!selectedChain) { addNotification({ @@ -23,6 +24,7 @@ export const makeOffer = async ( } const { instances, brands } = useContractStore.getState(); + console.log(brands); const instance = instances?.['orca']; if (!instance || !brands) { @@ -32,15 +34,15 @@ export const makeOffer = async ( } // fetch the BLD brand - const bldBrand = brands.BLD; - if (!bldBrand) { - setLoading(false); - handleToggle(); - throw Error('BLD brand not found.'); - } + // const bldBrand = brands.BLD; + // if (!bldBrand) { + // setLoading(false); + // handleToggle(); + // throw Error('BLD brand not found.'); + // } const want = {}; - const give = { Deposit: { brand: bldBrand, value: BigInt(1000) } }; + // const give = { Deposit: { brand: bldBrand, value: BigInt(1000) } }; const offerId = Date.now(); From 0bac018e0e54f0f465713e3743842ba19feb442a Mon Sep 17 00:00:00 2001 From: jovonni Date: Tue, 20 Aug 2024 04:34:57 -0400 Subject: [PATCH 13/14] feat: fetch delegations, submit fundAndDelegate offer, delegations modal foundation --- .../Orchestration/Orchestration.tsx | 105 +++++++++++++++--- 1 file changed, 89 insertions(+), 16 deletions(-) diff --git a/ui/src/components/Orchestration/Orchestration.tsx b/ui/src/components/Orchestration/Orchestration.tsx index f64532f..dab7d14 100644 --- a/ui/src/components/Orchestration/Orchestration.tsx +++ b/ui/src/components/Orchestration/Orchestration.tsx @@ -7,6 +7,7 @@ import AccountList from './AccountList'; import ChainSelector from './ChainSelector'; import CreateAccountButton from './CreateAccountButton'; import { fetchBalances } from './FetchBalances'; +import { fetchDelegations } from './FetchDelegations'; import { initializeKeplr } from './KeplrInitializer'; import { makeOffer } from './MakeOffer'; import RpcEndpoints from './RpcEndpoints'; @@ -16,6 +17,9 @@ const Orchestration = () => { const { addNotification } = useContext(NotificationContext); const icas = useContractStore(state => state.icas); const [balances, setBalances] = useState([]); + const [walletBalances, setWalletBalances] = useState([]); + const [delegations, setDelegations] = useState([]); + const [selectedChain, setSelectedChain] = useState(''); const [loadingDeposit, setLoadingDeposit] = useState<{ [key: string]: boolean; @@ -35,6 +39,8 @@ const Orchestration = () => { const [modalOpen, setModalOpen] = useState(false); const [modalAddress, setModalAddress] = useState(''); const [selectedDenom, setSelectedDenom] = useState('uist'); + const [fundDenom, setFundDenom] = useState('uist'); + const [fundAmount, setFundAmount] = useState(0); const [amount, setAmount] = useState(0); const [statusText, setStatusText] = useState(''); const modalRef = useRef(null); @@ -47,8 +53,12 @@ const Orchestration = () => { useEffect(() => { const loadBalances = async () => { try { - const fetchedBalances = await fetchBalances(icas); + const [fetchedBalances, fetchedDelegations] = await Promise.all([ + fetchBalances(icas), + fetchDelegations(icas), + ]); setBalances(fetchedBalances); + setDelegations(fetchedDelegations); } catch (error) { console.error('failed to fetch balances:', error); } @@ -87,6 +97,7 @@ const Orchestration = () => { setLoadingCreateAccount, handleToggle, setStatusText, + {} ).catch(error => { addNotification!({ text: `Transaction failed: ${error.message}`, @@ -102,8 +113,8 @@ const Orchestration = () => { }); setLoadingCreateAccount(false); handleToggle(); - setLoadingCreateAccount(false); - handleToggle(); + // setLoadingCreateAccount(false); + // handleToggle(); } }; @@ -113,6 +124,10 @@ const Orchestration = () => { setStatusText('Submitted'); if (walletConnection) { openModal('Create & Fund Account...', selectedChain); + + const { brands } = useContractStore.getState(); + const give = { Deposit: { brand: brands.BLD, value: BigInt(1000) } }; + makeOffer( walletConnection, addNotification!, @@ -122,6 +137,7 @@ const Orchestration = () => { setLoadingCreateAndFund, handleToggle, setStatusText, + give ).catch(error => { addNotification!({ text: `Transaction failed: ${error.message}`, @@ -140,7 +156,15 @@ const Orchestration = () => { } }; - const handleDeposit = (address: string) => { + const handleDeposit = async (address: string) => { + try { + const client = walletConnection.signingClient; + const accountAddress = walletConnection.address; + const balances = await client.getAllBalances(accountAddress); + setWalletBalances([...balances]); + } catch (error) { + console.error('Failed to fetch wallet balances:', error); + } openModal('Deposit', address); }; @@ -303,6 +327,7 @@ const Orchestration = () => { > { handleCreateAndFund={handleCreateAndFund} loadingCreateAccount={loadingCreateAccount} loadingCreateAndFund={loadingCreateAndFund} + openFundModal={openFundModal} />
@@ -365,18 +391,22 @@ const Orchestration = () => { {modalContent === 'Deposit' && (
+ Select Denom +
+ + +
+
)} + {modalContent === 'Fund and Delegate' && ( +
+ + +
+ + +
+
+ )}
From 0273c180930d936c4aac434236598c0fcb196ceb Mon Sep 17 00:00:00 2001 From: jovonni Date: Tue, 20 Aug 2024 04:36:21 -0400 Subject: [PATCH 14/14] feat: added fetch delegations function --- .../Orchestration/FetchDelegations.tsx | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 ui/src/components/Orchestration/FetchDelegations.tsx diff --git a/ui/src/components/Orchestration/FetchDelegations.tsx b/ui/src/components/Orchestration/FetchDelegations.tsx new file mode 100644 index 0000000..d682ee3 --- /dev/null +++ b/ui/src/components/Orchestration/FetchDelegations.tsx @@ -0,0 +1,50 @@ +import { StargateClient } from '@cosmjs/stargate'; + +const rpcEndpoints = { + osmosis: 'http://127.0.0.1:26655', + agoric: 'http://127.0.0.1:26657', +}; + +export const fetchDelegations = async (addresses: string[]) => { + return Promise.all( + addresses.map(async address => { + console.log('fetching delegations for address:', address); + let chain = ''; + if (address.startsWith('osmo1')) { + chain = 'osmosis'; + } else if (address.startsWith('agoric1')) { + chain = 'agoric'; + } else { + return { + address, + delegations: [], + }; + } + + const rpcEndpoint = rpcEndpoints[chain]; + try { + const delegations = await fetchDelegationsFromRpc(address, rpcEndpoint); + return { + address, + delegations, + }; + } catch (e) { + console.error('error fetching delegations:', e); + return { + address, + delegations: [], + }; + } + }), + ); +}; + +const fetchDelegationsFromRpc = async (address: string, rpcEndpoint: string) => { + const client = await StargateClient.connect(rpcEndpoint); + const delegations = await client.getDelegation(address); + return delegations.map(delegation => ({ + validatorAddress: delegation.delegation.validator_address, + amount: delegation.balance.amount, + denom: delegation.balance.denom, + })); +}; \ No newline at end of file