Skip to content

Commit

Permalink
utxo selection overhaul
Browse files Browse the repository at this point in the history
  • Loading branch information
Piefayth committed Apr 5, 2024
1 parent 3b86869 commit 2e38002
Show file tree
Hide file tree
Showing 14 changed files with 797 additions and 552 deletions.
8 changes: 8 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ body {
user-select: none;
}

.underline {
text-decoration: underline;
}

.disabled {
opacity: 0.2;
cursor: not-allowed !important;
Expand Down Expand Up @@ -208,6 +212,10 @@ button.disabled:hover {

.button {
font-size: 16px;
height: 25px;
display: flex;
justify-content: center;
align-items: center;
outline: none;
border: solid 1px black;
padding: 5px;
Expand Down
155 changes: 155 additions & 0 deletions src/panels/management/Utxos.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
.utxo-card {
min-width: 300px;
}

.utxo-loader {
display:flex;
justify-content: center;
align-items: center;
margin: 10px;
width: 100%;
}

.utxos {
display: flex;
flex-wrap: wrap;
justify-content: start;
width: calc(100% - 8px);
max-width: 650px;
height: 230px;
max-height: 230px;
overflow-y:auto;
overflow-x: hidden;
background-color: #0002;
border-radius: 8px;
}

.utxo {
background-color: var(--main-background-darkest);
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: start;
font-size: 15px;
margin-right: 10px;
margin-left: 10px;
}

.utxo-header {
border-radius: 8px;
background-color: var(--main-background-darkest);
font-size: 13px;
display: flex;
align-items: center;
justify-content: end;
padding-left: 15px;
padding-right: 10px;
padding-bottom: 2px;
margin-top: 10px;
border-bottom: none;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
margin-right: 10px;
}

.header-shrinker {
display: flex;
align-self: flex-end;
margin-bottom: -10px;
padding: 5px;
padding-left: 10px;
z-index: 98;
}

.utxo-select-container {
font-size: 12px;
display: flex;
justify-content: ce;
align-items: center;
}

.utxo-select-container input {
margin-bottom: 1px;
margin-left: 5px;
}

.asset {
padding: 5px;
margin-bottom: 2px;
padding-left: 10px;
padding-right: 10px;
display: flex;
width: 100%;
box-sizing: border-box;
justify-content: space-between;
font-size: 12px;

border-radius: 4px;
}

.datum-indicator {
font-size: 12px;
text-decoration: underline;
}
.script-ref {
margin-right: 20px;
}

.assets-header {
font-size: 14px;
margin-left: 20px;
}

.no-unspent-outputs {
font-size: 13px;
padding: 5px;
display: flex;
width: 100%;
justify-content: center;
align-items: center;
}
.assets-container {
width: 90%;
border-radius: 4px;
margin-top: 2px;
margin-bottom: 10px;
align-self: center;
gap: 2px;
display: flex;
flex-direction: column;
}
.utxos-heading {
font-size: 18px;
}

.assets-container .asset:nth-child(even) {
background-color: var(--alternate-color-even);
}

.assets-container .asset:nth-child(odd) {
background-color: var(--alternate-color-odd);
}


.no-datum-indicator {
font-size: 12px;
}

.datum-and-script-ref {
display: flex;
width: 100%;
justify-content: flex-end;
align-items: center;
gap: 20px;
margin-top: 2px;
margin-bottom: 2px;
font-size: 13px;
}

@supports ( -moz-appearance:none ){
.utxos {
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-color) #0000;
scrollbar-gutter: stable;
}
}
163 changes: 163 additions & 0 deletions src/panels/management/Utxos.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { useEffect, useState } from "react"
import JsonPopup from "../../components/JsonPopup"
import { Data, UTxO, toText } from "lucid-cardano"
import { useLucid } from "../../components/LucidProvider"
import { isSameUtxo, sumAssets } from "../../util/utxo"
import { deconstructObject } from "../../util/data"
import { shortenAddress } from "../../util/strings"
import Copy from "../../components/Copy"
import { useSelector } from "react-redux"
import { RootState } from "../../app/store"
import { UtxoSource } from "./transact/BetterUtxoSelector"
import './Utxos.css'

type UtxosProps = {
address: string
source: UtxoSource
onUtxoUpdate?: (utxos: UTxO[]) => void
onSelectedUtxosUpdate?: (selectedUtxos: UTxO[]) => void
selectable?: boolean
excludeUtxos?: UTxO[]
selectedUtxos?: UTxO[]
}

function Utxos({ address, source, selectable = false, onSelectedUtxosUpdate = () => {}, excludeUtxos = [], selectedUtxos= [], onUtxoUpdate = () => {} }: UtxosProps) {
const wallets = useSelector((state: RootState) => state.management.wallets)
const [utxos, setUtxos] = useState<UTxO[]>([])
const [isLoadingUtxos, setIsLoadingUtxos] = useState(false)
const [utxosError, setUtxosError] = useState('')
const { lucid, isLucidLoading } = useLucid()

useEffect(() => {
async function getContractUtxos() {
if (isLucidLoading) {
return
}

const connectedWallet = source === 'wallet' && wallets.find(wallet => wallet.address === address && wallet.isCurrentlyConnected)

try {
setIsLoadingUtxos(true)
setUtxosError('')

let fetchedUtxos = undefined
if (connectedWallet) {
fetchedUtxos = await lucid!!.wallet.getUtxos()
} else {
fetchedUtxos = await lucid!!.provider.getUtxos(address)
}

onUtxoUpdate(fetchedUtxos)

setUtxos(fetchedUtxos)
} catch (e: any) {
setUtxosError(e.message)
} finally {
setIsLoadingUtxos(false)
}

}

getContractUtxos()
}, [isLucidLoading, address])


if (isLucidLoading) {
return <></>
}

const loadingSpinner = <div className="utxo-loader">Fetching...<div className="lds-ring"><div></div><div></div><div></div><div></div></div></div>

if (utxosError) {
return (
<div className='utxo-loader'>{utxosError}</div>
)
}

const shownUtxos = utxos.filter(utxo => !excludeUtxos.find(excludedUtxo => isSameUtxo(excludedUtxo, utxo)))
return (
<div className='utxos'>
{
isLoadingUtxos ? loadingSpinner : shownUtxos.length > 0 ? shownUtxos.map(utxo => {
const parsedDatum = utxo.datum ? deconstructObject(Data.from(utxo.datum)) : null

return (
<div key={`${utxo.txHash}${utxo.outputIndex}`} className='utxo-card'>
<div className='header-shrinker'>
<div
className='utxo-header'
>
{`${shortenAddress(utxo.txHash)}@${utxo.outputIndex}`}<Copy value={utxo.txHash} />
</div>
{
selectable ?
<div
className='utxo-select-container'
>
Add
<input
type='checkbox'
checked={(selectedUtxos.find(selectedUtxo => isSameUtxo(selectedUtxo, utxo)) !== undefined)}
onChange={(e) => {
const newSelection = e.target.checked ?
[...selectedUtxos, utxo] :
selectedUtxos.filter(selectedUtxo => !isSameUtxo(selectedUtxo, utxo))

onSelectedUtxosUpdate(newSelection)
}}
/>
</div> : null
}
</div>
<div
className='utxo'
key={`${utxo.txHash}${utxo.outputIndex}`}
>

<div className='datum-and-script-ref'>
<div
className='datum'
>
{
utxo.datum ?
<JsonPopup jsonString={JSON.stringify(parsedDatum, null, 2)}>
<span className='datum-indicator'>Datum</span>
</JsonPopup> : '​'
// <span className='no-datum-indicator'>No Datum</span>
}
</div>

<div
className='script-ref'
>
{
utxo.scriptRef ?
<JsonPopup jsonString={utxo.scriptRef.script}>
<span className='datum-indicator'>Ref</span>
</JsonPopup> : null
// <span className='no-datum-indicator'>No Reference Script</span>
}
</div>
</div>
<div className='assets-container'>
{
Object.entries(utxo.assets).map(([assetName, quantity]) => {
return (
<div key={assetName} className='asset'>
<div>{assetName === 'lovelace' ? assetName : `[${shortenAddress(assetName.substring(0, 55), 4, 4)}] ${toText(assetName.substring(56))}`}</div>
<div>{quantity.toString()}</div>
</div>
)
})
}
</div>
</div>
</div>
)
}) : <div className='no-unspent-outputs'>No unspent outputs found at this address.</div>
}
</div>
)
}

export { Utxos }
2 changes: 1 addition & 1 deletion src/panels/management/contract/AddContract.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function AddContract() {
</div>

<div className='add-contract-selection-container'>
<div className='input-label'>Validator Name </div>
<div className='input-label'>Validator</div>
{
scriptType === 'aiken' ?
(
Expand Down
Loading

0 comments on commit 2e38002

Please sign in to comment.