diff --git a/dApp-to-dApps/add-pool-liquidity/pool.ride b/dApp-to-dApps/add-pool-liquidity/pool.ride new file mode 100644 index 0000000..bd0add7 --- /dev/null +++ b/dApp-to-dApps/add-pool-liquidity/pool.ride @@ -0,0 +1,49 @@ +# This is an example of a pool contract for add liquidity scenario. +# +# Increases pool liquidity using attached WAVES tokens for leasing and USDN tokens for staking. + +{-# STDLIB_VERSION 5 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} + +let usdN = base58'' +let staker = Address(base58'') +let leasePool = Address(base58'') +let shareToken = base58'' + +@Callable(i) +func addLiquidity() = { + if (i.payments[0].assetId != unit || i.payments[1].assetId != usdN) + then + throw("unexpected assets") + else { + strict r = invoke(staker, "stake", [], [i.payments[1]]) + let stakingAmount = match r { + case a: Int => a + case _ => throw("unexpected result type from the staker") + } + + let stakingAmountKey = "STAKING_AMOUNT_" + i.caller.toString() + let leaseAmountKey = "LEASE_AMOUNT_" + i.caller.toString() + let idKey = "ID_" + i.caller.toString() + + let leasedAmount = this.getInteger(leaseAmountKey).valueOrElse(0) + let leaseId = this.getString(idKey) + + let newLease = Lease(leasePool, leasedAmount + i.payments[0].amount) + let newLeaseId = calculateLeaseId(newLease) + + let cancel = match leaseId { + case id: String => [ LeaseCancel(fromBase58String(id)) ] + case _ => [ StringEntry(idKey, toBase58String(newLeaseId)) ] + } + + cancel ++ + [ + newLease, + ScriptTransfer(i.caller, 1, shareToken), + IntegerEntry(leaseAmountKey, leasedAmount + i.payments[0].amount), + IntegerEntry(stakingAmountKey, stakingAmount) + ] + } +} diff --git a/dApp-to-dApps/add-pool-liquidity/staker.ride b/dApp-to-dApps/add-pool-liquidity/staker.ride new file mode 100644 index 0000000..f240070 --- /dev/null +++ b/dApp-to-dApps/add-pool-liquidity/staker.ride @@ -0,0 +1,24 @@ +# This is an example of a staker contract for add liquidity scenario. +# +# Receives USDN and saves the new staking amount in the state. + +{-# STDLIB_VERSION 5 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} + +let usdN = base58'' + +@Callable(i) +func stake() = { + if (i.payments[0].assetId != usdN) + then + throw("unexpected asset") + else { + let currentLiquidity = this.getInteger(i.originCaller.toString()).valueOrElse(0) + let newLiquidity = currentLiquidity + i.payments[0].amount + ( + [ IntegerEntry(i.originCaller.toString(), newLiquidity) ], + newLiquidity + ) + } +} diff --git a/dApp-to-dApps/flash-loan/borrower.ride b/dApp-to-dApps/flash-loan/borrower.ride new file mode 100644 index 0000000..ec08f44 --- /dev/null +++ b/dApp-to-dApps/flash-loan/borrower.ride @@ -0,0 +1,36 @@ +# This is an example of a borrower contract for flash loan scenario. +# +# Borrows token A, changes to B, then changes the funds received again to A, +# returns the money to the lender and stays in profit on token A. + +{-# STDLIB_VERSION 5 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} + +let loanFeePercent = 5 +let assetA = base58'' +let assetB = base58'' +let exchangerABAddress = Address(base58'') +let exchangerBAAddress = Address(base58'') +let loanerAddress = Address(base58'') + +@Callable(i) +func trade(beneficiary: ByteVector) = { + let loanAmount = + if (i.payments[0].assetId == assetA) + then i.payments[0].amount + else throw("unexpected payment asset") + + strict startBalanceB = this.assetBalance(assetB) + strict r1 = invoke(exchangerABAddress, "exchangeAB", [], [AttachedPayment(assetA, loanAmount)]) + strict diffB = this.assetBalance(assetB) - startBalanceB + + strict r2 = invoke(exchangerBAAddress, "exchangeBA", [], [AttachedPayment(assetB, diffB)]) + + let debt = loanAmount.fraction(100 + loanFeePercent, 100) + let profit = this.assetBalance(assetA) - debt + [ + ScriptTransfer(Address(beneficiary), profit, assetA), + ScriptTransfer(loanerAddress, debt, assetA) + ] +} diff --git a/dApp-to-dApps/flash-loan/exchanger1.ride b/dApp-to-dApps/flash-loan/exchanger1.ride new file mode 100644 index 0000000..ff37ea7 --- /dev/null +++ b/dApp-to-dApps/flash-loan/exchanger1.ride @@ -0,0 +1,21 @@ +# This is an example of a first exchanger contract for flash loan scenario. +# +# Changes A to B and transfers B to the address of the calling contract. +# Returns transfer amount. + +{-# STDLIB_VERSION 5 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} + +let aToBRate = 5 +let assetA = base58'' +let assetB = base58'' + +@Callable(i) +func exchangeAB() = { + if (i.payments[0].assetId == assetA) + then + [ ScriptTransfer(i.caller, i.payments[0].amount * aToBRate, assetB) ] + else + throw("unexpected token") +} diff --git a/dApp-to-dApps/flash-loan/exchanger2.ride b/dApp-to-dApps/flash-loan/exchanger2.ride new file mode 100644 index 0000000..b4a2ec3 --- /dev/null +++ b/dApp-to-dApps/flash-loan/exchanger2.ride @@ -0,0 +1,23 @@ +# This is an example of a second exchanger contract for flash loan scenario. +# +# Changes B to A and transfers A to the address of the calling contract. +# Returns transfer amount. + +{-# STDLIB_VERSION 5 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} + +let exchangeRate = 5 +let exchangeRateDiffPercent = 20 +let aToBRate = exchangeRate.fraction(100 - exchangeRateDiffPercent, 100) +let assetA = base58'' +let assetB = base58'' + +@Callable(i) +func exchangeBA() = { + if (i.payments[0].assetId == assetB) + then + [ ScriptTransfer(i.caller, i.payments[0].amount / aToBRate, assetA) ] + else + throw("unexpected token") +} diff --git a/dApp-to-dApps/flash-loan/loaner.ride b/dApp-to-dApps/flash-loan/loaner.ride new file mode 100644 index 0000000..8ec98d3 --- /dev/null +++ b/dApp-to-dApps/flash-loan/loaner.ride @@ -0,0 +1,29 @@ +# This is an example of a loaner contract for flash loan scenario. +# +# Should be called from the account related to the borrower. +# +# Calls the contract specified by the borrower when called in the transaction +# and applies the requested amount of token A in the call. +# Checks that upon completion of the call to the contract, the balance of token A has increased. + +{-# STDLIB_VERSION 5 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} + +let assetA = base58'' +let loanFeePercent = 5 + +@Callable(i) +func loan(amount: Int, callback: String, borrower: ByteVector) = { + strict startBalance = this.assetBalance(assetA) + strict r = invoke(Address(borrower), callback, [i.caller.bytes], [AttachedPayment(assetA, amount)]) + + let balanceDiff = this.assetBalance(assetA) - startBalance + let profit = amount.fraction(loanFeePercent, 100) + + if (balanceDiff < profit) + then + throw("debt is not paid: diff=" + balanceDiff.toString() + ", expected=" + profit.toString()) + else + [] +} diff --git a/dApp-to-dApps/swap/exchanger.ride b/dApp-to-dApps/swap/exchanger.ride new file mode 100644 index 0000000..a392228 --- /dev/null +++ b/dApp-to-dApps/swap/exchanger.ride @@ -0,0 +1,24 @@ +# This is an example of a exchanger contract for swap scenario. +# +# Calls the USDN staking contract canceling USDN staking for the amount +# that the user should receive during the exchange +# and transfers USDN to the user's address. + +{-# STDLIB_VERSION 5 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} + +let usdN = base58'' +let exchangeRate = 5 +let staker = Address(base58'') + +@Callable(i) +func exchangeWavesUsdN() = { + if (i.payments[0].assetId != unit) + then + throw("unexpected asset") + else { + strict r = invoke(staker, "cancelStake", [i.payments[0].amount * exchangeRate], []) + [ ScriptTransfer(i.caller, i.payments[0].amount * exchangeRate, usdN) ] + } +} diff --git a/dApp-to-dApps/swap/staker.ride b/dApp-to-dApps/swap/staker.ride new file mode 100644 index 0000000..559b386 --- /dev/null +++ b/dApp-to-dApps/swap/staker.ride @@ -0,0 +1,30 @@ +# This is an example of a staker contract for swap scenario. +# +# "stake" receives USDN and saves the new staking amount in the state. +# "cancelStake" withdraws the required amount from staking and transfers it to the account. + +{-# STDLIB_VERSION 5 #-} +{-# SCRIPT_TYPE ACCOUNT #-} +{-# CONTENT_TYPE DAPP #-} + +let usdN = base58'' + +@Callable(i) +func stake() = { + if (i.payments[0].assetId != usdN) + then + throw("unexpected asset") + else { + let currentLiquidity = this.getInteger(i.originCaller.toString()).valueOrElse(0) + [ IntegerEntry(i.originCaller.toString(), currentLiquidity + i.payments[0].amount) ] + } +} + +@Callable(i) +func cancelStake(amount: Int) = { + if (this.getIntegerValue(i.caller.toString()) >= amount) + then + [ ScriptTransfer(i.caller, amount, usdN) ] + else + throw("too big amount") +}