From 5eff63fa0cd789ec6c2065eab2afab1e9c2f82a6 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:25:25 -0400 Subject: [PATCH 01/42] feat: switch from soroban-react to generated libs --- README.md | 11 - components/atoms/connect-button/index.tsx | 16 +- components/molecules/deposits/index.tsx | 28 +- components/molecules/form-pledge/index.tsx | 291 +- components/molecules/wallet-data/index.tsx | 26 +- components/organisms/pledge/index.tsx | 160 +- convert.ts | 239 +- hooks/useAccount.tsx | 61 +- initialize.sh | 1 + package-lock.json | 4432 ++------------------ package.json | 23 +- pages/_app.tsx | 21 +- shared/utils.tsx | 16 +- tsconfig.json | 2 +- 14 files changed, 728 insertions(+), 4599 deletions(-) diff --git a/README.md b/README.md index 71f3a116..9872ac8f 100755 --- a/README.md +++ b/README.md @@ -148,14 +148,3 @@ Then via the web UI, users should be able to: - Deposit an allowed asset - See their deposit(s) appear on the page as the transactions are confirmed. - "Live"-Update the page with the total amount with the new amount - -Wallet Integration & Data Fetching -================================== - -There is a `./wallet` directory, which contains a small library to connect to -the user's freighter wallet, as well as some React hooks to talk to a -soroban-rpc server (e.g. `soroban-cli serve`), to fetch data and send -transactions. - -Data from contracts is fetched using the `useContractValue` hook from @soroban-react/contracts. Transactions are submitted to the network -using the `useSendTransaction` from @soroban-react/contracts. diff --git a/components/atoms/connect-button/index.tsx b/components/atoms/connect-button/index.tsx index 4457898e..0a35efcf 100644 --- a/components/atoms/connect-button/index.tsx +++ b/components/atoms/connect-button/index.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { useSorobanReact } from '@soroban-react/core' +import { getPublicKey } from '@stellar/freighter-api' import styles from './style.module.css' export interface ConnectButtonProps { @@ -8,9 +8,19 @@ export interface ConnectButtonProps { } export function ConnectButton({ label, isHigher }: ConnectButtonProps) { - const { connect } = useSorobanReact() const openConnectModal = async () => { - await connect() + // Freighter currently lacks a way to get the public key without also + // popping a modal, or open a modal explicitly. + // See https://github.com/stellar/freighter/issues/830 + // + // You could work around this by storing some state in localStorage, or you + // could send a PR to the Freighter team and fix this for everyone who uses + // Freighter! + // + // Eventually, you will want to stop relying on Freighter explicitly, + // preferring a higher-level wallet/account abstraction that allows users + // to choose whichever wallet hardware/software they prefer. + await getPublicKey() } return ( diff --git a/components/molecules/deposits/index.tsx b/components/molecules/deposits/index.tsx index 00b9869c..a42fb63b 100644 --- a/components/molecules/deposits/index.tsx +++ b/components/molecules/deposits/index.tsx @@ -1,15 +1,8 @@ import React from 'react' -import * as SorobanClient from 'soroban-client' import styles from './style.module.css' import { Utils } from '../../../shared/utils' import { Spacer } from '../../atoms/spacer' -import * as convert from '../../../convert' -import { Constants } from '../../../shared/constants' -import { - ContractValueType, - useContractValue, -} from '@soroban-react/contracts' -import { useSorobanReact } from '@soroban-react/core' +import { balance as getBalance } from 'crowdfund-contract' export interface IDepositsProps { address: string @@ -20,19 +13,14 @@ export interface IDepositsProps { } export function Deposits(props: IDepositsProps) { - const useLoadDeposits = (): ContractValueType => { - return useContractValue({ - contractId: props.idCrowdfund, - method: 'balance', - params: [new SorobanClient.Address(props.address).toScVal()], - sorobanContext: useSorobanReact() - }) - } + const [balance, setBalance] = React.useState(BigInt(0)) + + React.useEffect(() => { + getBalance({ user: props.address }).then(setBalance) + }, [props.address]) - let yourDepositsXdr = useLoadDeposits() - const yourDeposits = convert.scvalToBigNumber(yourDepositsXdr.result) - if (yourDeposits.toNumber() <= 0) { + if (Number(balance) <= 0) { return } @@ -42,7 +30,7 @@ export function Deposits(props: IDepositsProps) {
You’ve Pledged
- {Utils.formatAmount(yourDeposits, props.decimals)}{' '} + {Utils.formatAmount(balance, props.decimals)}{' '} {props.symbol} {/* diff --git a/components/molecules/form-pledge/index.tsx b/components/molecules/form-pledge/index.tsx index b4102bc5..2305c62f 100644 --- a/components/molecules/form-pledge/index.tsx +++ b/components/molecules/form-pledge/index.tsx @@ -3,14 +3,11 @@ import { AmountInput, Button, Checkbox } from '../../atoms' import { TransactionModal } from '../../molecules/transaction-modal' import { Utils } from '../../../shared/utils' import styles from './style.module.css' -import { useSendTransaction, useContractValue, contractTransaction } from '@soroban-react/contracts' -import { useSorobanReact } from '@soroban-react/core' import * as SorobanClient from 'soroban-client' -import BigNumber from 'bignumber.js' -import * as convert from '../../../convert' import { Constants } from '../../../shared/constants' import { Spacer } from '../../atoms/spacer' -let xdr = SorobanClient.xdr +import { deposit } from 'crowdfund-contract' +import * as ft from 'ft-contract' export interface IFormPledgeProps { account: string @@ -23,57 +20,125 @@ export interface IFormPledgeProps { export interface IResultSubmit { status: string - scVal?: SorobanClient.xdr.ScVal error?: string - value?: number - symbol?: string } -const FormPledge: FunctionComponent = props => { - const sorobanContext = useSorobanReact() - +/** + * Mint 100.0000000 tokens to the user's wallet for testing + */ +function MintButton({ account, symbol }: { account: string; symbol: string }) { + const [isSubmitting, setSubmitting] = useState(false) - // Call the contract to get user's balance of the token - const useLoadToken = (): any => { - return { - userBalance: useContractValue({ - contractId: Constants.TokenId, - method: 'balance', - params: [new SorobanClient.Address(props.account).toScVal()], - sorobanContext - }), - decimals: useContractValue({ - contractId: Constants.TokenId, - method: 'decimals', - sorobanContext - }), - symbol: useContractValue({ - contractId: Constants.TokenId, - method: 'symbol', - sorobanContext - }), - } - } + const amount = BigInt(100) - let token = useLoadToken() - const userBalance = convert.scvalToBigNumber(token.userBalance.result) - const tokenDecimals = - token.decimals.result && (token.decimals.result?.u32() ?? 7) - const tokenSymbol = - token.symbol.result && convert.scvalToString(token.symbol.result)?.replace("\u0000", "") + return ( +
@@ -196,124 +247,6 @@ const FormPledge: FunctionComponent = props => { )} ) - - // MintButton mints 100.0000000 tokens to the user's wallet for testing - function MintButton({ - account, - decimals, - symbol, - }: { - account: string - decimals: number - symbol: string - }) { - const [isSubmitting, setSubmitting] = useState(false) - const server = sorobanContext.server - const networkPassphrase = sorobanContext.activeChain?.networkPassphrase - - - const { sendTransaction } = useSendTransaction() - const amount = BigNumber(100) - - return ( - diff --git a/hooks/useAccount.tsx b/hooks/useAccount.tsx index bc30653c..859e3f9d 100644 --- a/hooks/useAccount.tsx +++ b/hooks/useAccount.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from "react"; -import { getPublicKey } from "@stellar/freighter-api"; +import { getUserInfo } from "@stellar/freighter-api"; -let address: Awaited>; +let address: string; -let addressLookup = getPublicKey() +let addressLookup = getUserInfo() // returning the same object identity every time avoids unnecessary re-renders const addressObject = { @@ -37,7 +37,7 @@ export function useAccount(): typeof addressObject | null { if (address !== undefined) return; addressLookup - .then((publicKey) => { address = publicKey }) + .then(({ publicKey }) => { address = publicKey }) .catch(() => { address = '' }) .finally(() => { setLoading(false) }); }, []); diff --git a/package-lock.json b/package-lock.json index d2edfb35..b75512ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@radix-ui/react-dialog": "1.0.2", "@soroban-react/chains": "^5.0.3", "@soroban-react/events": "^5.0.3", - "@stellar/freighter-api": "^1.4.0", + "@stellar/freighter-api": "^1.5.0", "axios": "^0.27.2", "bigint-conversion": "^2.4.1", "humanize-duration": "^3.27.3", @@ -611,9 +611,9 @@ "integrity": "sha512-bzouh+upQOJ19qjtfGb2K9GN1r0n/dxtgsyK8Rml6hC19HZFHIjcmgpdwvvvSLXuU+9XPlBsTWJm/YhYxDiWew==" }, "node_modules/@stellar/freighter-api": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-1.4.0.tgz", - "integrity": "sha512-/ANu1/4mnReUvrSDveKj5XhrnafEssESF/lVdOR1v0ja02kFuhsdsw3anzdz0NvPaPbFgPmjU+v9t9R8KN6r+g==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-1.5.0.tgz", + "integrity": "sha512-j9bAo3U7UJ0jaEGhKkCcmAiRJ67xUG1Ty3N8dVb65WVkEdXtxEfFtPuRcsr9brX9sHeN+s2caS6KQL8FYZqixg==" }, "node_modules/@swc/helpers": { "version": "0.5.1", diff --git a/package.json b/package.json index 25ef4773..4d0c21fb 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@radix-ui/react-dialog": "1.0.2", "@soroban-react/chains": "^5.0.3", "@soroban-react/events": "^5.0.3", - "@stellar/freighter-api": "^1.4.0", + "@stellar/freighter-api": "^1.5.0", "axios": "^0.27.2", "bigint-conversion": "^2.4.1", "humanize-duration": "^3.27.3", From ac00a3be0b8d2d1b13d34244ff25551efb391cee Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Fri, 16 Jun 2023 12:21:54 -0400 Subject: [PATCH 28/42] feat: straightforward copy/paste of subscribe logic This gets the subscriptions working, and finally breaks all dependence on the @soroban-react packages. The logic is a little confusing, but it works! --- components/AlmostUnnecessaryProvider.tsx | 27 ------- components/organisms/pledge/index.tsx | 94 ++++++++++++++++++++---- package-lock.json | 51 ------------- package.json | 2 - pages/_app.tsx | 5 +- 5 files changed, 81 insertions(+), 98 deletions(-) delete mode 100644 components/AlmostUnnecessaryProvider.tsx diff --git a/components/AlmostUnnecessaryProvider.tsx b/components/AlmostUnnecessaryProvider.tsx deleted file mode 100644 index 9f0fe72d..00000000 --- a/components/AlmostUnnecessaryProvider.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react' -import {SorobanReactProvider} from '@soroban-react/core'; -import {SorobanEventsProvider} from '@soroban-react/events'; -import {futurenet, sandbox, standalone} from '@soroban-react/chains'; -import {freighter} from '@soroban-react/freighter'; -import {ChainMetadata, Connector} from "@soroban-react/types"; - -const chains: ChainMetadata[] = [sandbox, standalone, futurenet]; -const connectors: Connector[] = [freighter()]; - -/** - * This machinery is needed for @soroban-react/events functionality, which - * we still need until event subscriptions are implemented in the libraries - * generated with `soroban contract bindings typescript` - */ -export default function AlmostUnnecessaryProvider({children}:{children: React.ReactNode}) { - return ( - - - {children} - - - ) -} diff --git a/components/organisms/pledge/index.tsx b/components/organisms/pledge/index.tsx index 8ac3e372..33817e34 100644 --- a/components/organisms/pledge/index.tsx +++ b/components/organisms/pledge/index.tsx @@ -12,13 +12,18 @@ import * as abundanceContract from 'abundance-token' import * as SorobanClient from 'soroban-client' import { Deposits, FormPledge } from '../../molecules' import * as convert from '../../../convert' -import { useSorobanEvents, EventSubscription } from '@soroban-react/events' let xdr = SorobanClient.xdr +const pollInterval = 5000 + +// TODO: update js-soroban-client to include latestLedger +interface GetEventsWithLatestLedger extends SorobanClient.SorobanRpc.GetEventsResponse { + latestLedger?: string; +} + const Pledge: FunctionComponent = () => { const [loadedAt, setLoadedAt] = React.useState(Date.now()) const account = useAccount() - const sorobanEventsContext = useSorobanEvents() const [abundance, setAbundance] = React.useState<{ balance: BigInt @@ -58,30 +63,91 @@ const Pledge: FunctionComponent = () => { const [targetReached, setTargetReached] = useState(false) - const crowdfundPledgedEventSubscription = useRef({ - contractId: crowdfundContract.CONTRACT_ID, + const subscriptions: { + contractId: string + topics: string[] + cb: (event: { value: { xdr: string } }) => void + lastLedgerStart?: number + pagingToken?: string + }[] = React.useMemo(() => [ + { + contractId: crowdfundContract.CONTRACT_ID_HEX, topics: ['pledged_amount_changed'], cb: (event) => { let eventTokenBalance = xdr.ScVal.fromXDR(event.value.xdr, 'base64') setAbundance({ ...abundance!, balance: convert.scvalToBigInt(eventTokenBalance) }) }, - id: Math.random()} as EventSubscription); - - const crowdfundTargetReachedSubscription = useRef({ - contractId: crowdfundContract.CONTRACT_ID, + }, + { + contractId: crowdfundContract.CONTRACT_ID_HEX, topics: ['target_reached'], cb: () => { setTargetReached(true) }, - id: Math.random()} as EventSubscription); + }, + ], [abundance, setTargetReached]) React.useEffect(() => { - const pledgedSubId = sorobanEventsContext.subscribe(crowdfundPledgedEventSubscription.current) - const reachedSubId = sorobanEventsContext.subscribe(crowdfundTargetReachedSubscription.current) + let timeoutId: NodeJS.Timer | null = null + let stop = false + + async function pollEvents(): Promise { + try { + for (const subscription of subscriptions) { + if (!subscription.lastLedgerStart) { + let latestLedgerState = await crowdfundContract.Server.getLatestLedger(); + subscription.lastLedgerStart = latestLedgerState.sequence + } + + const subscriptionTopicXdrs: Array = [] + subscription.topics && subscription.topics.forEach( topic => { + subscriptionTopicXdrs.push( xdr.ScVal.scvSymbol(topic).toXDR("base64")); + }) + + // TODO: use rpc batch for single round trip, each subscription can be one + // getEvents request in the batch, is that possible now? + let response = await crowdfundContract.Server.getEvents({ + startLedger: !subscription.pagingToken ? subscription.lastLedgerStart : undefined, + cursor: subscription.pagingToken, + filters: [ + { + contractIds: [subscription.contractId], + topics: [subscriptionTopicXdrs], + type: "contract" + } + ], + limit: 10 + }) as GetEventsWithLatestLedger; + + delete subscription.pagingToken; + if (response.latestLedger) { + subscription.lastLedgerStart = parseInt(response.latestLedger); + } + response.events && response.events.forEach(event => { + try { + subscription.cb(event) + } catch (error) { + console.error("Poll Events: subscription callback had error: ", error); + } finally { + subscription.pagingToken = event.pagingToken + } + }) + } + } catch (error) { + console.error("Poll Events: error: ", error); + } finally { + if (!stop) { + timeoutId = setTimeout(pollEvents, pollInterval); + } + } + } + + pollEvents(); return () => { - sorobanEventsContext.unsubscribe(pledgedSubId); - sorobanEventsContext.unsubscribe(reachedSubId); + if (timeoutId != null) clearTimeout(timeoutId) + stop = true } - }, [sorobanEventsContext]); + }, [subscriptions]); + return ( diff --git a/package-lock.json b/package-lock.json index b75512ca..5fb2454c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,6 @@ "hasInstallScript": true, "dependencies": { "@radix-ui/react-dialog": "1.0.2", - "@soroban-react/chains": "^5.0.3", - "@soroban-react/events": "^5.0.3", "@stellar/freighter-api": "^1.5.0", "axios": "^0.27.2", "bigint-conversion": "^2.4.1", @@ -561,55 +559,6 @@ "integrity": "sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==", "dev": true }, - "node_modules/@soroban-react/chains": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@soroban-react/chains/-/chains-5.0.3.tgz", - "integrity": "sha512-+jfoWayEGRqEIgJuMj6JxFJV0af+YNh0fXARkRifkywsu3ZUbC2j1fRL2bFPW3bDpN/wA9aYQ4+YuKU9Sg68Rg==", - "dependencies": { - "@soroban-react/types": "^5.0.3", - "soroban-client": "0.8.0" - } - }, - "node_modules/@soroban-react/core": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@soroban-react/core/-/core-5.0.3.tgz", - "integrity": "sha512-oAx9w4ItF+wWDK2VFdnZhok656rw8AATvh8BTOfmC1bt4rzQVk6EjJkZKkCGMJBhnIxjXreYGr3MPTp26+cc5Q==", - "dependencies": { - "@soroban-react/freighter": "^5.0.3", - "@soroban-react/types": "^5.0.3", - "soroban-client": "0.8.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/@soroban-react/events": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@soroban-react/events/-/events-5.0.3.tgz", - "integrity": "sha512-PTY3BYFgDj9VcnsKNJEgsEYmNZpkrg7fBRKglT1XcYvi40TWs7R0LD7fPp4ZHnMpp8LlVzURsr9+iCl3abqzTA==", - "dependencies": { - "@soroban-react/core": "^5.0.3", - "@soroban-react/types": "^5.0.3", - "soroban-client": "0.8.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/@soroban-react/freighter": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@soroban-react/freighter/-/freighter-5.0.3.tgz", - "integrity": "sha512-kgMVJ7xJppzDSsXBFZWZ+VESX00uFFiQhEBPkXxokkWlmKcviNVb9Z43wiqe3aTtNm83kF0rxaagEMIhl4/fwA==", - "dependencies": { - "@soroban-react/types": "^5.0.3", - "@stellar/freighter-api": "^1.4.0" - } - }, - "node_modules/@soroban-react/types": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@soroban-react/types/-/types-5.0.3.tgz", - "integrity": "sha512-bzouh+upQOJ19qjtfGb2K9GN1r0n/dxtgsyK8Rml6hC19HZFHIjcmgpdwvvvSLXuU+9XPlBsTWJm/YhYxDiWew==" - }, "node_modules/@stellar/freighter-api": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-1.5.0.tgz", diff --git a/package.json b/package.json index 4d0c21fb..5864ab7a 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,6 @@ }, "dependencies": { "@radix-ui/react-dialog": "1.0.2", - "@soroban-react/chains": "^5.0.3", - "@soroban-react/events": "^5.0.3", "@stellar/freighter-api": "^1.5.0", "axios": "^0.27.2", "bigint-conversion": "^2.4.1", diff --git a/pages/_app.tsx b/pages/_app.tsx index 58b04fc4..2adccdd1 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,13 +1,10 @@ import type { AppProps } from 'next/app' import '../styles/globals.css' -import AlmostUnnecessaryProvider from '../components/AlmostUnnecessaryProvider'; function MyApp({ Component, pageProps }: AppProps) { return ( - - - + ); } From 4c86660d2353dd89b2c391bca2b871e183553f83 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:54:06 -0400 Subject: [PATCH 29/42] feat: move subscribe logic to useSubscription hook This is a hook that can be copy/pasted into other React projects that need such functionality, to work alongside their generated libraries until these generated libraries expose subscription logic natively. --- components/organisms/pledge/index.tsx | 103 ++------------------ hooks/index.ts | 3 + hooks/index.tsx | 2 - hooks/{useAccount.tsx => useAccount.ts} | 0 hooks/{useIsMounted.tsx => useIsMounted.ts} | 0 hooks/useSubscription.ts | 101 +++++++++++++++++++ 6 files changed, 114 insertions(+), 95 deletions(-) create mode 100644 hooks/index.ts delete mode 100644 hooks/index.tsx rename hooks/{useAccount.tsx => useAccount.ts} (100%) rename hooks/{useIsMounted.tsx => useIsMounted.ts} (100%) create mode 100644 hooks/useSubscription.ts diff --git a/components/organisms/pledge/index.tsx b/components/organisms/pledge/index.tsx index 33817e34..d67a3742 100644 --- a/components/organisms/pledge/index.tsx +++ b/components/organisms/pledge/index.tsx @@ -1,10 +1,11 @@ -import React, { FunctionComponent, useState, useRef } from 'react' +import React, { FunctionComponent, useState } from 'react' import { Card, ConnectButton, Loading, ProgressBar } from '../../atoms' import styles from './style.module.css' import { Spacer } from '../../atoms/spacer' import { Utils } from '../../../shared/utils' import { - useAccount + useAccount, + useSubscription, } from '../../../hooks' import * as crowdfundContract from 'crowdfund-contract' import * as abundanceContract from 'abundance-token' @@ -14,13 +15,6 @@ import { Deposits, FormPledge } from '../../molecules' import * as convert from '../../../convert' let xdr = SorobanClient.xdr -const pollInterval = 5000 - -// TODO: update js-soroban-client to include latestLedger -interface GetEventsWithLatestLedger extends SorobanClient.SorobanRpc.GetEventsResponse { - latestLedger?: string; -} - const Pledge: FunctionComponent = () => { const [loadedAt, setLoadedAt] = React.useState(Date.now()) const account = useAccount() @@ -63,91 +57,14 @@ const Pledge: FunctionComponent = () => { const [targetReached, setTargetReached] = useState(false) - const subscriptions: { - contractId: string - topics: string[] - cb: (event: { value: { xdr: string } }) => void - lastLedgerStart?: number - pagingToken?: string - }[] = React.useMemo(() => [ - { - contractId: crowdfundContract.CONTRACT_ID_HEX, - topics: ['pledged_amount_changed'], - cb: (event) => { - let eventTokenBalance = xdr.ScVal.fromXDR(event.value.xdr, 'base64') - setAbundance({ ...abundance!, balance: convert.scvalToBigInt(eventTokenBalance) }) - }, - }, - { - contractId: crowdfundContract.CONTRACT_ID_HEX, - topics: ['target_reached'], - cb: () => { setTargetReached(true) }, - }, - ], [abundance, setTargetReached]) - - React.useEffect(() => { - let timeoutId: NodeJS.Timer | null = null - let stop = false - - async function pollEvents(): Promise { - try { - for (const subscription of subscriptions) { - if (!subscription.lastLedgerStart) { - let latestLedgerState = await crowdfundContract.Server.getLatestLedger(); - subscription.lastLedgerStart = latestLedgerState.sequence - } - - const subscriptionTopicXdrs: Array = [] - subscription.topics && subscription.topics.forEach( topic => { - subscriptionTopicXdrs.push( xdr.ScVal.scvSymbol(topic).toXDR("base64")); - }) - - // TODO: use rpc batch for single round trip, each subscription can be one - // getEvents request in the batch, is that possible now? - let response = await crowdfundContract.Server.getEvents({ - startLedger: !subscription.pagingToken ? subscription.lastLedgerStart : undefined, - cursor: subscription.pagingToken, - filters: [ - { - contractIds: [subscription.contractId], - topics: [subscriptionTopicXdrs], - type: "contract" - } - ], - limit: 10 - }) as GetEventsWithLatestLedger; - - delete subscription.pagingToken; - if (response.latestLedger) { - subscription.lastLedgerStart = parseInt(response.latestLedger); - } - response.events && response.events.forEach(event => { - try { - subscription.cb(event) - } catch (error) { - console.error("Poll Events: subscription callback had error: ", error); - } finally { - subscription.pagingToken = event.pagingToken - } - }) - } - } catch (error) { - console.error("Poll Events: error: ", error); - } finally { - if (!stop) { - timeoutId = setTimeout(pollEvents, pollInterval); - } - } - } - - pollEvents(); - - return () => { - if (timeoutId != null) clearTimeout(timeoutId) - stop = true - } - }, [subscriptions]); + useSubscription(crowdfundContract, 'pledged_amount_changed', React.useMemo(() => event => { + let eventTokenBalance = xdr.ScVal.fromXDR(event.value.xdr, 'base64') + setAbundance({ ...abundance!, balance: convert.scvalToBigInt(eventTokenBalance) }) + }, [abundance])) + useSubscription(crowdfundContract, 'target_reached', React.useMemo(() => () => { + setTargetReached(true) + }, [])) return ( diff --git a/hooks/index.ts b/hooks/index.ts new file mode 100644 index 00000000..5b3f1443 --- /dev/null +++ b/hooks/index.ts @@ -0,0 +1,3 @@ +export * from "./useAccount"; +export * from "./useIsMounted"; +export * from './useSubscription'; diff --git a/hooks/index.tsx b/hooks/index.tsx deleted file mode 100644 index 5fef8181..00000000 --- a/hooks/index.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./useAccount"; -export * from "./useIsMounted"; \ No newline at end of file diff --git a/hooks/useAccount.tsx b/hooks/useAccount.ts similarity index 100% rename from hooks/useAccount.tsx rename to hooks/useAccount.ts diff --git a/hooks/useIsMounted.tsx b/hooks/useIsMounted.ts similarity index 100% rename from hooks/useIsMounted.tsx rename to hooks/useIsMounted.ts diff --git a/hooks/useSubscription.ts b/hooks/useSubscription.ts new file mode 100644 index 00000000..457515bd --- /dev/null +++ b/hooks/useSubscription.ts @@ -0,0 +1,101 @@ +import * as React from 'react' +import * as SorobanClient from 'soroban-client' +let xdr = SorobanClient.xdr + +interface GeneratedLibrary { + Server: SorobanClient.Server + CONTRACT_ID_HEX: string +} + +// TODO: update js-soroban-client to include latestLedger +interface GetEventsWithLatestLedger extends SorobanClient.SorobanRpc.GetEventsResponse { + latestLedger?: string; +} + +/** + * Concatenated `${CONTRACT_ID_HEX}:${topic}` + */ +type PagingKey = string + +/** + * Paging tokens for each contract/topic pair. These can be mutated directly, + * rather than being stored as state within the React hook. + */ +const paging: Record = {} + +/** + * Subscribe to events for a given topic from a given contract, using a library + * generated with `soroban contract bindings typescript`. + * + * Someday such generated libraries will include functions for subscribing to + * the events the contract emits, but for now you can copy this hook into your + * React project if you need to subscribe to events, or adapt this logic for + * non-React use. + */ +export function useSubscription( + library: GeneratedLibrary, + topic: string, + onEvent: (event: SorobanClient.SorobanRpc.EventResponse) => void, + pollInterval = 5000 +) { + const id = `${library.CONTRACT_ID_HEX}:${topic}` + paging[id] = paging[id] || {} + + React.useEffect(() => { + let timeoutId: NodeJS.Timer | null = null + let stop = false + + async function pollEvents(): Promise { + try { + if (!paging[id].lastLedgerStart) { + let latestLedgerState = await library.Server.getLatestLedger(); + paging[id].lastLedgerStart = latestLedgerState.sequence + } + + let response = await library.Server.getEvents({ + startLedger: !paging[id].pagingToken + ? paging[id].lastLedgerStart + : undefined, + cursor: paging[id].pagingToken, + filters: [ + { + contractIds: [library.CONTRACT_ID_HEX], + topics: [[ + xdr.ScVal.scvSymbol(topic).toXDR("base64") + ]], + type: "contract" + } + ], + limit: 10 + }) as GetEventsWithLatestLedger; + + paging[id].pagingToken = undefined; + if (response.latestLedger) { + paging[id].lastLedgerStart = parseInt(response.latestLedger); + } + response.events && response.events.forEach(event => { + try { + onEvent(event) + } catch (error) { + console.error("Poll Events: subscription callback had error: ", error); + } finally { + paging[id].pagingToken = event.pagingToken + } + }) + } catch (error) { + console.error("Poll Events: error: ", error); + } finally { + if (!stop) { + timeoutId = setTimeout(pollEvents, pollInterval); + } + } + } + + pollEvents(); + + return () => { + if (timeoutId != null) clearTimeout(timeoutId) + stop = true + } + }, [library, topic, onEvent, id, pollInterval]) +} From fa09e6260a508527ecd93a2b437d8e48ac9cf2de Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:05:01 -0400 Subject: [PATCH 30/42] fix: update all relevant UI after pledging --- components/molecules/form-pledge/index.tsx | 6 +++--- components/organisms/pledge/index.tsx | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/components/molecules/form-pledge/index.tsx b/components/molecules/form-pledge/index.tsx index 056a81df..22addf5b 100644 --- a/components/molecules/form-pledge/index.tsx +++ b/components/molecules/form-pledge/index.tsx @@ -12,6 +12,7 @@ export interface IFormPledgeProps { decimals: number symbol?: string onPledge: () => void + updatedAt: number } export interface IResultSubmit { @@ -46,7 +47,6 @@ function MintButton({ account, symbol, onComplete, decimals }: { decimals: numbe } const FormPledge: FunctionComponent = props => { - const [loadedAt, setLoadedAt] = React.useState(Date.now()) const [balance, setBalance] = React.useState(BigInt(0)) const [decimals, setDecimals] = React.useState(0) const [symbol, setSymbol] = React.useState() @@ -66,7 +66,7 @@ const FormPledge: FunctionComponent = props => { setDecimals(fetched[1]) setSymbol(fetched[2].toString()) }) - }, [props.account, loadedAt]) + }, [props.account, props.updatedAt]) const clearInput = (): void => { setInput('') @@ -162,7 +162,7 @@ const FormPledge: FunctionComponent = props => { account={props.account} symbol={props.symbol} decimals={decimals} - onComplete={() => setLoadedAt(Date.now())} + onComplete={() => props.onPledge()} />
diff --git a/components/organisms/pledge/index.tsx b/components/organisms/pledge/index.tsx index d67a3742..9a0a7b04 100644 --- a/components/organisms/pledge/index.tsx +++ b/components/organisms/pledge/index.tsx @@ -16,7 +16,7 @@ import * as convert from '../../../convert' let xdr = SorobanClient.xdr const Pledge: FunctionComponent = () => { - const [loadedAt, setLoadedAt] = React.useState(Date.now()) + const [updatedAt, setUpdatedAt] = React.useState(Date.now()) const account = useAccount() const [abundance, setAbundance] = React.useState<{ @@ -53,7 +53,7 @@ const Pledge: FunctionComponent = () => { target: fetched[5], }) }) - }, [loadedAt]) + }, [updatedAt]) const [targetReached, setTargetReached] = useState(false) @@ -105,7 +105,8 @@ const Pledge: FunctionComponent = () => { decimals={abundance.decimals || 7} account={account.address} symbol={abundance.symbol} - onPledge={() => setLoadedAt(Date.now())} + updatedAt={updatedAt} + onPledge={() => setUpdatedAt(Date.now())} /> ) : ( From b74d052ec71f1d3ba32d9b76ad10d7b06c6d8287 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:09:51 -0400 Subject: [PATCH 31/42] fix: avoid Freighter error if not yet connected --- hooks/useAccount.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hooks/useAccount.ts b/hooks/useAccount.ts index 859e3f9d..22d59cc0 100644 --- a/hooks/useAccount.ts +++ b/hooks/useAccount.ts @@ -1,9 +1,11 @@ import { useEffect, useState } from "react"; -import { getUserInfo } from "@stellar/freighter-api"; +import { isConnected, getUserInfo } from "@stellar/freighter-api"; let address: string; -let addressLookup = getUserInfo() +let addressLookup = (async () => { + if (isConnected()) return getUserInfo() +})(); // returning the same object identity every time avoids unnecessary re-renders const addressObject = { From a9e40b3742f39730f1b7d424ad69a526cbe314d7 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:40:30 -0400 Subject: [PATCH 32/42] fix: can't default build to wasm because tests --- .cargo/config.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index d48ab4c5..d35e4376 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -2,6 +2,7 @@ [alias] # command aliases install_soroban = "install --git https://github.com/ahalabs/soroban-tools --rev aea9f9450b8d0e8344bb1c6a2639c2805956aa90 --root ./target soroban-cli --debug" +b = "build --target wasm32-unknown-unknown --release" # c = "check" # t = "test" # r = "run" @@ -15,7 +16,7 @@ install_soroban = "install --git https://github.com/ahalabs/soroban-tools --rev # rustc-wrapper = "…" # run this wrapper instead of `rustc` # rustc-workspace-wrapper = "…" # run this wrapper instead of `rustc` for workspace members # rustdoc = "rustdoc" # the doc generator tool -target = "wasm32-unknown-unknown" # build for the target triple (ignored by `cargo install`) +# target = "wasm32-unknown-unknown" # build for the target triple (ignored by `cargo install`) # target-dir = "target" # path of where to place all generated artifacts rustflags = [ # set these to match .github/workflows/rust.yml "-Wclippy::all", # warn for all clippy lints From 842aea391082f77a542cd29e082a256904f4a930 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Fri, 16 Jun 2023 16:30:08 -0400 Subject: [PATCH 33/42] build: use latest soroban-cli Uses the version with updated freighter-api https://github.com/stellar/soroban-tools/pull/708 --- .cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index d35e4376..4b284749 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,7 +1,7 @@ # paths = ["/path/to/override"] # path dependency overrides [alias] # command aliases -install_soroban = "install --git https://github.com/ahalabs/soroban-tools --rev aea9f9450b8d0e8344bb1c6a2639c2805956aa90 --root ./target soroban-cli --debug" +install_soroban = "install --git https://github.com/ahalabs/soroban-tools --rev 9fbf7550db18b363bacce0544b645b757499ad5b --root ./target soroban-cli --debug" b = "build --target wasm32-unknown-unknown --release" # c = "check" # t = "test" From 24ba3d77e360401798505593265d9d048431c2cb Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Mon, 19 Jun 2023 11:47:27 -0400 Subject: [PATCH 34/42] build: use latest cli/soroban-client; rm stellar-base pin --- .cargo/config.toml | 2 +- package-lock.json | 11 +++++------ package.json | 3 +-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 4b284749..4090bdfc 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,7 +1,7 @@ # paths = ["/path/to/override"] # path dependency overrides [alias] # command aliases -install_soroban = "install --git https://github.com/ahalabs/soroban-tools --rev 9fbf7550db18b363bacce0544b645b757499ad5b --root ./target soroban-cli --debug" +install_soroban = "install --git https://github.com/ahalabs/soroban-tools --rev e55af280bcd78f64ba7e9dd8d69137fad340b8a5 --root ./target soroban-cli --debug" b = "build --target wasm32-unknown-unknown --release" # c = "check" # t = "test" diff --git a/package-lock.json b/package-lock.json index 5fb2454c..5f3a2292 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,8 +18,7 @@ "next": "^13.4.4", "react": "^18.2.0", "react-dom": "^18.2.0", - "soroban-client": "0.8.0", - "stellar-base": "9.0.0-soroban.3" + "soroban-client": "0.8.1" }, "devDependencies": { "@types/humanize-duration": "^3.27.1", @@ -4323,9 +4322,9 @@ } }, "node_modules/soroban-client": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/soroban-client/-/soroban-client-0.8.0.tgz", - "integrity": "sha512-INc9W6uOZfHaa/n747jN+r6V2FvpmmFNoh5Ki1HbQbcKqiSo6yY/d1a4//AbMyzDs8WXeNTJOA2EYJnqcexdiw==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/soroban-client/-/soroban-client-0.8.1.tgz", + "integrity": "sha512-F+3K+hHlpXbSSdBMjvTlkim1tb2aMlg4OT+71r1ILk8T+bMFHXlZShettJg2VMQ402WGalBNN4Q9oSeoHsPVFQ==", "dependencies": { "axios": "^1.4.0", "bignumber.js": "^9.1.1", @@ -4335,7 +4334,7 @@ "eventsource": "^2.0.2", "lodash": "^4.17.21", "randombytes": "^2.1.0", - "stellar-base": "^9.0.0-soroban.3", + "stellar-base": "9.0.0-soroban.3", "toml": "^3.0.0", "urijs": "^1.19.1" } diff --git a/package.json b/package.json index 5864ab7a..76df9ec5 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,7 @@ "next": "^13.4.4", "react": "^18.2.0", "react-dom": "^18.2.0", - "soroban-client": "0.8.0", - "stellar-base": "9.0.0-soroban.3" + "soroban-client": "0.8.1" }, "devDependencies": { "@types/humanize-duration": "^3.27.1", From 4eab2800928da919e7bc0a00c09799986a9fd535 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Mon, 19 Jun 2023 14:55:24 -0400 Subject: [PATCH 35/42] build: use latest CLI rev from stellar repo --- .cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 4090bdfc..0158d530 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,7 +1,7 @@ # paths = ["/path/to/override"] # path dependency overrides [alias] # command aliases -install_soroban = "install --git https://github.com/ahalabs/soroban-tools --rev e55af280bcd78f64ba7e9dd8d69137fad340b8a5 --root ./target soroban-cli --debug" +install_soroban = "install --git https://github.com/stellar/soroban-tools --rev 9f045c09727ac4ca9f693c2e3851c4b5de1f46f5 --root ./target soroban-cli --debug" b = "build --target wasm32-unknown-unknown --release" # c = "check" # t = "test" From c8cda1a07738828e107165a64f774fdcab1c87bb Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Mon, 19 Jun 2023 15:43:18 -0400 Subject: [PATCH 36/42] fix: deal with undefined case --- hooks/useAccount.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hooks/useAccount.ts b/hooks/useAccount.ts index 22d59cc0..d09d6ace 100644 --- a/hooks/useAccount.ts +++ b/hooks/useAccount.ts @@ -39,8 +39,7 @@ export function useAccount(): typeof addressObject | null { if (address !== undefined) return; addressLookup - .then(({ publicKey }) => { address = publicKey }) - .catch(() => { address = '' }) + .then(user => { if (user) address = user.publicKey }) .finally(() => { setLoading(false) }); }, []); From 7db004ecbf24ee68ce5f87d9d285220f4818acfa Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Tue, 20 Jun 2023 09:48:22 -0400 Subject: [PATCH 37/42] build: rm RUSTFLAGS from Makefile Since d771b3f28599664d3e96c313397bb6aad3b71d38, the default settings are now set in `.cargo/config.toml` --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 96497c09..3919581a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ all: check build test -export RUSTFLAGS=-Dwarnings -Dclippy::all -Dclippy::pedantic CARGO_BUILD_TARGET?=wasm32-unknown-unknown test: fmt From 8b65e626f23a3b0b752719aee61f0798d6ec84e1 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Tue, 20 Jun 2023 12:34:56 -0400 Subject: [PATCH 38/42] fix: allow using standalone Everything looks correct, but when running the app it fails with: Error: Cannot connect to insecure soroban-rpc server --- Dockerfile | 1 - README.md | 8 ++++---- initialize.sh | 9 ++++++--- package.json | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 46a0d6be..cadb8e4d 100755 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,6 @@ ENV PATH="$PATH:/root/.cargo/bin" RUN rustup target add wasm32-unknown-unknown RUN apt install -y build-essential -RUN cargo install --locked --version 0.8.0 soroban-cli # WORKDIR / RUN mkdir /workspace WORKDIR /workspace diff --git a/README.md b/README.md index 5ad2d1dd..41fd693c 100755 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Getting Started Install Dependencies -------------------- -1. `soroban-cli v0.8.0`. See https://soroban.stellar.org/docs/getting-started/setup#install-the-soroban-cli +1. `soroban-cli`. See https://soroban.stellar.org/docs/getting-started/setup#install-the-soroban-cli, but instead of `cargo install soroban-cli`, run `cargo install_soroban`. This is an alias set up in [.cargo/config.toml](./.cargo/config.toml), which pins the local soroban-cli to a specific version. If you add `./target/bin/` [to your PATH](https://linuxize.com/post/how-to-add-directory-to-path-in-linux/), then you'll automatically use this version of `soroban-cli` when you're in this directory. 2. If you want to run everything locally: `docker` (you can run both Standalone and Futurenet backends with it) 3. Node.js v18 4. [Freighter Wallet](https://www.freighter.app/) ≥[v5.0.2](https://github.com/stellar/freighter/releases/tag/2.9.1). Or from the Firefox / Chrome extension store. Once installed, enable "Experimental Mode" in the settings (gear icon). @@ -33,9 +33,9 @@ You have three options: 1. Deploy on [Futurenet](https://soroban.stellar.org/doc 1. Deploy the contracts and initialize them - ./initialize.sh futurenet + npm run setup - This will create a `token-admin` identity for you (`soroban config identity create token-admin`) and deploy a Fungible Token contract as well as the [crowdfund contract](./contracts/crowdfund), with this account as admin. + This runs `./initialize.sh futurenet` behind the scenes, which will create a `token-admin` identity for you (`soroban config identity create token-admin`) and deploy a Fungible Token contract as well as the [crowdfund contract](./contracts/crowdfund), with this account as admin. 2. Select the Futurenet network in your Freighter browser extension @@ -91,7 +91,7 @@ You have three options: 1. Deploy on [Futurenet](https://soroban.stellar.org/doc You can use your own local soroban-cli: - ./initialize.sh standalone + NETWORK=standalone npm run setup Or run it inside the soroban-preview docker container: diff --git a/initialize.sh b/initialize.sh index 216cdab2..4ebfc025 100755 --- a/initialize.sh +++ b/initialize.sh @@ -36,12 +36,10 @@ SOROBAN_RPC_URL="$SOROBAN_RPC_HOST/soroban/rpc" case "$1" in standalone) - echo "Using standalone network with RPC URL: $SOROBAN_RPC_URL" SOROBAN_NETWORK_PASSPHRASE="Standalone Network ; February 2017" FRIENDBOT_URL="$SOROBAN_RPC_HOST/friendbot" ;; futurenet) - echo "Using Futurenet network with RPC URL: $SOROBAN_RPC_URL" SOROBAN_NETWORK_PASSPHRASE="Test SDF Future Network ; October 2022" FRIENDBOT_URL="https://friendbot-futurenet.stellar.org/" ;; @@ -51,12 +49,18 @@ futurenet) ;; esac +echo "Using $NETWORK network" +echo " RPC URL: $SOROBAN_RPC_URL" +echo " Friendbot URL: $FRIENDBOT_URL" echo Add the $NETWORK network to cli client soroban config network add \ --rpc-url "$SOROBAN_RPC_URL" \ --network-passphrase "$SOROBAN_NETWORK_PASSPHRASE" "$NETWORK" +echo Add $NETWORK to .soroban-example-dapp for use with npm scripts +mkdir -p .soroban-example-dapp +echo $NETWORK > ./.soroban-example-dapp/network if !(soroban config identity ls | grep token-admin 2>&1 >/dev/null); then echo Create the token-admin identity @@ -79,7 +83,6 @@ ABUNDANCE_ID="$( --wasm target/wasm32-unknown-unknown/release/abundance_token.wasm )" echo "Contract deployed succesfully with ID: $ABUNDANCE_ID" -mkdir -p .soroban-example-dapp echo -n "$ABUNDANCE_ID" > .soroban-example-dapp/abundance_token_id echo Deploy the crowdfund contract diff --git a/package.json b/package.json index 76df9ec5..d3d7302b 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,13 @@ "version": "0.1.0", "private": true, "scripts": { - "setup": "./initialize.sh futurenet && npm install", + "setup": "./initialize.sh ${NETWORK:-futurenet} && npm install", "reset": "rm -rf .soroban-example-dapp && rm -rf .next && rm -rf node_modules/crowdfund-contract && rm -rf node_modules/abundance-token && npm run setup", "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", - "postinstall": "./target/bin/soroban contract bindings typescript --wasm ./target/wasm32-unknown-unknown/release/soroban_crowdfund_contract.wasm --id $(cat ./.soroban-example-dapp/crowdfund_id) --output-dir ./node_modules/crowdfund-contract --network futurenet --contract-name crowdfund-contract && ./target/bin/soroban contract bindings typescript --wasm ./target/wasm32-unknown-unknown/release/abundance_token.wasm --id $(cat ./.soroban-example-dapp/abundance_token_id) --output-dir ./node_modules/abundance-token --network futurenet --contract-name abundance-token" + "postinstall": "./target/bin/soroban contract bindings typescript --wasm ./target/wasm32-unknown-unknown/release/soroban_crowdfund_contract.wasm --id $(cat ./.soroban-example-dapp/crowdfund_id) --output-dir ./node_modules/crowdfund-contract --network $(cat ./.soroban-example-dapp/network) --contract-name crowdfund-contract && ./target/bin/soroban contract bindings typescript --wasm ./target/wasm32-unknown-unknown/release/abundance_token.wasm --id $(cat ./.soroban-example-dapp/abundance_token_id) --output-dir ./node_modules/abundance-token --network $(cat ./.soroban-example-dapp/network) --contract-name abundance-token" }, "dependencies": { "@radix-ui/react-dialog": "1.0.2", From 0a214faf9df9d91335d43d5ee44f4ee27dd50670 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Tue, 20 Jun 2023 13:46:01 -0400 Subject: [PATCH 39/42] build: update freighter-api --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5f3a2292..b953721c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "dependencies": { "@radix-ui/react-dialog": "1.0.2", - "@stellar/freighter-api": "^1.5.0", + "@stellar/freighter-api": "^1.5.1", "axios": "^0.27.2", "bigint-conversion": "^2.4.1", "humanize-duration": "^3.27.3", @@ -559,9 +559,9 @@ "dev": true }, "node_modules/@stellar/freighter-api": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-1.5.0.tgz", - "integrity": "sha512-j9bAo3U7UJ0jaEGhKkCcmAiRJ67xUG1Ty3N8dVb65WVkEdXtxEfFtPuRcsr9brX9sHeN+s2caS6KQL8FYZqixg==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-1.5.1.tgz", + "integrity": "sha512-WEnKEqd+xVLnOq6bJv+fLXod8JQyPjzpOKTpH4g7tG9MM1fmXzD3y2SXJlpCIw8kVqtiC4ynWOlSWX+TKO7KiQ==" }, "node_modules/@swc/helpers": { "version": "0.5.1", diff --git a/package.json b/package.json index d3d7302b..459bab95 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@radix-ui/react-dialog": "1.0.2", - "@stellar/freighter-api": "^1.5.0", + "@stellar/freighter-api": "^1.5.1", "axios": "^0.27.2", "bigint-conversion": "^2.4.1", "humanize-duration": "^3.27.3", From 77cc1e3af6873700f6ba24e3a10d0b73088f2d71 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:14:13 -0400 Subject: [PATCH 40/42] build: update pinned soroban-cli version --- .cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 0158d530..81cb1efd 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,7 +1,7 @@ # paths = ["/path/to/override"] # path dependency overrides [alias] # command aliases -install_soroban = "install --git https://github.com/stellar/soroban-tools --rev 9f045c09727ac4ca9f693c2e3851c4b5de1f46f5 --root ./target soroban-cli --debug" +install_soroban = "install --git https://github.com/stellar/soroban-tools --rev 2b343d3e6afdb5eff54fb03622627cd55e785358 --root ./target soroban-cli --debug" b = "build --target wasm32-unknown-unknown --release" # c = "check" # t = "test" From be72e6e27519c54b872bdaefe54763a544ad7053 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:29:09 -0400 Subject: [PATCH 41/42] build(ci): stub .soroban-example-dapp/network --- .github/workflows/nodejs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 902704f6..7a506119 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -30,6 +30,7 @@ jobs: cache: 'npm' - run: | mkdir -p .soroban-example-dapp + echo 'futurenet' > .soroban-example-dapp/network echo 'CC757WDV3G442WQCNPNOA2UEXOC7UJD5VP4BLLCRDW5LRM6UZZR6ISVU' > .soroban-example-dapp/abundance_token_id echo 'CCHCPXECLYGX4QU34ZZOHP6C6KVAPIDTUNPIUA6GF4SP6ECFF5BX57OG' > .soroban-example-dapp/crowdfund_id - run: npm ci From f7793e2e08c0ea5f7df52da255f4977cf1af6941 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:36:16 -0400 Subject: [PATCH 42/42] fix: add 'await' --- hooks/useAccount.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/useAccount.ts b/hooks/useAccount.ts index d09d6ace..0a52cad0 100644 --- a/hooks/useAccount.ts +++ b/hooks/useAccount.ts @@ -4,7 +4,7 @@ import { isConnected, getUserInfo } from "@stellar/freighter-api"; let address: string; let addressLookup = (async () => { - if (isConnected()) return getUserInfo() + if (await isConnected()) return getUserInfo() })(); // returning the same object identity every time avoids unnecessary re-renders