diff --git a/src/contracts/bsv20Loan.ts b/src/contracts/bsv20Loan.ts index 651f7193..b8136b52 100644 --- a/src/contracts/bsv20Loan.ts +++ b/src/contracts/bsv20Loan.ts @@ -2,18 +2,17 @@ import { BSV20V2 } from 'scrypt-ord' import { assert, ByteString, + byteString2Int, hash256, method, prop, PubKey, pubKey2Addr, - sha256, - Sha256, Sig, - SmartContract, - toByteString, + slice, Utils, } from 'scrypt-ts' +import { RabinPubKey, RabinSig, RabinVerifier } from 'scrypt-ts-lib' export class Bsv20Loan extends BSV20V2 { @prop() @@ -26,7 +25,7 @@ export class Bsv20Loan extends BSV20V2 { @prop() tokenAmt: bigint - // Fixed interest rate of the load. + // Fixed interest rate of the loan. // 1 = 1% @prop() interestRate: bigint @@ -44,6 +43,9 @@ export class Bsv20Loan extends BSV20V2 { @prop(true) taken: boolean + @prop() + oraclePubKey: RabinPubKey + constructor( id: ByteString, sym: ByteString, @@ -54,7 +56,8 @@ export class Bsv20Loan extends BSV20V2 { tokenAmt: bigint, interestRate: bigint, collateral: bigint, - deadline: bigint + deadline: bigint, + oraclePubKey: RabinPubKey ) { super(id, sym, max, dec) this.init(...arguments) @@ -66,10 +69,11 @@ export class Bsv20Loan extends BSV20V2 { this.collateral = collateral this.deadline = deadline this.taken = false + this.oraclePubKey = oraclePubKey } @method() - public takeLoan() { + public borrow() { // Check loan isn't taken yet. assert(this.taken == false, 'loan already taken') this.taken = true @@ -88,12 +92,30 @@ export class Bsv20Loan extends BSV20V2 { } @method() - public repay() { + public repay(oracleMsg: ByteString, oracleSig: RabinSig) { // Check loan is already taken. assert(this.taken == true, 'loan not taken yet') - // Pay lender back the principal token amount plus interest. + // Check oracle signature. + assert( + RabinVerifier.verifySig(oracleMsg, oracleSig, this.oraclePubKey), + 'oracle sig verify failed' + ) + + // Check that we're unlocking the UTXO specified in the oracles message. + assert( + slice(this.prevouts, 0n, 36n) == slice(oracleMsg, 0n, 36n), + 'first input is not spending specified ordinal UTXO' + ) + + // Get token amount held by the UTXO from oracle message. + const utxoTokenAmt = byteString2Int(slice(oracleMsg, 36n, 44n)) + + // Check token amount is correct. const interest = (this.tokenAmt * this.interestRate) / 100n + assert(utxoTokenAmt == this.tokenAmt + interest, 'invalid token amount') + + // Pay lender back the principal token amount plus interest. let outputs = BSV20V2.buildTransferOutput( pubKey2Addr(this.lender), this.id,