Skip to content

Commit

Permalink
fix updateUtxosContract, change contracts state to add Utxos
Browse files Browse the repository at this point in the history
  • Loading branch information
mr-zwets authored and rkalis committed Jun 4, 2024
1 parent 0501e53 commit d87656f
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 157 deletions.
35 changes: 22 additions & 13 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Components
import React, { useState } from 'react';
import { Artifact, Network, Contract, Utxo } from 'cashscript';
import { Artifact, Network } from 'cashscript';
import Header from './Header'
import Main from './Main'
import Footer from './Footer';
import Tab from 'react-bootstrap/Tab';
import Tabs from 'react-bootstrap/Tabs';
import WalletInfo from './Wallets';
import { Wallet } from './shared';
import { Wallet, ContractInfo } from './shared';
import NewContract from './NewContract';
import Contracts from './Contracts';
import TransactionBuilder from './TransactionBuilder';
Expand All @@ -16,9 +16,7 @@ function App() {
const [network, setNetwork] = useState<Network>('chipnet')
const [wallets, setWallets] = useState<Wallet[]>([])
const [artifacts, setArtifacts] = useState<Artifact[] | undefined>(undefined);
const [contracts, setContracts] = useState<Contract[] | undefined>(undefined)
const [utxos, setUtxos] = useState<Utxo[] | undefined>(undefined)
const [balance, setBalance] = useState<bigint | undefined>(undefined)
const [contracts, setContracts] = useState<ContractInfo[] | undefined>(undefined)
const [code, setCode] = useState<string>(
`pragma cashscript >= 0.8.0;
Expand All @@ -35,11 +33,22 @@ contract TransferWithTimeout(pubkey sender, pubkey recipient, int timeout) {
}
}
`);
const contract = contracts?.[0] // TODO: delete this
async function updateUtxosContract () {
if (!contract) return
setBalance(await contract.getBalance())
setUtxos(await contract.getUtxos())

async function updateUtxosContract (nameContract: string) {
const contractIndex = contracts?.findIndex(contractInfo => contractInfo.contract.name == nameContract)
if (contractIndex == undefined) return
const currentContract = contracts?.[contractIndex].contract
if (!currentContract) return
// create two separate lists (deep copies) and mutate utxos
// map best way to deep clone
const utxosList = contracts.map(contract => contract.utxos ?? [])
const contractsList = contracts.map(contract => contract.contract)
const contractUtxos = await currentContract.getUtxos();
utxosList[contractIndex] = contractUtxos
const newContracts: ContractInfo[] = contractsList.map((contract,index) =>
({contract,utxos:utxosList[index]})
)
setContracts(newContracts)
}

return (
Expand All @@ -56,16 +65,16 @@ contract TransferWithTimeout(pubkey sender, pubkey recipient, int timeout) {
<Main code={code} setCode={setCode} artifacts={artifacts} setArtifacts={setArtifacts} />
</Tab>
<Tab eventKey="newcontract" title="New Contract">
<NewContract artifacts={artifacts} network={network} setNetwork={setNetwork} utxos={utxos} balance={balance} contracts={contracts} setContracts={setContracts} updateUtxosContract={updateUtxosContract} />
<NewContract artifacts={artifacts} network={network} setNetwork={setNetwork} contracts={contracts} setContracts={setContracts} updateUtxosContract={updateUtxosContract} />
</Tab>
<Tab eventKey="contracts" title="Contracts">
<Contracts contracts={contracts} setContracts={setContracts} utxos={utxos} balance={balance} updateUtxosContract={updateUtxosContract} />
<Contracts contracts={contracts} setContracts={setContracts} updateUtxosContract={updateUtxosContract} />
</Tab>
<Tab eventKey="wallets" title="Wallets">
<WalletInfo network={network} wallets={wallets} setWallets={setWallets}/>
</Tab>
<Tab eventKey="transactionBuilder" title="TransactionBuilder">
<TransactionBuilder network={network} wallets={wallets} utxos={utxos} contracts={contracts} updateUtxosContract={updateUtxosContract}/>
<TransactionBuilder network={network} wallets={wallets} contracts={contracts} updateUtxosContract={updateUtxosContract}/>
</Tab>
</Tabs>
</div>
Expand Down
33 changes: 17 additions & 16 deletions src/components/ContractCreation.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import React, { useState, useEffect } from 'react'
import { Artifact, Contract, Argument, Network, ElectrumNetworkProvider, Utxo } from 'cashscript'
import { Artifact, Contract, Argument, Network, ElectrumNetworkProvider } from 'cashscript'
import { InputGroup, Form, Button } from 'react-bootstrap'
import { readAsType } from './shared'
import { readAsType, ContractInfo } from './shared'

interface Props {
artifact?: Artifact
contracts?: Contract[]
setContracts: (contract?: Contract[]) => void
contracts?: ContractInfo[]
setContracts: (contracts?: ContractInfo[]) => void
network: Network
utxos: Utxo[] | undefined
balance: bigint | undefined
updateUtxosContract: () => void
updateUtxosContract: (contractName: string) => void
}

const ContractCreation: React.FC<Props> = ({ artifact, contracts, setContracts, network, updateUtxosContract}) => {
const [args, setArgs] = useState<Argument[]>([])
const [nameContract, setNameContract] = useState<string>("");
const [createdContract, setCreatedContract] = useState(false);

const resetInputFields = () => {
// This code is suuper ugly but I haven't found any other way to clear the value
Expand All @@ -24,18 +23,12 @@ const ContractCreation: React.FC<Props> = ({ artifact, contracts, setContracts,
const el = document.getElementById(`constructor-arg-${i}`)
if (el) (el as any).value = ''
})

// Set empty strings as default values
const newArgs = artifact?.constructorInputs.map(() => '') || []

setArgs(newArgs)
setNameContract("")
}

useEffect(() => {
//updateUtxosContract()
setArgs([])
}, [artifact])

const inputFields = artifact?.constructorInputs.map((input, i) => (
<Form.Control key={`constructor-arg-${i}`} size="sm" id={`constructor-arg-${i}`}
placeholder={`${input.type} ${input.name}`}
Expand All @@ -62,15 +55,23 @@ const ContractCreation: React.FC<Props> = ({ artifact, contracts, setContracts,
const provider = new ElectrumNetworkProvider(network)
const newContract = new Contract(artifact, args, { provider })
newContract.name = nameContract
setContracts([newContract, ...contracts ?? []])
const contractInfo = {contract: newContract, utxos: undefined}
setContracts([contractInfo, ...contracts ?? []])
alert("created contract!")
resetInputFields()
setCreatedContract(true)
} catch (e: any) {
alert(e.message)
console.error(e.message)
}
}

useEffect(() => {
if(!createdContract) return
updateUtxosContract(nameContract)
resetInputFields()
setCreatedContract(false)
}, [createdContract]);

return (
<div style={{
marginTop: "15px"
Expand Down
20 changes: 11 additions & 9 deletions src/components/ContractFunction.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import React, { useState, useEffect } from 'react'
import { Contract, AbiFunction, Argument, Network, Recipient, SignatureTemplate, Utxo } from 'cashscript'
import { AbiFunction, Argument, Network, Recipient, SignatureTemplate, Utxo } from 'cashscript'
import { Form, InputGroup, Button, Card } from 'react-bootstrap'
import { readAsType, ExplorerString, Wallet, NamedUtxo } from './shared'
import { readAsType, ExplorerString, Wallet, NamedUtxo, ContractInfo } from './shared'

interface Props {
contract?: Contract
contractInfo: ContractInfo
abi?: AbiFunction
network: Network
wallets: Wallet[]
contractUtxos: Utxo[] | undefined
updateUtxosContract: () => void
updateUtxosContract: (contractName: string) => void
}

const ContractFunction: React.FC<Props> = ({ contract, abi, network, wallets, contractUtxos, updateUtxosContract }) => {
const ContractFunction: React.FC<Props> = ({ contractInfo, abi, network, wallets, updateUtxosContract }) => {
const [args, setArgs] = useState<Argument[]>([])
const [outputs, setOutputs] = useState<Recipient[]>([{ to: '', amount: 0n }])
// transaction inputs, not the same as abi.inputs
Expand All @@ -23,6 +22,9 @@ const ContractFunction: React.FC<Props> = ({ contract, abi, network, wallets, co
const [noAutomaticChange, setNoAutomaticChange] = useState<boolean>(false)
const [namedUtxoList, setNamedUtxoList] = useState<NamedUtxo[]>([])

const contract = contractInfo.contract
const contractUtxos = contractInfo.utxos

useEffect(() => {
// Set empty strings as default values
const newArgs = abi?.inputs.map(() => '') || [];
Expand All @@ -32,7 +34,7 @@ const ContractFunction: React.FC<Props> = ({ contract, abi, network, wallets, co
useEffect(() => {
if (!manualSelection) return;
async function updateUtxos() {
if (contract === undefined || contractUtxos === undefined) return
if (contractInfo.contract === undefined || contractUtxos === undefined) return
const namedUtxosContract: NamedUtxo[] = contractUtxos.map((utxo, index) => ({ ...utxo, name: `Contract UTXO ${index}`, isP2pkh: false }))
let newNamedUtxoList = namedUtxosContract
const walletUtxos = wallets.map(wallet => wallet?.utxos ?? [])
Expand All @@ -47,7 +49,7 @@ const ContractFunction: React.FC<Props> = ({ contract, abi, network, wallets, co
setNamedUtxoList(newNamedUtxoList);
}
updateUtxos()
}, [manualSelection, contractUtxos])
}, [manualSelection, contractInfo])

function fillPrivKey(i: number, walletIndex: string) {
const argsCopy = [...args];
Expand Down Expand Up @@ -291,7 +293,7 @@ const ContractFunction: React.FC<Props> = ({ contract, abi, network, wallets, co

alert(`Transaction successfully sent: ${ExplorerString[network]}/tx/${txid}`)
console.log(`Transaction successfully sent: ${ExplorerString[network]}/tx/${txid}`)
updateUtxosContract()
updateUtxosContract(contract.name)
} catch (e: any) {
alert(e.message)
console.error(e.message)
Expand Down
15 changes: 7 additions & 8 deletions src/components/ContractFunctions.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import React from 'react'
import { Contract, Network, Utxo } from 'cashscript'
import { Network } from 'cashscript'
import ContractFunction from './ContractFunction'
import { Wallet } from './shared'
import { Wallet, ContractInfo } from './shared'

interface Props {
contract: Contract
contractInfo: ContractInfo
network: Network
wallets: Wallet[]
contractUtxos: Utxo[] | undefined
updateUtxosContract: () => void
updateUtxosContract: (contractName: string) => void
}

const ContractFunctions: React.FC<Props> = ({ contract, network, wallets, contractUtxos, updateUtxosContract }) => {
const functions = contract.artifact?.abi.map(func => (
<ContractFunction contract={contract} key={func.name} abi={func} network={network} wallets={wallets} contractUtxos={contractUtxos} updateUtxosContract={updateUtxosContract}/>
const ContractFunctions: React.FC<Props> = ({ contractInfo, network, wallets, updateUtxosContract }) => {
const functions = contractInfo.contract.artifact?.abi.map(func => (
<ContractFunction contractInfo={contractInfo} key={func.name} abi={func} network={network} wallets={wallets} updateUtxosContract={updateUtxosContract}/>
))

return (
Expand Down
56 changes: 0 additions & 56 deletions src/components/ContractInfo.tsx

This file was deleted.

65 changes: 35 additions & 30 deletions src/components/Contracts.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import React from 'react'
import { Contract, Utxo } from 'cashscript'
import CopyText from './shared/CopyText'
import { Card } from 'react-bootstrap'
import { Card, Button } from 'react-bootstrap'
import { ContractInfo } from './shared'
import InfoUtxos from './InfoUtxos'

interface Props {
contracts: Contract[] | undefined
setContracts: (contract: Contract[] | undefined) => void
balance: bigint | undefined
utxos: Utxo[] | undefined
updateUtxosContract: () => void
contracts: ContractInfo[] | undefined
setContracts: (contract: ContractInfo[] | undefined) => void
updateUtxosContract: (contractName: string) => void
}

const Contracts: React.FC<Props> = ({ contracts, setContracts, utxos, balance, updateUtxosContract }) => {
const Contracts: React.FC<Props> = ({ contracts, setContracts, updateUtxosContract }) => {

const removeContract = (contractToRemove: Contract) => {
const removeContract = (contractInfo: ContractInfo) => {
const contractToRemove = contractInfo.contract
const contractToRemoveAddress = contractToRemove.address;
const newContracts = contracts?.filter(contract => contract.address !== contractToRemoveAddress)
const newContracts = contracts?.filter(contractInfo => contractInfo.contract.address !== contractToRemoveAddress)
setContracts(newContracts)
}

Expand All @@ -36,40 +36,45 @@ const Contracts: React.FC<Props> = ({ contracts, setContracts, utxos, balance, u
{contracts == undefined ? <p>
No Contracts created yet...
</p>:null}
{contracts?.map(contract => (
<Card style={{ marginBottom: '10px' }} key={contract.address}>
{contracts?.map((contractInfo) => (
<Card style={{ marginBottom: '10px' }} key={contractInfo.contract.address}>
<Card.Header style={{ display:"flex", justifyContent:"space-between"}}>
<div>{contract.name}</div>
<img src='./trash.svg' onClick={() => removeContract(contract)} style={{padding: "0px 6px", width: "fit-content", cursor:"pointer"}}/>
<div>{contractInfo.contract.name}</div>
<img src='./trash.svg' onClick={() => removeContract(contractInfo)} style={{padding: "0px 6px", width: "fit-content", cursor:"pointer"}}/>
</Card.Header>
<Card.Body>
<div style={{ margin: '5px', width: '100%' }}>
<strong>Contract address (p2sh32)</strong>
<CopyText>{contract.address}</CopyText>
<CopyText>{contractInfo.contract.address}</CopyText>
<strong>Contract token address (p2sh32)</strong>
<CopyText>{contract.tokenAddress}</CopyText>
<CopyText>{contractInfo.contract.tokenAddress}</CopyText>
<strong>Contract artifact</strong>
<p>{contract.artifact.contractName}</p>
<p>{contractInfo.contract.artifact.contractName}</p>
<strong>Contract utxos</strong>
{utxos == undefined?
{contractInfo?.utxos == undefined?
<p>loading ...</p>:
(<>
<p>{utxos.length} {utxos.length == 1 ? "utxo" : "utxos"}</p>
{utxos.length ?
<details>
<summary>Show utxos</summary>
<div>
</div>
</details> : null}
</>)
(<div>
{contractInfo?.utxos.length} {contractInfo?.utxos.length == 1 ? "utxo" : "utxos"}
<span onClick={() => {}} style={{cursor:"pointer", marginLeft:"10px"}}>
<Button size='sm' onClick={() => updateUtxosContract(contractInfo.contract.name)} variant='secondary' style={{padding:" 0px 2px"}}>refresh ⭯</Button>
</span>
{contractInfo.utxos.length ?
<details>
<summary>Show utxos</summary>
<div>
<InfoUtxos utxos={contractInfo?.utxos}/>
</div>
</details> : null}
</div>)
}
<strong>Total contract balance</strong>
{balance == undefined?
{contractInfo.utxos == undefined?
<p>loading ...</p>:
<p>{balance.toString()} satoshis</p>
<p>{contractInfo.utxos?.reduce((acc, utxo) => acc + utxo.satoshis, 0n).toString()} satoshis</p>

}
<strong>Contract size</strong>
<p>{contract.bytesize} bytes (max 520), {contract.opcount} opcodes (max 201)</p>
<p>{contractInfo.contract.bytesize} bytes (max 520), {contractInfo.contract.opcount} opcodes (max 201)</p>
</div>
</Card.Body>
</Card>
Expand Down
Loading

0 comments on commit d87656f

Please sign in to comment.