Skip to content

Commit

Permalink
Show user balance of EXT token and update the user balance after mint…
Browse files Browse the repository at this point in the history
… (#95)

* soroban-cli command is just 'soroban'

* Add npm install instructions

* not use optimizing builds

* use SorobanContext name following web3-react standard

* Revert "not use optimizing builds"

This reverts commit 840e69aa2d95b4381b9bade1e05b7ad02799b78d.

* fix: use SorobanContext

* use soroban-react folder

* change WalletProvider to SorobanReactProvider inside soroban-react folder

* use useSorobanReact() instead of React.useContext(SorobanContext)

* use ProviderExample in _app.tsx

* move Wallet.tsx to types

* use connector instead of wallet

* React.Node type for children

* delete components/WalletProvider.tsx as using soroban-react/SorobanReactProvider.tsx

* use getDefaultConnectors instead of getDefaultWallets

* realtime react for wallet address or network changes

* use @soroban-react library

* use @soroban-react/core v1.02

* use @soroban-react/core v1.0.2

* Delete yarn.lock

Trying to only have package-lock.json with npm for simplicity of the example repo.

* Update wallet/hooks/useNetwork.tsx

* handle error when wallets are not funded

* feat(user-balance): Add user's token balance section

* feat(user-balance): reconects, and hence upload balance after mint transactions

* Use early return when not having balance in wallet

* Fix an import

* Fixing a bunch of typos and compilation errors

---------

Co-authored-by: Paul Bellamy <[email protected]>
Co-authored-by: Paul Bellamy <[email protected]>
  • Loading branch information
3 people authored Apr 3, 2023
1 parent ff0e4d2 commit 87e2bbe
Show file tree
Hide file tree
Showing 10 changed files with 361 additions and 7 deletions.
65 changes: 58 additions & 7 deletions components/molecules/form-pledge/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { FunctionComponent, useState } from 'react'
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 } from '@soroban-react/contracts'
import { useSendTransaction, useContractValue } from '@soroban-react/contracts'
import { useSorobanReact } from '@soroban-react/core'
import {
useNetwork,
Expand All @@ -28,18 +29,51 @@ export interface IResultSubmit {
scVal?: SorobanClient.xdr.ScVal
error?: string
value?: number
symbol?: string
symbol?: string
}

const FormPledge: FunctionComponent<IFormPledgeProps> = props => {
const sorobanContext = useSorobanReact()


// 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
}),
}
}

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", "")




const [amount, setAmount] = useState<number>()
const [resultSubmit, setResultSubmit] = useState<IResultSubmit | undefined>()
const [input, setInput] = useState('')
const [isSubmitting, setSubmitting] = useState(false)
const { server } = useNetwork()

const sorobanContext = useSorobanReact()
const parsedAmount = BigNumber(amount || 0)

const { sendTransaction } = useSendTransaction()
Expand Down Expand Up @@ -174,6 +208,11 @@ const FormPledge: FunctionComponent<IFormPledgeProps> = props => {
decimals={props.decimals}
symbol={props.symbol}
/>
<div className={styles.wrapper}>
<div>
<h6>Your balance: {Utils.formatAmount(userBalance, tokenDecimals)} {tokenSymbol}</h6>
</div>
</div>
</div>
) : null}
{resultSubmit && (
Expand Down Expand Up @@ -204,12 +243,18 @@ const FormPledge: FunctionComponent<IFormPledgeProps> = props => {
title={`Mint ${amount.toString()} ${symbol}`}
onClick={async () => {
setSubmitting(true)

if (!server) throw new Error("Not connected to server")

const adminSource = await server.getAccount(Constants.TokenAdmin)

const walletSource = await server.getAccount(account)
let adminSource, walletSource
try{
adminSource = await server.getAccount(Constants.TokenAdmin)
walletSource = await server.getAccount(account)
}
catch(error){
alert("Your wallet or the token admin wallet might not be funded")
setSubmitting(false)
return
}

//
// 1. Establish a trustline to the admin (if necessary)
Expand All @@ -225,6 +270,7 @@ const FormPledge: FunctionComponent<IFormPledgeProps> = props => {
//
// Today, we establish the trustline unconditionally.
try {
console.log("Establishing the trustline...")
console.log("sorobanContext: ", sorobanContext)
const trustlineResult = await sendTransaction(
new SorobanClient.TransactionBuilder(walletSource, {
Expand All @@ -247,10 +293,12 @@ const FormPledge: FunctionComponent<IFormPledgeProps> = props => {
)
console.debug(trustlineResult)
} catch (err) {
console.log("Error while establishing the trustline: ", err)
console.error(err)
}

try {
console.log("Minting the token...")
const paymentResult = await sendTransaction(
new SorobanClient.TransactionBuilder(adminSource, {
networkPassphrase,
Expand All @@ -272,14 +320,17 @@ const FormPledge: FunctionComponent<IFormPledgeProps> = props => {
}
)
console.debug(paymentResult)
sorobanContext.connect()
} catch (err) {
console.log("Error while minting the token: ", err)
console.error(err)
}
//
// TODO: Show some user feedback while we are awaiting, and then based
// on the result
//
setSubmitting(false)

}}
disabled={isSubmitting}
isLoading={isSubmitting}
Expand Down
29 changes: 29 additions & 0 deletions wallet/WalletChainContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';

export interface WalletChain {
id: string;
name?: string;
networkPassphrase: string;
iconBackground?: string;
iconUrl?: string | null;
// TODO: Use this to indicate which chains a dapp supports
unsupported?: boolean;
};

export const WalletChainContext = React.createContext<WalletChain[]>([]);

export const useWalletChains = () => React.useContext(WalletChainContext);

export const useWalletChainsById = () => {
const walletChains = useWalletChains();

return React.useMemo(() => {
const walletChainsById: Record<string, WalletChain> = {};

walletChains.forEach(rkChain => {
walletChainsById[rkChain.id] = rkChain;
});

return walletChainsById;
}, [walletChains]);
};
37 changes: 37 additions & 0 deletions wallet/connectors/freighter/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* eslint-disable sort-keys-fix/sort-keys-fix */
import freighterApi from "@stellar/freighter-api";
import { WalletChain } from '../../WalletChainContext';
import { NetworkDetails, Connector } from '../../types';

export interface FreighterOptions {
appName?: string;
chains: WalletChain[];
}

export function freighter(_: FreighterOptions): Connector {
return {
id: 'freighter',
name: 'Freighter',
iconUrl: async () => '',
// iconUrl: async () => (await import('./freighter.svg')).default,
iconBackground: '#fff',
// TODO: Check this
installed: true,
downloadUrls: {
browserExtension:
'https://chrome.google.com/webstore/detail/freighter/bcacfldlkkdogcmkkibnjlakofdplcbk?hl=en',
},
isConnected(): boolean {
return !!freighterApi?.isConnected()
},
getNetworkDetails(): Promise<NetworkDetails> {
return freighterApi.getNetworkDetails()
},
getPublicKey(): Promise<string> {
return freighterApi.getPublicKey()
},
signTransaction(xdr: string, opts?: { network?: string; networkPassphrase?: string; accountToSign?: string }): Promise<string> {
return freighterApi.signTransaction(xdr, opts)
},
}
};
1 change: 1 addition & 0 deletions wallet/connectors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./freighter";
22 changes: 22 additions & 0 deletions wallet/getDefaultConnectors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { WalletChain } from './WalletChainContext';
import { ConnectorList } from './types';
import { freighter } from './connectors';

export const getDefaultConnectors = (
{appName,chains,}: {appName: string; chains: WalletChain[];})
: {

connectors: ConnectorList;} => {
const connectors: ConnectorList = [
{
groupName: 'Popular',
connectors: [
freighter({ appName, chains }),
],
},
];

return {
connectors,
};
};
28 changes: 28 additions & 0 deletions wallet/soroban-react/SorobanContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React, {createContext} from "react";
import * as SorobanClient from "soroban-client";
import { ChainMetadata } from "@soroban-react/types";
import { Connector, ConnectorList } from "../types";

export const defaultSorobanContext: SorobanContextType = {
appName: undefined,
chains: [],
connectors: [],
server: new SorobanClient.Server("https://soroban-rpc.stellar.org"),
async connect() {},
async disconnect() {},
};

export interface SorobanContextType {
autoconnect?: boolean;
appName?: string;
chains: ChainMetadata[];
connectors: ConnectorList;
activeChain?: ChainMetadata;
address?: string;
activeWallet?: Connector;
server?: SorobanClient.Server;
connect: () => Promise<void>;
disconnect: () => Promise<void>;
}

export const SorobanContext = createContext<SorobanContextType | undefined>(undefined)
Loading

0 comments on commit 87e2bbe

Please sign in to comment.