Skip to main content

Mô tả hoạt động

Bạn đã viết xong hợp đồng. Bây giờ là lúc chúng ta thực sự bắt đầu sử dụng framework của mình để xây dựng các giao dịch cho nó.

Framework là gì?

Framework là các đoạn code đã được viết sẵn, cấu thành nên một bộ khung và các thư viện lập trình được đóng gói. Chúng cung cấp các tính năng có sẵn như mô hình, API và các yếu tố khác để tối giản cho việc phát triển các ứng dụng web phong phú, năng động. Các framework giống như là chúng ta có khung nhà được làm sẵn nền móng cơ bản, bạn chỉ cần vào xây dựng và nội thất theo ý mình.

Framework cung cấp cho các nhà lập trình những chức năng cơ bản nhất. Ở đó các lập trình viên nhận được sự trợ giúp trong quá trình xây dựng và phát triển website, ứng dụng web của mình. Chúng ta có thể ví framework như tập các “Vật liệu” cho từng lĩnh vực dành cho các lập trình viên. Có framework các lập trình viên không cần phải đau đầu thiết kế trước khi dùng, điều này giúp họ tiết kiệm thời gian. Vì vậy các lập trình viên chỉ cần tìm hiểu và sáng tạo trên những framework để tạo ra sản phẩm theo mong muốn của mình.

Nguyên tắc chính cần hiểu ở đây là - chúng ta chỉ cần đưa ra những điều cần thiết, tức là chúng ta chỉ xác định những gì chúng ta muốn và framework sẽ thực hiện phần còn lại.

Chẳng hạn, chúng ta có thể nói rằng chúng ta muốn sử dụng đầu vào này thuộc địa chỉ của tập lệnh và tạo một số đầu ra. Do đó, nhiệm vụ của framework là thực hiện phần còn lại, giả sử:

  • Chọn UTxO có sẵn trong ví của người dùng và tạo đầu ra thay đổi phù hợp để cân bằng giao dịch có tính phí.
  • Đảm bảo rằng tất cả các UTxO được tạo đều đáp ứng yêu cầu ADA tối thiểu.
  • Xử lý tài sản thế chấp.
  • Vân vân...

Vì vậy, chúng ta chỉ xác định ở mức cao những gì chúng ta muốn. Điều này sẽ trở nên rõ ràng khi chúng ta thực sự bắt đầu viết các hoạt động cho hợp đồng của mình.

Toàn bộ mã cho các hoạt động này có sẵn ở đây.


Thao tác 1 : Tạo địa chỉ cho Hợp đồng thông minh

Tạo Trình xác thực cho Hợp đồng thông minh

Sau quá trình diễn tập thông thường, chúng ta tạo các tham số hợp đồng do Trình xác thực cung cấp (phần sau được ghi trong tệpCompiled.hs :

-- | Generates validator given params.
betRefValidator :: BetRefParams -> Validator
betRefValidator betRefParams = mkValidatorScript $
$$(PlutusTx.compile [|| mkBetRefValidator||]) `PlutusTx.applyCode` PlutusTx.liftCode betRefParams

Những gì chúng ta đã thu được là kiểu Validator được xác định trong plutus-ledger-api, không là gì ngoài một trình bao bọc xung quanh kiểu Script được định nghĩa tương tự.

Tương tự như vậy, chúng ta có các kiểu của riêng mình, GYValidator (tương tự GYMintingPolicy để đúc các tập lệnh chính sách) & GYScript (được định nghĩa trong Script.hs) để đại diện cho những điều này trong framework của chúng ta.

Các tập tin được đề cập Script.hs chứa rất nhiều tiện ích trợ giúp, chẳng hạn như loại validatorFromPlutus của Plutus Validator để đưa ra GYValidator. Mặc dù đã có một chút lạm dụng khi đề cập đến kiểu ở đây vì những gì thực sự được đưa ra là GYValidator v biến kiểu v thuộc loại PlutusVersion được định nghĩa trong tệp PlutusVersion.hs mà bạn có thể hiểu là ở đây để biểu thị phiên bản plutus cho tập lệnh trình xác nhận của chúng ta 1 .

Nếu chúng ta nhìn vào chữ ký kiểu của validatorFromPlutus, chúng ta sẽ thấy: validatorFromPlutus :: forall v. SingPlutusVersionI v => Plutus.Validator -> GYValidator v tạm thời chúng ta có thể bỏ qua mô tả của kiểu SingPlutusVersionI (Xem thêm Chú thích 1) bên cạnh việc lưu ý thực tế là chỉ các kiểu (hiện tại 'PlutusV1 & 'PlutusV2) PlutusVersion mới có một thể hiện cho nó. Vì vậy, ở đây, chức năng của chúng ta validatorFromPlutus hoạt động cho tất cả các biến loại v có một phiên bản SingPlutusVersionI nhưng không có cách nào để tìm hiểu cái gì v chỉ dựa trên đầu vào Plutus.Validator và do đó, người gọi phải chỉ định nó, bằng cách cung cấp chữ ký loại (của callee hoặc người gọi do loại suy luận) hoặc bằng cách sử dụng ứng dụng loại hiển thị. Hoạt động lần đầu của chúng ta sử dụng nó nhưng trước khi xem xét nó, chúng ta cần hiểu về GYTxQueryMonad.

Tham khảo - GYTxQueryMonad

Khi chúng ta muốn lấy địa chỉ của tập lệnh từ hàm băm của nó, ngoài hàm băm, chúng ta cũng cần biết mạng mà chúng ta hiện đang hoạt động. Đó là một số testnet hay mainnet?

Tương tự, việc xây dựng giao dịch liên quan đến việc truy vấn sổ cái để biết nhiều thông tin khác nhau, chẳng hạn như truy vấn UTxO có mặt tại địa chỉ của một người, tương tự, nó có thể cần sự trợ giúp của một số trình chỉ mục chuỗi để truy vấn Datum trong trường hợp đầu ra chỉ chứa hàm băm của Datum.

Tất cả điều này được nắm bắt bởi typeclass GYTxQueryMonad định nghĩa ở đây và cũng được hiển thị bên dưới (vui lòng xem tất cả các chức năng được định nghĩa cho kiểu chữ này).


-- | Class of monads for querying chain data.
class MonadError GYTxMonadException m => GYTxQueryMonad m where
{-# MINIMAL networkId, lookupDatum, (utxoAtTxOutRef | utxosAtTxOutRefs), (utxosAtAddress | utxosAtAddresses), slotConfig, currentSlot, logMsg #-}

-- | Get the network id
networkId :: m GYNetworkId

-- | Lookup datum by its hash.
lookupDatum :: GYDatumHash -> m (Maybe GYDatum)

-- | Lookup 'GYUTxO' at 'GYTxOutRef'.
--
utxoAtTxOutRef :: GYTxOutRef -> m (Maybe GYUTxO)
utxoAtTxOutRef ref = do
utxos <- utxosAtTxOutRefs [ref]
return $ case utxosToList utxos of
[] -> Nothing
utxo : _ -> Just utxo

-- | Lookup 'GYUTxOs' at multiple 'GYTxOutRef's at once
utxosAtTxOutRefs :: [GYTxOutRef] -> m GYUTxOs
utxosAtTxOutRefs orefs = utxosFromList <$> wither utxoAtTxOutRef orefs

-- | Lookup 'GYUTxOs' at 'GYAddress'.
utxosAtAddress :: GYAddress -> m GYUTxOs
utxosAtAddress = utxosAtAddresses . return

-- | Lookup 'GYUTxOs' at zero or more 'GYAddress'.
utxosAtAddresses :: [GYAddress] -> m GYUTxOs
utxosAtAddresses = foldM f mempty
where
f :: GYUTxOs -> GYAddress -> m GYUTxOs
f utxos addr = (<> utxos) <$> utxosAtAddress addr

-- | Lookup the `[GYTxOutRef]`s at a `GYAddress`
utxoRefsAtAddress :: GYAddress -> m [GYTxOutRef]
utxoRefsAtAddress = fmap (Map.keys . mapUTxOs id) . utxosAtAddress

{- | Obtain the slot config for the network.

Implementations using era history to create slot config may raise 'GYEraSummariesToSlotConfigError'.
-}
slotConfig :: m GYSlotConfig

-- | Lookup the current 'GYSlot'.
currentSlot :: m GYSlot

-- | Log a message with specified namespace and severity.
logMsg :: HasCallStack => GYLogNamespace -> GYLogSeverity -> String -> m ()

Vì vậy, nếu chúng ta đang làm việc bên trong một monad tình cờ cũng cung cấp một thể hiện cho nó, thì chúng ta sẽ rất vui khi có thể truy vấn thông tin như vậy.

Tạo địa chỉ

Trong thao tác này, chúng ta chỉ cần lấy thông tin chi tiết về mạng với sự trợ giúp của monad này. Đây là mã để lấy địa chỉ (lưu ý rằng chúng ta đã cung cấp nhiều phiên bản của cùng một mã tại đây) :

note

Loại scriptAddress được sử dụng bên dưới (& được định nghĩa trongClass.hs) là scriptAddress :: forall (m :: * -> *) (v :: PlutusVersion). GYTxQueryMonad m => GYValidator v -> m GYAddress. Do đó, đối với ứng dụng loại, tham số lần đầu dành cho monad và tham số thứ hai là PlutusVersion loại.

Nội bộ chức năng này truy vấn chi tiết mạng.

-- A. Type is given by `scriptAddress`.

-- | Validator in question, obtained after giving required parameters.
betRefValidator' :: SingPlutusVersionI v => BetRefParams -> GYValidator v
betRefValidator' brp = validatorFromPlutus $ betRefValidator brp

-- | Address of the validator, given params.
betRefAddress :: (HasCallStack, GYTxQueryMonad m) => BetRefParams -> m GYAddress
betRefAddress brp = scriptAddress @_ @'PlutusV2 $ betRefValidator' brp

Chà, monad m này đang được sử dụng ở đây là gì? Vâng bất kỳ! Miễn là nó có một phiên bản cho GYTxQueryMonad. Khi chúng ta bắt đầu viết bài kiểm tra, thì chúng ta sẽ sử dụng tất cả các thao tác này và rất có thể cách sử dụng chúng sẽ trở nên rõ ràng sau đó.


Thao tác 2 : Thêm input để tham chiếu sau (Reference Input)

Tham khảo - GYTxSkeleton

Như đã đề cập trước đây, chúng ta chỉ đề cập ở cấp độ cao những gì chúng ta muốn trong một giao dịch. Điều này được ghi lại bằng cách GYTxSkeleton xác định tại đây và mô tả của nó được đề cập dưới đây.

Lĩnh vựcĐại diện bởichi tiết bổ sung
InputsgytxInsĐó là danh sách các đầu vào trong đó đối với mỗi đầu vào, chúng ta có tham chiếu UTxO của nó ("TxIn" là thông số sổ cái cardano gọi nó) và một nhân chứng. Trong trường hợp UTxO này không thuộc tập lệnh, chúng ta chỉ cần sử dụng nhân chứng chính, nếu không, chúng ta cần tập lệnh được liên kết, cơ sở Datum và trình mua lại đầu vào của nó trong đó tập lệnh được liên kết có thể được cung cấp như một phần của nội dung giao dịch này hoặc có thể được lấy từ đầu vào tham chiếu. Nhìn thấyTxIn.hs.
OutputsgytxOutsDanh sách các đầu ra được tạo bởi giao dịch này, trong đó đối với mỗi đầu ra, chúng ta có thể đề cập liệu Datum có được nội tuyến hay không và liệu đầu ra này có lưu trữ bất kỳ tập lệnh nào hay không. Nhìn thấyTxOut.hs.
Reference InputsgytxRefInsBộ tham chiếu đến UTxO tương ứng với đầu vào tham chiếu. Được xác định trong cùng một tệp, viz.Class.hs.
MintsgytxMintBản đồ của chính sách đúc cho bộ người đổi quà và một bản đồ khác cho tên mã thông báo để đúc số tiền cho mã thông báo đó.
SignatoriesgytxSigsTập hợp Hash khóa công khai của người ký.
Có hiệu lực saugytxInvalidBeforeSlot trước đó giao dịch hợp lệ.
Có hiệu lực trướcgytxInvalidAfterSlot sau đó giao dịch có hiệu lực.

Đoạn mã haskell tương ứng:

data GYTxSkeleton (v :: PlutusVersion) = GYTxSkeleton
{ gytxIns :: ![GYTxIn v]
, gytxOuts :: ![GYTxOut v]
, gytxRefIns :: !(GYTxSkeletonRefIns v)
, gytxMint :: !(Map (Some GYMintingPolicy) (Map GYTokenName Integer, GYRedeemer))
, gytxSigs :: !(Set GYPubKeyHash)
, gytxInvalidBefore :: !(Maybe GYSlot)
, gytxInvalidAfter :: !(Maybe GYSlot)
} deriving Show

Khi xây dựng giao dịch, chúng ta chỉ cần xác định những gì chúng ta muốn trong khung này.

Phần này tự nhiên có một thể hiện monoid trong đó hai phần được kết hợp bằng cách chạy mappend trên từng trường của chúng. Chúng ta có các chức năng tiện ích được xác định trong cùng một tệp như Class.hs (lưu ý rằng có các chức năng hữu ích khác được xác định trong cùng một tệp và nói chung sẽ hữu ích khi xem qua chúng) :

mustHaveOutput :: GYTxOut v -> GYTxSkeleton v
mustHaveOutput o = emptyGYTxSkeleton {gytxOuts = [o]}

mustHaveInput :: GYTxIn v -> GYTxSkeleton v
mustHaveInput i = emptyGYTxSkeleton {gytxIns = [i]}

mustHaveRefInput :: VersionIsGreaterOrEqual v PlutusV2 => GYTxOutRef -> GYTxSkeleton v
mustHaveRefInput i = emptyGYTxSkeleton { gytxRefIns = GYTxSkeletonRefIns (Set.singleton i) }

mustMint :: GYMintingPolicy u -> GYRedeemer -> GYTokenName -> Integer -> GYTxSkeleton v
mustMint p r tn n = emptyGYTxSkeleton {gytxMint = Map.singleton (Some p) (Map.singleton tn n, r)}

mustBeSignedBy :: GYPubKeyHash -> GYTxSkeleton v
mustBeSignedBy pkh = emptyGYTxSkeleton {gytxSigs = Set.singleton pkh}

isInvalidBefore :: GYSlot -> GYTxSkeleton v
isInvalidBefore s = emptyGYTxSkeleton {gytxInvalidBefore = Just s}

isInvalidAfter :: GYSlot -> GYTxSkeleton v
isInvalidAfter s = emptyGYTxSkeleton {gytxInvalidAfter = Just s}

Vì vậy, chúng ta có thể chỉ định rằng giao dịch của chúng ta phải có đầu ra này (sử dụng mustHaveOutput) và đầu ra đó và phải có đầu vào này (sử dụng mustHaveInput), v.v.... và kết hợp tất cả chúng thành một khung duy nhất bằng cách sử dụng mappend.

Bộ khung để thêm đầu vào tham chiếu (reference input)

Ở đây, chúng ta muốn tạo một đầu ra tại một địa chỉ nhất định (địa chỉ của Oracle) với mốc thời gian đã cho. UTxO này sau này sẽ được sử dụng làm đầu vào tham chiếu theo tập lệnh trong đó tập lệnh sẽ tham chiếu đến mốc thời gian của nó. Ở đây, chúng ta đã quyết định giữ nội tuyến Datum này vì khung hiện tại không hỗ trợ đọc Datum chuẩn cho đầu vào tham chiếu có đầu ra chỉ chứa hàm băm Datum.

note

Tuy nhiên, điều này không đúng với các đầu vào thông thường, nơi bạn có thể chỉ định Datum chuẩn như chúng ta sẽ thấy trong các hoạt động khác.

-- | Add UTxO to be used as reference input at a given address with given datum.
addRefInput :: GYAddress -> OracleAnswerDatum -> GYTxSkeleton 'PlutusV2
addRefInput addr dat =
mustHaveOutput $ GYTxOut addr mempty (Just (datumFromPlutusData dat, GYTxOutUseInlineDatum)) Nothing
-- Note that the value can be empty as tx building logic would add the needed minimum UTxO ada.

Lưu ý rằng chúng ta đã đề cập đến giá trị là trống cho UTxO này và đây là một trong những điểm hay của khung của chúng ta rằng nó sẽ tự quản lý việc thêm dây buộc tình yêu để đáp ứng yêu cầu ada tối thiểu.

Bạn có thể tạo khung để thêm tập lệnh tham chiếu không?

Với địa chỉ đầu ra và trình xác thực Plutus V2 , chúng ta có thể viết addr::GYAddress``script::GYValidator'PlutusV2``mustHaveOutput $ GYTxOut addr mempty (Just (datumFromPlutusData (), GYTxOutDontUseInlineDatum)) (Just $ validatorToScript script)


Thao tác 3 : Đặt cược

Đặt cược lần đầu

Trong trường hợp đây là lần đặt cược lần đầu (một chương trình xử lý các cược có thể quyết định xem người dùng đặt cược có phải là lần lần đầu hay không bằng cách truy vấn các UTxO tại địa chỉ tập lệnh), thì chúng ta chỉ cần tạo một đầu ra tại địa chỉ tập lệnh với giá trị đặt cược và dự đoán của chúng ta.

-- | Operation to place bet.
placeBet :: (HasCallStack, GYTxMonad m)
=> GYTxOutRef -- ^ Reference Script.
-> BetRefParams -- ^ Validator Params.
-> OracleAnswerDatum -- ^ Guess.
-> GYValue -- ^ Bet amount to place.
-> GYAddress -- ^ Own address.
-> Maybe GYTxOutRef -- ^ Reference to previous bets UTxO (if any).
-> m (GYTxSkeleton PlutusV2)
placeBet refScript brp guess bet ownAddr mPreviousBetsUtxoRef = do
pkh <- addressToPubKeyHash' ownAddr
betAddr <- betRefAddress brp
case mPreviousBetsUtxoRef of
-- This is the first bet.
Nothing -> do
return $ mustHaveOutput $ GYTxOut
{ gyTxOutAddress = betAddr
, gyTxOutValue = bet
, gyTxOutDatum = Just (datumFromPlutusData $ BetRefDatum [(pubKeyHashToPlutus pkh, guess)] (valueToPlutus bet), GYTxOutDontUseInlineDatum)
, gyTxOutRefS = Nothing
}

Tại thời điểm này, cần hiểu rõ điều gì đang xảy ra trong khối mã trên. Chức năng này hơi quá tải và đang xử lý cả hai trường hợp đặt cược trước hay không và nó xác định điều này bằng cách sử dụng sự hiện diện của tham chiếu đến UTxO (đại diện cho các lần đặt cược trước đó) tại tập lệnh trình xác thực. Trong trường hợp không có, tức là Nothing đối với Maybe giá trị của chúng ta, chúng ta sẽ đặt cược lần đầu. Lưu ý rằng chúng ta đề cập rằng Datum của chúng ta không nên được đưa vào đầu ra bằng cách sử dụng GYTxOutDontUseInlineDatum.

Đặt cược tiếp theo

Ở đây, lần lần đầu chúng ta sẽ thực hiện logic của kịch bản. Chúng ta sẽ sử dụng UTxO có tại địa chỉ tập lệnh. Chúng ta đã xác định một chức năng, viz. input sẽ nhận các tham số sau:

  • BetRefParams : để tạo tập lệnh trình xác thực hoặc nếu không, chúng ta có thể đọc tập lệnh từ UTxO liên quan đến tập lệnh tham chiếu.
  • Tham chiếu đến tập lệnh tham chiếu UTxO.
  • Tham chiếu đầu vào tập lệnh để sử dụng.
  • Datum hiện tại ở đầu vào này. Hãy nhớ lại rằng mốc thời gian của chúng ta không được nội tuyến cho đầu ra cụ thể này, do đó chúng ta sẽ cần tra cứu mốc bằng cách sử dụng lookupDatum để chuyển mốc thực tế cho hàm này.
  • Hành động cứu chuộc.

Vì vậy, chúng ta có định nghĩa của nó là:

-- | Utility function to consume script UTxO.
input :: BetRefParams -> GYTxOutRef -> GYTxOutRef -> BetRefDatum -> BetRefAction -> GYTxSkeleton 'PlutusV2
input brp refScript inputRef dat red =
mustHaveInput GYTxIn
{ gyTxInTxOutRef = inputRef
, gyTxInWitness = GYTxInWitnessScript
(GYInReference refScript $ validatorToScript $ betRefValidator' brp)
(datumFromPlutusData dat)
(redeemerFromPlutusData red)
}
note

Trong trường hợp chúng ta không muốn sử dụng tập lệnh tham chiếu, chúng ta sẽ viết gyTxInWitness như sau:

gyTxInWitness  = GYTxInWitnessScript
(GYInScript (validatorToScript $ betRefValidator' brp))
(datumFromPlutusData dat)
(redeemerFromPlutusData red)

Sau đây là mã hoàn chỉnh để xử lý trường hợp này. Vài bình luận để tạo điều kiện cho sự hiểu biết của nó:

  • Trước tiên, chúng ta truy vấn UTxO tương ứng với các lần đặt cược trước đó tại địa chỉ tập lệnh và sau đó chúng ta truy vấn Datum của nó bằng cách sử dụng utxoDatum' Datum cố gắng hết sức để truy xuất Datum và đưa ra một ngoại lệ trong trường hợp không thành công. Đây là chữ ký của nó: utxoDatum' :: (GYTxQueryMonad m, Plutus.FromData a) => GYUTxO -> m (GYAddress, GYValue, a) .
  • Lưu ý : utxoAtTxOutRef' (được xác định lại trongClass.hs) là một trình bao bọc xung quanh utxoAtTxOutRef sẽ đưa ra một ngoại lệ trong trường hợp kết quả là Nothing.
  • Sau đó, chúng ta thấy việc sử dụng gyLogDebug' which như bạn mong đợi là dành cho mục đích ghi nhật ký. Đối số lần đầu mà nó nhận tương ứng với không gian tên được sử dụng bởiKatip. Đây là nơi tích hợp mã ngoài chuỗi và mã trên chuỗi thực sự bắt đầu tỏa sáng ✨, việc xác Show định phiên bản cho một số loại trên chuỗi của chúng ta cho phép chúng ta ghi nhật ký chúng.
  • timeFromPlutus như bạn mong đợi - cung cấp cho chúng ta biểu diễn thời gian của khung từ biểu diễn thời gian của plutus. Và enclosingSlotFromTime' sử dụng thông tin của sổ cái để xác định vị trí tương ứng trong thời gian nhất định. Chúng ta cần điều này vì nút của cardano hoạt động trong các vị trí. Chúng ta đề cập rằng giao dịch của chúng ta sẽ không hợp lệ sau thời điểm này bằng cách sử dụng isInvalidAfter.
  • Chúng ta đề cập rằng giao dịch của chúng ta phải có hàm băm khóa công khai của chúng ta với tư cách là bên ký kết khi hợp đồng thông minh plutus yêu cầu sử dụng mustBeSignedBy
  • Cuối cùng, giao dịch này phải tạo đầu ra cho địa chỉ của tập lệnh với giá trị gia tăng và Datum được cập nhật.
  • valueToPlutus cung cấp loại giá trị tương ứng được sử dụng bởi plutus từ những gì chúng ta có trong khung của chúng ta (viz., GYValue).

Tất cả các bộ xương này được kết hợp với nhau bằng cách sử dụng mappend định nghĩa cho GYTxSkeleton.

    -- Need to append to previous.
Just previousBetsUtxoRef -> do
previousUtxo <- utxoAtTxOutRef' previousBetsUtxoRef
(_addr, previousValue, dat@(BetRefDatum previousGuesses _previousBet)) <- utxoDatum' previousUtxo
gyLogDebug' "" $ printf "previous guesses %s" (show previousGuesses)
betUntilSlot <- enclosingSlotFromTime' (timeFromPlutus $ brpBetUntil brp)
gyLogDebug' "" $ printf "bet until slot %s" (show betUntilSlot)
return $
input brp refScript previousBetsUtxoRef dat (Bet guess)
<> mustHaveOutput GYTxOut
{ gyTxOutAddress = betAddr
, gyTxOutValue = bet <> previousValue
, gyTxOutDatum = Just (datumFromPlutusData $ BetRefDatum ((pubKeyHashToPlutus pkh, guess) : previousGuesses) (valueToPlutus bet), GYTxOutDontUseInlineDatum)
, gyTxOutRefS = Nothing
}
<> isInvalidAfter betUntilSlot
<> mustBeSignedBy pkh

Thao tác 4: Lấy bet pot

Tại thời điểm này, việc đọc đoạn mã sau sẽ có ý nghĩa vì nó tương tự như những gì chúng ta đã làm trước đây. Ở đây lưu ý rằng chúng ta đang sử dụng mustHaveRefInput để thông báo rằng giao dịch phải có tham chiếu UTxO sau làm đầu vào tham chiếu.

note

Lưu ý rằng chúng ta không cần chỉ định rằng giá trị mà chúng ta sử dụng thành công từ UTxO của tập lệnh phải đến tay chúng ta vì bộ cân bằng giao dịch sẽ thêm đầu ra thay đổi cho chúng ta.

-- | Operation to take UTxO corresponding to previous bets.
takeBets :: (HasCallStack, GYTxMonad m)
=> GYTxOutRef -- ^ Reference Script.
-> BetRefParams -- ^ Validator params.
-> GYTxOutRef -- ^ Script UTxO to consume.
-> GYAddress -- ^ Own address.
-> GYTxOutRef -- ^ Oracle reference input.
-> m (GYTxSkeleton PlutusV2)
takeBets refScript brp previousBetsUtxoRef ownAddr oracleRefInput = do
pkh <- addressToPubKeyHash' ownAddr
previousUtxo <- utxoAtTxOutRef' previousBetsUtxoRef
(_addr, _previousValue, dat) <- utxoDatum' previousUtxo
betRevealSlot <- enclosingSlotFromTime' (timeFromPlutus $ brpBetReveal brp)
return $
input brp refScript previousBetsUtxoRef dat Take
<> isInvalidBefore betRevealSlot
<> mustHaveRefInput oracleRefInput
<> mustBeSignedBy pkh

Chú thích

  1. Điều này có liên quan đến singletons và người ta có thể đọc về nó từ chương "Các kiểu phụ thuộc" (chương cuối cùng) trong sách Thinking with Types.

Nguồn bài viết tại đây


Picture