I am trying to make a Plutus smart contract which takes tokens locked to the contract and then on endpoint call (purchase) sends 1 to the caller and then the rest back to the contract. I cant find a distribution model for this I would assume you would have to create a new utxo out of the existing utxo and reduce it down into a single token on the script but I am very lost with this process.

I need help figuring this out so that I can create this send 1 token out of many script. A specific answer is what I'm looking for.

This is the code relevant to the problem, but it currently does not work.

purchaseUtxo :: ChainIndexTxOut
purchaseUtxo = case fromTxOut (scriptTxOut (Value.singleton (policyID contractInfo) (nameOfToken contractInfo) (1)) validate (Datum $ PlutusTx.toBuiltinData ()) )  of
    Nothing     ->  error ()
    Just x      ->  x

purchase ::  AsContractError e => PurchaseParams -> Contract w s e ()
purchase p=  do
    utxos <- fundsAtAddressGeq valAddress (Ada.lovelaceValueOf 1)
    let utxoMap = Map.singleton (TxOutRef (_citxTxId ChainIndexTx) 1) purchaseUtxo
        redeemer = ()
        pkh = ownPubKey
        tx       = Constraints.mustPayToTheScript () price <> collectFromScript utxoMap redeemer
    void (submitTxConstraintsSpending lootBox utxos tx)

And here is the error:

Compilation Error, Line 148, Column 54 (jump)

• Couldn't match expected type ‘ChainIndexTx’
with actual type ‘TxId
-> Data.Set.Internal.Set TxIn
-> ChainIndexTxOutputs
-> SlotRange
-> Map DatumHash Datum
-> Map RedeemerHash Redeemer
-> Map ScriptHash Script
-> Maybe SomeCardanoApiTx
-> ChainIndexTx’
• Probable cause: ‘ChainIndexTx’ is applied to too few arguments
In the first argument of ‘_citxTxId’, namely ‘ChainIndexTx’
In the first argument of ‘TxOutRef’, namely
‘(_citxTxId ChainIndexTx)’
In the first argument of ‘Map.singleton’, namely
‘(TxOutRef (_citxTxId ChainIndexTx) 1)’
| 148 | let utxoMap = Map.singleton (TxOutRef (_citxTxId ChainIndexTx) 1) purchaseUtxo
| ^^^^^^^^^^^^

2 Answers 2


on endpoint call sends 1 to the caller and then the rest back to the contract

Remember, the on-chain portion of a contract doesn't do anything actively, it only validates transactions. So a more accurate way to phrase this would be, "the script only validates transactions that spend 1 ADA and return the rest to the script."

I think everything you need to write a validator you could find in the auction code. Notice that it stores the current bid amount in the datum and that datum is attached to the actual UTxO with the value.

    ownOutput   :: TxOut
    outputDatum :: AuctionDatum
    (ownOutput, outputDatum) = case getContinuingOutputs ctx of
        [o] -> case txOutDatumHash o of
            Nothing   -> traceError "wrong output type"
            Just h -> case findDatum h info of
                Nothing        -> traceError "datum not found"
                Just (Datum d) ->  case PlutusTx.fromData d of
                    Just ad' -> (o, ad')
                    Nothing  -> traceError "error decoding data"
        _   -> traceError "expected exactly one continuing output"

    correctBidOutputDatum :: Bid -> Bool
    correctBidOutputDatum b = (adAuction outputDatum == auction)   &&
                              (adHighestBid outputDatum == Just b)

    correctBidOutputValue :: Integer -> Bool
    correctBidOutputValue amount =
        txOutValue ownOutput == tokenValue Plutus.<> Ada.lovelaceValueOf amount

If instead of the close endpoint, you have a take distributions endpoint, you could just do a similar check that the datum was updated and the value wasn't decremented by more than 1.

At that point, it is up to the caller to build a transaction in their own benefit. Again, the off-chain code in the above auction example could be adapted to build a transaction to claim distributions.

  • 1
    Thanks ill try this method
    – Floof99
    Jan 25, 2022 at 2:07
  • Did you have any luck? Feb 1, 2022 at 19:14
  • 1
    yes I think I understand it better now thank you
    – Floof99
    Feb 2, 2022 at 22:48

On casual search I think what you need is Ledger.TxConstraint:


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.