Skip to content

Commit 8798232

Browse files
Merge pull request #20 from mlabs-haskell/calum/fetch-single-nft
Contract to fetch single NFT
2 parents 705feb1 + bfcf8a6 commit 8798232

File tree

12 files changed

+125
-44
lines changed

12 files changed

+125
-44
lines changed

flake.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
repo = "cardano-transaction-lib";
1313
# should be same rev as in packages.dhall
1414
# Oh update, do `spago2nix generate`
15-
rev = "b7614b4e11a57b5b366b65509b86eb4b086bb1ce";
15+
# https://github.com/Plutonomicon/cardano-transaction-lib/pull/702/commits/6592f4188850ca4b2adab0c593c6a971087a54ba
16+
rev = "6592f4188850ca4b2adab0c593c6a971087a54ba";
1617
};
1718
nixpkgs.follows = "cardano-transaction-lib/nixpkgs";
1819
};

index.d.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ export function callMarketPlaceBuy(config: Config, args: BuyNftArgs):
22
Promise<void>
33
export function callMarketPlaceListNft(config: Config):
44
Promise<Array<NftListing>>
5+
/**
6+
* Fetch the info for a single NFT. Returns null if the given
7+
* transaction input has been spent (for example if the NFT has been
8+
* bought).
9+
*/
10+
export function callMarketPlaceFetchNft(config: Config, args: FetchNftArgs):
11+
Promise<NftListing?>
512
export function connectWallet(): Promise<any>
613
export function getWalletBalance(): Promise<any>
714

@@ -36,6 +43,8 @@ export type BuyNftArgs = {
3643

3744
}
3845

46+
export type FetchNftArgs = Input
47+
3948
export type NftCollectionArgs = {
4049
// CurrencySymbol of nft collection
4150
collectionNftCs: string,
@@ -66,8 +75,8 @@ export type NftListing = {
6675
}
6776

6877
export type Input = {
69-
transaction_id: String,
70-
input_index: number
78+
transactionId: String,
79+
inputIndex: number
7180
}
7281

7382
export type Output = {

index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ exports.callMarketPlaceListNft = async (config) => {
2727
return sb.callMarketPlaceListNft(config)();
2828
};
2929

30+
exports.callMarketPlaceFetchNft = async (config, args) => {
31+
const sb = await seabug;
32+
return sb.callMarketPlaceFetchNft(config)(args)();
33+
};
34+
3035

3136
/**
3237
* Returns a promise containing the connected wallet's balance.

packages.dhall

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,7 @@ let additions =
328328
]
329329
, repo = "https://github.com/Plutonomicon/cardano-transaction-lib.git"
330330
-- should be same rev as in flake.nix
331-
-- https://github.com/Plutonomicon/cardano-transaction-lib/pull/696
332-
-- PR: Return error if no utxo is specified for a tx input & Fix transaction inputs locking
333-
, version = "b7614b4e11a57b5b366b65509b86eb4b086bb1ce"
331+
, version = "6592f4188850ca4b2adab0c593c6a971087a54ba"
334332
}
335333
}
336334
in upstream // additions

spago-packages.nix

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

spago.dhall

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ You can edit this file as you like.
2727
, "monad-logger"
2828
, "mote"
2929
, "newtype"
30+
, "nullable"
3031
, "ordered-collections"
3132
, "parallel"
3233
, "partial"

src/Seabug/CallContract.purs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
module Seabug.CallContract
22
( callMarketPlaceBuy
3-
, callMarketPlaceListNft
43
, callMarketPlaceBuyTest
4+
, callMarketPlaceFetchNft
5+
, callMarketPlaceListNft
56
) where
67

78
import Contract.Prelude
@@ -16,12 +17,9 @@ import Contract.Monad
1617
, runContract_
1718
)
1819
import Contract.Numeric.Natural (toBigInt)
19-
import Contract.Prim.ByteArray
20-
( byteArrayToHex
21-
, hexToByteArray
22-
)
20+
import Contract.Prim.ByteArray (byteArrayToHex, hexToByteArray)
2321
import Contract.Transaction
24-
( TransactionInput(TransactionInput)
22+
( TransactionInput(..)
2523
, TransactionOutput(TransactionOutput)
2624
)
2725
import Contract.Value
@@ -38,19 +36,22 @@ import Control.Promise (Promise)
3836
import Control.Promise as Promise
3937
import Data.BigInt (BigInt)
4038
import Data.BigInt as BigInt
39+
import Data.Log.Level (LogLevel(..))
40+
import Data.Nullable (Nullable, notNull, null)
4141
import Data.Tuple.Nested ((/\))
4242
import Data.UInt as UInt
4343
import Effect (Effect)
4444
import Effect.Aff (error)
4545
import Effect.Class (liftEffect)
46-
import Data.Log.Level (LogLevel(..))
4746
import Effect.Exception (Error)
48-
import Seabug.Metadata.Types (SeabugMetadata(SeabugMetadata))
49-
import Seabug.Metadata.Share (unShare)
5047
import Partial.Unsafe (unsafePartial)
5148
import Plutus.Conversion (fromPlutusAddress)
49+
import Seabug.Contract.Common (NftResult)
5250
import Seabug.Contract.MarketPlaceBuy (marketplaceBuy)
53-
import Seabug.Contract.MarketPlaceListNft (ListNftResult, marketPlaceListNft)
51+
import Seabug.Contract.MarketPlaceFetchNft (marketPlaceFetchNft)
52+
import Seabug.Contract.MarketPlaceListNft (marketPlaceListNft)
53+
import Seabug.Metadata.Share (unShare)
54+
import Seabug.Metadata.Types (SeabugMetadata(SeabugMetadata))
5455
import Seabug.Types
5556
( NftCollection(NftCollection)
5657
, NftData(NftData)
@@ -63,14 +64,26 @@ import Serialization.Hash
6364
, scriptHashFromBech32
6465
, scriptHashToBech32Unsafe
6566
)
67+
import Types.BigNum as BigNum
6668
import Types.Natural as Nat
6769
import Wallet (mkNamiWalletAff)
68-
import Types.BigNum as BigNum
6970

7071
-- | Exists temporarily for testing purposes
7172
callMarketPlaceBuyTest :: String -> Effect (Promise String)
7273
callMarketPlaceBuyTest = Promise.fromAff <<< pure
7374

75+
callMarketPlaceFetchNft
76+
:: ContractConfiguration
77+
-> TransactionInputOut
78+
-> Effect (Promise (Nullable ListNftResultOut))
79+
callMarketPlaceFetchNft cfg args = Promise.fromAff do
80+
contractConfig <- buildContractConfig cfg
81+
txInput <- liftEffect $ liftEither $ buildTransactionInput args
82+
runContract contractConfig (marketPlaceFetchNft txInput) >>= case _ of
83+
Nothing -> pure null
84+
Just nftResult -> pure $ notNull $
85+
buildNftList (unwrap contractConfig).networkId nftResult
86+
7487
-- | Calls Seabugs marketplaceBuy and takes care of converting data types.
7588
-- Returns a JS promise holding no data.
7689
callMarketPlaceBuy
@@ -123,12 +136,14 @@ type BuyNftArgs =
123136
}
124137
}
125138

139+
type TransactionInputOut = { transactionId :: String, inputIndex :: Int }
140+
126141
-- Placeholder for types I'm not sure how should we represent on frontend.
127142
type ValueOut = Array
128143
{ currencySymbol :: String, tokenName :: String, amount :: BigInt }
129144

130145
type ListNftResultOut =
131-
{ input :: { transactionId :: String, inputIndex :: Int }
146+
{ input :: TransactionInputOut
132147
, output :: { address :: String, value :: ValueOut, dataHash :: String }
133148
, metadata ::
134149
{ seabugMetadata ::
@@ -193,7 +208,7 @@ stringToLogLevel "Warn" = Just Warn
193208
stringToLogLevel "Error" = Just Error
194209
stringToLogLevel _ = Nothing
195210

196-
buildNftList :: NetworkId -> ListNftResult -> ListNftResultOut
211+
buildNftList :: NetworkId -> NftResult -> ListNftResultOut
197212
buildNftList
198213
network
199214
{ input: TransactionInput input, output: TransactionOutput output, metadata } =
@@ -298,3 +313,13 @@ buildNftData { nftCollectionArgs, nftIdArgs } = do
298313
, daoScript
299314
, daoShare
300315
}
316+
317+
buildTransactionInput :: TransactionInputOut -> Either Error TransactionInput
318+
buildTransactionInput input = do
319+
transactionId <-
320+
note (error $ "Invalid transaction id: " <> input.transactionId)
321+
$ wrap
322+
<$> hexToByteArray input.transactionId
323+
index <- note (error $ "Invalid input index: " <> show input.inputIndex) $
324+
UInt.fromInt' input.inputIndex
325+
pure $ wrap { transactionId, index }

src/Seabug/Contract/Common.purs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Seabug.Contract.Common
2+
( NftResult
3+
) where
4+
5+
import Contract.Transaction (TransactionInput, TransactionOutput)
6+
import Seabug.Metadata (FullSeabugMetadata)
7+
8+
type NftResult =
9+
{ input :: TransactionInput
10+
, output :: TransactionOutput
11+
, metadata :: FullSeabugMetadata
12+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
-- | Contract to fetch a single NFT
2+
module Seabug.Contract.MarketPlaceFetchNft
3+
( marketPlaceFetchNft
4+
) where
5+
6+
import Contract.Prelude
7+
8+
import Contract.Monad (Contract, liftContractM, liftedE, liftedM, logWarn')
9+
import Contract.PlutusData (fromData, getDatumByHash)
10+
import Contract.Transaction (TransactionInput, TransactionOutput(..))
11+
import Contract.Utxos (getUtxo)
12+
import Control.Monad.Reader (asks)
13+
import Seabug.Contract.Common (NftResult)
14+
import Seabug.Metadata (getFullSeabugMetadataWithBackoff)
15+
import Seabug.Types (MarketplaceDatum(..))
16+
17+
-- | Fetch the info for a single NFT identified by a utxo
18+
-- | (`TransactionInput`). Returns `Nothing` if the given transaction
19+
-- | input has been spent (for example if the NFT has been bought).
20+
marketPlaceFetchNft
21+
:: forall (r :: Row Type)
22+
. TransactionInput
23+
-> Contract (projectId :: String | r) (Maybe NftResult)
24+
marketPlaceFetchNft ref = do
25+
getUtxo ref >>= case _ of
26+
Nothing -> do
27+
logWarn' "Could not find NFT utxo, it may have been spent"
28+
pure Nothing
29+
Just output@(TransactionOutput nftTxOut) -> do
30+
datumHash <- liftContractM "Datum hash not available for NFT"
31+
nftTxOut.dataHash
32+
MarketplaceDatum { getMarketplaceDatum: datum } <-
33+
liftedM "Could not get datum for NFT" $ getDatumByHash datumHash <#>
34+
(_ >>= unwrap >>> fromData)
35+
projectId <- asks $ unwrap >>> _.projectId
36+
metadata <- liftedE $ liftAff $
37+
getFullSeabugMetadataWithBackoff datum projectId
38+
pure $ Just { input: ref, output, metadata }

0 commit comments

Comments
 (0)