Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,14 @@ In case the Borrower fails to pay interest before the lending contract expiry, t

From repo root:

```bash
docker compose up --build
```
1. Create the environment file (in the root):
```bash
cp .env.example .env
```
2. Start the services:
```bash
docker compose up --build
```


### Locally (without Docker)
Expand Down
4 changes: 2 additions & 2 deletions web/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM rust:1.90-bookworm AS lwk-builder

ARG LWK_REF=wasm_0.15.0
ARG LWK_COMMIT=5b015d6548a2e5ce60c5fcaae449248447e4c02d
ARG LWK_REF=wasm_0.16.0
ARG LWK_COMMIT=4786e456db6efc05413721f6489899a6426eaa47

RUN apt-get update && apt-get install -y --no-install-recommends git pkg-config libssl-dev ca-certificates clang && rm -rf /var/lib/apt/lists/*
RUN rustup target add wasm32-unknown-unknown
Expand Down
10 changes: 8 additions & 2 deletions web/src/pages/Dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import {
import { EsploraClient } from '../../api/esplora'
import { OfferTable } from '../../components/OfferTable'
import type { OfferShort } from '../../types/offers'
import { getScriptPubkeyHexFromAddress, getP2pkAddressFromSecret, P2PK_NETWORK } from '../../utility/addressP2pk'
import {
getScriptPubkeyHexFromAddress,
getP2pkAddressFromSecret,
P2PK_NETWORK,
} from '../../utility/addressP2pk'
import { POLICY_ASSET_ID } from '../../utility/addressP2pk'
import { deriveSecretKeyFromIndex, parseSeedHex } from '../../utility/seed'

Expand Down Expand Up @@ -133,7 +137,9 @@ export function Dashboard({

const allBorrowerIds = [...new Set([...idsByScript, ...idsByBorrowerPubkey])]
const [scriptOffersWithParticipants, borrowerOffersWithParticipants] = await Promise.all([
idsByScript.length === 0 ? Promise.resolve([]) : fetchOfferDetailsBatchWithParticipants(idsByScript),
idsByScript.length === 0
? Promise.resolve([])
: fetchOfferDetailsBatchWithParticipants(idsByScript),
allBorrowerIds.length === 0
? Promise.resolve([])
: fetchOfferDetailsBatchWithParticipants(allBorrowerIds),
Expand Down
4 changes: 2 additions & 2 deletions web/src/simplicity/covenants/lending.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ export function buildLendingWitness(
): LwkSimplicityWitnessValues {
const { SimplicityType, SimplicityTypedValue, SimplicityWitnessValues } = lwk

const pathType = new SimplicityType('Either<(), ()>')
const pathType = SimplicityType.fromString('Either<(), ()>')
const branchStr = params.branch === 'LoanRepayment' ? 'Left(())' : 'Right(())'
const pathValue = new SimplicityTypedValue(branchStr, pathType)
const pathValue = SimplicityTypedValue.parse(branchStr, pathType)

let witness = new SimplicityWitnessValues()
witness = witness.addValue('PATH', pathValue)
Expand Down
6 changes: 3 additions & 3 deletions web/src/simplicity/covenants/preLock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ export function buildPreLockWitness(
): LwkSimplicityWitnessValues {
const { SimplicityType, SimplicityTypedValue, SimplicityWitnessValues } = lwk

const pathType = new SimplicityType('Either<(), Signature>')
const pathType = SimplicityType.fromString('Either<(), Signature>')

const pathValue =
params.branch === 'LendingCreation'
? new SimplicityTypedValue('Left(())', pathType)
: new SimplicityTypedValue(`Right(0x${params.cancellationSignatureHex ?? ''})`, pathType)
? SimplicityTypedValue.parse('Left(())', pathType)
: SimplicityTypedValue.parse(`Right(0x${params.cancellationSignatureHex ?? ''})`, pathType)

let witness = new SimplicityWitnessValues()
const next = witness.addValue('PATH', pathValue)
Expand Down
21 changes: 8 additions & 13 deletions web/src/simplicity/lwk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@

let lwkInit: Promise<typeof import('lwk_web')> | null = null

function getWasmUrl(): string {
if (import.meta.env.DEV) return '/lwk_wasm_bg.wasm'
return `${import.meta.env.BASE_URL}assets/lwk_wasm_bg.wasm`
}

export async function getLwk(): Promise<typeof import('lwk_web')> {
if (!lwkInit) {
lwkInit = (async () => {
const lwk = await import('lwk_web')
if (typeof lwk.default === 'function') await lwk.default(getWasmUrl())
if (typeof lwk.default === 'function') await lwk.default()
return lwk
})()
}
Expand All @@ -30,7 +25,7 @@ export type Lwk = Awaited<ReturnType<typeof getLwk>>
export type LwkSimplicityArguments = InstanceType<Lwk['SimplicityArguments']>

/** Instance of LWK XOnlyPublicKey. */
export type LwkXOnlyPublicKey = InstanceType<Lwk['XOnlyPublicKey']>
export type LwkXOnlyPublicKey = ReturnType<Lwk['XOnlyPublicKey']['fromBytes']>

/** Instance of LWK Script. */
export type LwkScript = InstanceType<Lwk['Script']>
Expand All @@ -42,25 +37,25 @@ export type LwkTxOut = ReturnType<Lwk['TxOut']['fromExplicit']>
export type LwkTxOutArray = LwkTxOut[]

/** Instance of LWK SimplicityProgram. */
export type LwkSimplicityProgram = InstanceType<Lwk['SimplicityProgram']>
export type LwkSimplicityProgram = ReturnType<Lwk['SimplicityProgram']['load']>

/** Instance of LWK SimplicityTypedValue. */
export type LwkSimplicityTypedValue = InstanceType<Lwk['SimplicityTypedValue']>
export type LwkSimplicityTypedValue = ReturnType<Lwk['SimplicityTypedValue']['fromU8']>

/** Instance of LWK SimplicityWitnessValues. */
export type LwkSimplicityWitnessValues = InstanceType<Lwk['SimplicityWitnessValues']>

/** Instance of LWK SimplicityType (for parsing type strings). */
export type LwkSimplicityType = InstanceType<Lwk['SimplicityType']>
export type LwkSimplicityType = ReturnType<Lwk['SimplicityType']['u1']>

/** Instance of LWK Keypair. */
export type LwkKeypair = InstanceType<Lwk['Keypair']>
export type LwkKeypair = ReturnType<Lwk['Keypair']['fromSecretBytes']>

/** LWK Network (return type of Network.mainnet() / Network.testnet()). */
export type LwkNetwork = ReturnType<Lwk['Network']['mainnet']>

/** LWK transaction type (first argument of getSighashAll / return of finalizeTransaction). */
export type LwkTransaction = Parameters<InstanceType<Lwk['SimplicityProgram']>['getSighashAll']>[0]
export type LwkTransaction = ReturnType<Lwk['Transaction']['fromString']>

/** PSET that can yield the unsigned transaction for LWK signing (extractTx). */
export interface PsetWithExtractTx {
Expand All @@ -80,7 +75,7 @@ export interface CreateP2trAddressParams {
export async function createP2trAddress(params: CreateP2trAddressParams): Promise<string> {
const lwk = await getLwk()
const { SimplicityProgram, Network } = lwk
const program = new SimplicityProgram(params.source, params.args)
const program = SimplicityProgram.load(params.source, params.args)
const net = params.network === 'mainnet' ? Network.mainnet() : Network.testnet()
const address = program.createP2trAddress(params.internalKey, net)
return address.toString()
Expand Down
12 changes: 6 additions & 6 deletions web/src/tx/acceptOffer/finalizeAcceptOfferTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ export async function finalizeAcceptOfferTx(
const net = network === 'mainnet' ? Network.mainnet() : Network.testnet()
const taprootUnspendableKey = getTaprootUnspendableInternalKey(lwk)

const keypair = new Keypair(lenderSecretKey)
const p2pkInternalKey = keypair.xOnlyPublicKey()
const p2pkArgs = buildP2pkArguments(lwk, { publicKeyHex: p2pkInternalKey.toHex() })
const p2pkProgram = new SimplicityProgram(getSource('p2pk'), p2pkArgs)
const keypair = Keypair.fromSecretBytes(lenderSecretKey)
const p2pkInternalKey = keypair.xOnlyPublicKey
const p2pkArgs = buildP2pkArguments(lwk, { publicKeyHex: p2pkInternalKey.toString() })
const p2pkProgram = SimplicityProgram.load(getSource('p2pk'), p2pkArgs)

const preLockArgs = buildPreLockSimplicityArgs(lwk, preLockArguments)
const preLockProgram = new SimplicityProgram(getSource('pre_lock'), preLockArgs)
const preLockProgram = SimplicityProgram.load(getSource('pre_lock'), preLockArgs)
const preLockWitness = buildPreLockWitness(lwk, { branch: 'LendingCreation' })

const preLockScriptHex = prevouts[0]?.scriptpubkey ?? prevouts[0]?.scriptpubkey_hex ?? ''
Expand All @@ -69,7 +69,7 @@ export async function finalizeAcceptOfferTx(
}
const preLockInputScriptHash = await hashScriptPubkeyHex(preLockScriptHex)
const scriptAuthArgs = buildScriptAuthArguments(lwk, { scriptHash: preLockInputScriptHash })
const scriptAuthProgram = new SimplicityProgram(getSource('script_auth'), scriptAuthArgs)
const scriptAuthProgram = SimplicityProgram.load(getSource('script_auth'), scriptAuthArgs)
const scriptAuthInternalKey = getTaprootUnspendableInternalKey(lwk)
const scriptAuthWitness = buildScriptAuthWitness(lwk, { inputScriptIndex: 0 })

Expand Down
10 changes: 5 additions & 5 deletions web/src/tx/assetAuthUnlock/finalizeAssetAuthUnlockTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ export async function finalizeAssetAuthUnlockTx(
const net = network === 'mainnet' ? Network.mainnet() : Network.testnet()
const taprootUnspendableKey = getTaprootUnspendableInternalKey(lwk)

const keypair = new Keypair(lenderSecretKey)
const p2pkInternalKey = keypair.xOnlyPublicKey()
const p2pkArgs = buildP2pkArguments(lwk, { publicKeyHex: p2pkInternalKey.toHex() })
const p2pkProgram = new SimplicityProgram(getSource('p2pk'), p2pkArgs)
const keypair = Keypair.fromSecretBytes(lenderSecretKey)
const p2pkInternalKey = keypair.xOnlyPublicKey
const p2pkArgs = buildP2pkArguments(lwk, { publicKeyHex: p2pkInternalKey.toString() })
const p2pkProgram = SimplicityProgram.load(getSource('p2pk'), p2pkArgs)

const assetAuthArgsLwk = buildAssetAuthArguments(lwk, {
assetId: assetAuthArguments.assetId,
assetAmount: assetAuthArguments.assetAmount,
withAssetBurn: assetAuthArguments.withAssetBurn,
})
const assetAuthProgram = new SimplicityProgram(getSource('asset_auth'), assetAuthArgsLwk)
const assetAuthProgram = SimplicityProgram.load(getSource('asset_auth'), assetAuthArgsLwk)
const assetAuthWitness = buildAssetAuthWitness(lwk, {
inputAssetIndex: 1,
outputAssetIndex: 1,
Expand Down
12 changes: 6 additions & 6 deletions web/src/tx/loanLiquidation/finalizeLoanLiquidationTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ export async function finalizeLoanLiquidationTx(
const net = network === 'mainnet' ? Network.mainnet() : Network.testnet()
const taprootUnspendableKey = getTaprootUnspendableInternalKey(lwk)

const keypair = new Keypair(lenderSecretKey)
const p2pkInternalKey = keypair.xOnlyPublicKey()
const p2pkArgs = buildP2pkArguments(lwk, { publicKeyHex: p2pkInternalKey.toHex() })
const p2pkProgram = new SimplicityProgram(getSource('p2pk'), p2pkArgs)
const keypair = Keypair.fromSecretBytes(lenderSecretKey)
const p2pkInternalKey = keypair.xOnlyPublicKey
const p2pkArgs = buildP2pkArguments(lwk, { publicKeyHex: p2pkInternalKey.toString() })
const p2pkProgram = SimplicityProgram.load(getSource('p2pk'), p2pkArgs)

const lendingArgsLwk = buildLendingArguments(lwk, {
collateralAssetId: lendingArgs.collateralAssetId,
Expand All @@ -66,11 +66,11 @@ export async function finalizeLoanLiquidationTx(
lenderPrincipalCovHash: lendingArgs.lenderPrincipalCovHash,
lendingParams: lendingArgs.lendingParams,
})
const lendingProgram = new SimplicityProgram(getSource('lending'), lendingArgsLwk)
const lendingProgram = SimplicityProgram.load(getSource('lending'), lendingArgsLwk)
const lendingWitness = buildLendingWitness(lwk, { branch: 'LoanLiquidation' })

const scriptAuthArgs = buildScriptAuthArguments(lwk, { scriptHash: lendingCovHash })
const scriptAuthProgram = new SimplicityProgram(getSource('script_auth'), scriptAuthArgs)
const scriptAuthProgram = SimplicityProgram.load(getSource('script_auth'), scriptAuthArgs)
const scriptAuthInternalKey = getTaprootUnspendableInternalKey(lwk)
const scriptAuthWitness = buildScriptAuthWitness(lwk, { inputScriptIndex: 0 })

Expand Down
12 changes: 6 additions & 6 deletions web/src/tx/loanRepayment/finalizeLoanRepaymentTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ export async function finalizeLoanRepaymentTx(
const net = network === 'mainnet' ? Network.mainnet() : Network.testnet()
const taprootUnspendableKey = getTaprootUnspendableInternalKey(lwk)

const keypair = new Keypair(borrowerSecretKey)
const p2pkInternalKey = keypair.xOnlyPublicKey()
const p2pkArgs = buildP2pkArguments(lwk, { publicKeyHex: p2pkInternalKey.toHex() })
const p2pkProgram = new SimplicityProgram(getSource('p2pk'), p2pkArgs)
const keypair = Keypair.fromSecretBytes(borrowerSecretKey)
const p2pkInternalKey = keypair.xOnlyPublicKey
const p2pkArgs = buildP2pkArguments(lwk, { publicKeyHex: p2pkInternalKey.toString() })
const p2pkProgram = SimplicityProgram.load(getSource('p2pk'), p2pkArgs)

const lendingArgsLwk = buildLendingArguments(lwk, {
collateralAssetId: lendingArgs.collateralAssetId,
Expand All @@ -65,11 +65,11 @@ export async function finalizeLoanRepaymentTx(
lenderPrincipalCovHash: lendingArgs.lenderPrincipalCovHash,
lendingParams: lendingArgs.lendingParams,
})
const lendingProgram = new SimplicityProgram(getSource('lending'), lendingArgsLwk)
const lendingProgram = SimplicityProgram.load(getSource('lending'), lendingArgsLwk)
const lendingWitness = buildLendingWitness(lwk, { branch: 'LoanRepayment' })

const scriptAuthArgs = buildScriptAuthArguments(lwk, { scriptHash: lendingCovHash })
const scriptAuthProgram = new SimplicityProgram(getSource('script_auth'), scriptAuthArgs)
const scriptAuthProgram = SimplicityProgram.load(getSource('script_auth'), scriptAuthArgs)
const scriptAuthInternalKey = getTaprootUnspendableInternalKey(lwk)
const scriptAuthWitness = buildScriptAuthWitness(lwk, { inputScriptIndex: 0 })

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,21 @@ export async function finalizePreLockCancellationTx(
const net = network === 'mainnet' ? Network.mainnet() : Network.testnet()
const taprootUnspendableKey = getTaprootUnspendableInternalKey(lwk)

const borrowerKeypair = new Keypair(borrowerSecretKey)
const p2pkInternalKey = borrowerKeypair.xOnlyPublicKey()
const p2pkArgs = buildP2pkArguments(lwk, { publicKeyHex: p2pkInternalKey.toHex() })
const p2pkProgram = new SimplicityProgram(getSource('p2pk'), p2pkArgs)
const borrowerKeypair = Keypair.fromSecretBytes(borrowerSecretKey)
const p2pkInternalKey = borrowerKeypair.xOnlyPublicKey
const p2pkArgs = buildP2pkArguments(lwk, { publicKeyHex: p2pkInternalKey.toString() })
const p2pkProgram = SimplicityProgram.load(getSource('p2pk'), p2pkArgs)

const preLockArgs = buildPreLockSimplicityArgs(lwk, preLockArguments)
const preLockProgram = new SimplicityProgram(getSource('pre_lock'), preLockArgs)
const preLockProgram = SimplicityProgram.load(getSource('pre_lock'), preLockArgs)

const preLockScriptHex = prevouts[0]?.scriptpubkey ?? prevouts[0]?.scriptpubkey_hex ?? ''
if (!preLockScriptHex) {
throw new Error('Missing preLock scriptpubkey in prevouts[0]')
}
const preLockInputScriptHash = await hashScriptPubkeyHex(preLockScriptHex)
const scriptAuthArgs = buildScriptAuthArguments(lwk, { scriptHash: preLockInputScriptHash })
const scriptAuthProgram = new SimplicityProgram(getSource('script_auth'), scriptAuthArgs)
const scriptAuthProgram = SimplicityProgram.load(getSource('script_auth'), scriptAuthArgs)
const scriptAuthInternalKey = getTaprootUnspendableInternalKey(lwk)
const scriptAuthWitness = buildScriptAuthWitness(lwk, { inputScriptIndex: 0 })

Expand Down
6 changes: 3 additions & 3 deletions web/src/utility/addressP2pk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ export async function getP2pkAddressFromSecret(
const SimplicityArguments = lwk.SimplicityArguments
const SimplicityTypedValue = lwk.SimplicityTypedValue

const keypair = new Keypair(secretKey)
const internalKey = keypair.xOnlyPublicKey()
const internalKeyHex = internalKey.toHex()
const keypair = Keypair.fromSecretBytes(secretKey)
const internalKey = keypair.xOnlyPublicKey
const internalKeyHex = internalKey.toString()

const args = new SimplicityArguments().addValue(
'PUBLIC_KEY',
Expand Down
8 changes: 4 additions & 4 deletions web/src/utility/signP2pkInputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ export function signP2pkInputs(params: SignP2pkInputsParams): string {
} = lwk

const net = network === 'mainnet' ? Network.mainnet() : Network.testnet()
const keypair = new Keypair(secretKey)
const internalKey = keypair.xOnlyPublicKey()
const keypair = Keypair.fromSecretBytes(secretKey)
const internalKey = keypair.xOnlyPublicKey
const args = new SimplicityArguments().addValue(
'PUBLIC_KEY',
SimplicityTypedValue.fromU256Hex(internalKey.toHex())
SimplicityTypedValue.fromU256Hex(internalKey.toString())
)
const program = new SimplicityProgram(getSource('p2pk'), args)
const program = SimplicityProgram.load(getSource('p2pk'), args)

let tx: LwkTransaction = pset.extractTx()

Expand Down
Loading