Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metalamp/lending pool/incentivized tokens #62

Open
wants to merge 4 commits into
base: MetaLamp/lending-pool/development
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions MetaLamp/lending-pool/generate-purs/AaveTypes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import Language.PureScript.Bridge.Builder (BridgeData)
import Language.PureScript.Bridge.TypeParameters (A, E)
import qualified PSGenerator.Common
import Plutus.Abstract.ContractResponse (ContractResponse)
import Plutus.Abstract.IncentivizedAmount (IncentivizedAmount)
import qualified Plutus.Contracts.LendingPool.OffChain.Info as Aave
import qualified Plutus.Contracts.LendingPool.OffChain.Owner as Aave
import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave
Expand All @@ -52,6 +53,7 @@ psRatio = expand <$> psTypeParameters

aaveTypes :: [SumType 'Haskell]
aaveTypes = [ (equal <*> (genericShow <*> mkSumType)) (Proxy @AaveContracts)
, (equal <*> (genericShow <*> mkSumType)) (Proxy @IncentivizedAmount)
, (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.Aave)
, (equal <*> (genericShow <*> mkSumType)) (Proxy @Oracle.Oracle)
, (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractResponse E A))
Expand Down
2 changes: 1 addition & 1 deletion MetaLamp/lending-pool/plutus-starter.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ maintainer: Your email

library
exposed-modules:
Plutus.Abstract.State Plutus.Abstract.State.Select Plutus.Abstract.State.Update Plutus.Abstract.ContractResponse Plutus.Abstract.OutputValue Plutus.Abstract.TxUtils Plutus.Contracts.Service.FungibleToken Plutus.Contracts.Service.Oracle Plutus.Contracts.LendingPool.OnChain.Core Plutus.Contracts.LendingPool.OnChain.Core.Script Plutus.Contracts.LendingPool.OnChain.Core.Validator Plutus.Contracts.LendingPool.OnChain.Core.Logic Plutus.Contracts.LendingPool.OnChain.AToken Plutus.Contracts.LendingPool.OffChain.AToken Plutus.Contracts.LendingPool.OffChain.Info Plutus.Contracts.LendingPool.OffChain.Owner Plutus.Contracts.LendingPool.OffChain.State Plutus.Contracts.LendingPool.OffChain.User Plutus.PAB.Simulation Ext.Plutus.Ledger.Value Ext.Plutus.Ledger.Contexts
Plutus.Abstract.State Plutus.Abstract.State.Select Plutus.Abstract.State.Update Plutus.Abstract.ContractResponse Plutus.Abstract.OutputValue Plutus.Abstract.TxUtils Plutus.Abstract.IncentivizedAmount Plutus.Contracts.Service.FungibleToken Plutus.Contracts.Service.Oracle Plutus.Contracts.LendingPool.Shared Plutus.Contracts.LendingPool.OnChain.Core Plutus.Contracts.LendingPool.OnChain.Core.Script Plutus.Contracts.LendingPool.OnChain.Core.Validator Plutus.Contracts.LendingPool.OnChain.Core.Logic Plutus.Contracts.LendingPool.OnChain.AToken Plutus.Contracts.LendingPool.OffChain.AToken Plutus.Contracts.LendingPool.OffChain.Info Plutus.Contracts.LendingPool.OffChain.Owner Plutus.Contracts.LendingPool.OffChain.State Plutus.Contracts.LendingPool.OffChain.User Plutus.PAB.Simulation Ext.Plutus.Ledger.Value Ext.Plutus.Ledger.Contexts
build-depends:
base >= 4.9 && < 5,
aeson,
Expand Down
30 changes: 26 additions & 4 deletions MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@

module Ext.Plutus.Ledger.Contexts where

import Ledger (Address (Address),
Datum (getDatum), DatumHash,
PubKeyHash,
import Ledger (Address (Address), Datum (..),
DatumHash, PubKeyHash,
ScriptContext,
TxInInfo (txInInfoResolved),
TxInfo (txInfoInputs),
TxOut (TxOut, txOutAddress, txOutDatumHash, txOutValue),
ValidatorHash, Value, findDatum)
ValidatorHash, Value, findDatum,
findDatumHash, ownHashes,
scriptContextTxInfo,
scriptOutputsAt)
import Plutus.V1.Ledger.Contexts (ScriptContext)
import Plutus.V1.Ledger.Credential (Credential (PubKeyCredential, ScriptCredential))
import qualified PlutusTx
import PlutusTx.Prelude (Eq ((==)), Maybe (..), filter,
find, fst, mapMaybe, mconcat,
otherwise, snd, ($), (.), (<$>),
(>>=))

{-# INLINABLE findOnlyOneDatumByValue #-}
findOnlyOneDatumByValue :: PlutusTx.IsData a => ScriptContext -> Value -> Maybe a
findOnlyOneDatumByValue ctx value = findOnlyOneDatumHashByValue value (getScriptOutputs ctx) >>= parseDatum (scriptContextTxInfo ctx)

{-# INLINABLE findOnlyOneDatumHashByValue #-}
-- | Find the hash of a datum, if it is part of the script's outputs.
-- Assume search failed if more than one correspondence is found.
Expand All @@ -28,6 +36,20 @@ findOnlyOneDatumHashByValue val outs = fst <$> case filter f outs of
where
f (_, val') = val' == val

{-# INLINABLE getScriptOutputs #-}
getScriptOutputs :: ScriptContext -> [(DatumHash, Value)]
getScriptOutputs ctx = scriptOutputsAt scriptsHash (scriptContextTxInfo ctx)
where
(scriptsHash, _) = ownHashes ctx

{-# INLINABLE findValueByDatum #-}
findValueByDatum :: PlutusTx.IsData a => ScriptContext -> a -> Maybe Value
findValueByDatum ctx datum = (`findValueByDatumHash` scriptOutputs) <$> findDatumHash (Datum $ PlutusTx.toData datum) txInfo
where
txInfo = scriptContextTxInfo ctx
(scriptsHash, _) = ownHashes ctx
scriptOutputs = scriptOutputsAt scriptsHash txInfo

{-# INLINABLE findValueByDatumHash #-}
-- | Concat value of the script's outputs that have the specified hash of a datum
findValueByDatumHash :: DatumHash -> [(DatumHash, Value)] -> Value
Expand Down
44 changes: 44 additions & 0 deletions MetaLamp/lending-pool/src/Plutus/Abstract/IncentivizedAmount.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -fno-specialise #-}
{-# OPTIONS_GHC -fno-strictness #-}
{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-}
{-# OPTIONS_GHC -fno-omit-interface-pragmas #-}
{-# OPTIONS_GHC -fobject-code #-}

module Plutus.Abstract.IncentivizedAmount where

import qualified Control.Lens as Lens
import Data.Aeson (FromJSON, ToJSON)
import GHC.Generics
import qualified Plutus.Abstract.TxUtils as TxUtils
import Plutus.V1.Ledger.Slot (Slot (..))
import qualified PlutusTx
import PlutusTx.Prelude
import PlutusTx.Ratio (Ratio)
import qualified Prelude
import Schema (ToSchema)

data IncentivizedAmount = IncentivizedAmount{ iaSlot :: Slot, iaRate :: Rational, iaAmount :: Rational }
deriving stock (Prelude.Eq, Prelude.Show, Generic)
deriving anyclass (ToJSON, FromJSON)

Lens.makeClassy_ ''IncentivizedAmount

instance Eq IncentivizedAmount where
a == b = iaSlot a == iaSlot b && iaAmount a == iaAmount b && iaRate a == iaRate b

{-# INLINABLE accrue #-}
accrue :: Rational -> Slot -> IncentivizedAmount -> IncentivizedAmount
accrue newRate newSlot (IncentivizedAmount oldSlot oldRate amount) = IncentivizedAmount newSlot newRate (amount * oldRate)
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ createReserve aave CreateParams {..} =
rAmount = 0,
rAToken = AToken.makeAToken (Core.aaveHash aave) cpAsset,
rLiquidityIndex = 1,
rCurrentStableBorrowRate = 11 % 10, -- TODO configure borrow rate when lending core will be ready
rCurrentStableBorrowRate = 101 % 100,
rCurrentStableAccrualRate = 101 % 100,
rTrustedOracle = Oracle.toTuple cpOracle
}

Expand All @@ -102,7 +103,6 @@ start' getAaveToken params = do
let aave = Core.aave aaveToken
payment = assetClassValue (Core.aaveProtocolInst aave) 1
let aaveTokenTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pkh (Core.LendingPoolDatum pkh) payment
-- TODO how to ensure that newly minted owner token is paid to the script before someone else spends it?
ledgerTx <- TxUtils.submitTxPair aaveTokenTx
void $ awaitTxConfirmed $ txId ledgerTx

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import Ledger.Constraints.TxConstraints as Constraints
import qualified Ledger.Scripts as Scripts
import qualified Ledger.Typed.Scripts as Scripts
import Playground.Contract
import Plutus.Abstract.IncentivizedAmount (accrue)
import Plutus.Abstract.OutputValue (OutputValue (..),
_ovValue)
import qualified Plutus.Abstract.State as State
Expand All @@ -40,7 +41,10 @@ import Plutus.Contracts.LendingPool.OnChain.Core (Aave (..),
AaveScript,
Reserve (..),
UserConfig (..),
UserConfigId)
UserConfigId,
getAaveState,
reserveStateToken,
userStateToken)
import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core
import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken
import Plutus.V1.Ledger.Ada (adaValueOf,
Expand All @@ -64,10 +68,6 @@ findOutputBy aave = State.findOutputBy (Core.aaveAddress aave)
findAaveOwnerToken :: Aave -> Contract w s Text (OutputValue PubKeyHash)
findAaveOwnerToken aave@Aave{..} = findOutputBy aave aaveProtocolInst (^? Core._LendingPoolDatum)

reserveStateToken, userStateToken :: Aave -> AssetClass
reserveStateToken aave = State.makeStateToken (Core.aaveHash aave) (aaveProtocolInst aave) "aaveReserve"
userStateToken aave = State.makeStateToken (Core.aaveHash aave) (aaveProtocolInst aave) "aaveUser"

findAaveReserves :: Aave -> Contract w s Text (OutputValue (AssocMap.Map AssetClass Reserve))
findAaveReserves aave = findOutputBy aave (reserveStateToken aave) (^? Core._ReservesDatum . _2)

Expand Down Expand Up @@ -97,10 +97,9 @@ updateState aave = State.updateState (Core.aaveInstance aave)

makeReserveHandle :: Aave -> (AssocMap.Map AssetClass Reserve -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map AssetClass Reserve)
makeReserveHandle aave toRedeemer =
let stateToken = reserveStateToken aave in
StateHandle {
stateToken = stateToken,
toDatum = Core.ReservesDatum stateToken,
stateToken = reserveStateToken aave,
toDatum = Core.ReservesDatum (getAaveState aave),
toRedeemer = toRedeemer
}

Expand All @@ -124,10 +123,9 @@ roundtripReserves aave redeemer = do

makeUserHandle :: Aave -> (AssocMap.Map UserConfigId UserConfig -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map UserConfigId UserConfig)
makeUserHandle aave toRedeemer =
let stateToken = userStateToken aave in
StateHandle {
stateToken = stateToken,
toDatum = Core.UserConfigsDatum stateToken,
stateToken = userStateToken aave,
toDatum = Core.UserConfigsDatum (getAaveState aave),
toRedeemer = toRedeemer
}

Expand Down
Loading