Skip to content

Commit

Permalink
Merge pull request #15 from SCMusson/minting_tests
Browse files Browse the repository at this point in the history
Minting tests (WIP)
  • Loading branch information
SCMusson authored Oct 17, 2024
2 parents 4809cc0 + bff1b6d commit 1d81955
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 2 deletions.
2 changes: 1 addition & 1 deletion plutus_bench/tx_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ def generate_script_contexts_resolved(
for r in tx.transaction_witness_set.redeemer
if r.index == i and r.tag == RedeemerTag.MINT
),
tx.transaction_witness_set,
tx.transaction_witness_set.redeemer,
)
except StopIteration:
raise ValueError(
Expand Down
3 changes: 2 additions & 1 deletion tests/build_contracts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
DIR=$(dirname "${BASH_SOURCE[0]}")
cd $DIR

poetry run opshin build spending contracts/gift.py
poetry run opshin build spending contracts/gift.py
poetry run opshin build minting contracts/signed_mint.py
19 changes: 19 additions & 0 deletions tests/contracts/signed_mint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from opshin.prelude import *


def assert_minting_purpose(context: ScriptContext) -> None:
purpose = context.purpose
if isinstance(purpose, Minting):
is_minting = True
else:
is_minting = False
assert is_minting, "not minting purpose"


def assert_signed(pkh: PubKeyHash, context: ScriptContext) -> None:
assert pkh in context.tx_info.signatories, "missing signature"


def validator(pkh: PubKeyHash, redeemer: None, context: ScriptContext) -> None:
assert_minting_purpose(context)
assert_signed(pkh, context)
79 changes: 79 additions & 0 deletions tests/mint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import pathlib
from opshin import build
import cbor2
import pycardano
from pycardano import ChainContext
from plutus_bench.tool import load_contract, ScriptType, address_from_script

own_path = pathlib.Path(__file__)


def mint_coin_with_contract(
token_name: str,
amount: int,
issuer_signing_key: pycardano.PaymentSigningKey,
required_key: pycardano.PaymentVerificationKey,
context: ChainContext,
):
network = context.network

tn_bytes = bytes(token_name, encoding="utf-8")

VerificationKey = pycardano.PaymentVerificationKey.from_signing_key(
issuer_signing_key
)
payment_address = pycardano.Address(
payment_part=VerificationKey.hash(), network=network
)

# get input utxo
utxo_to_spend_or_burn = None
if amount > 0:
for utxo in context.utxos(payment_address):
if utxo.output.amount.coin > 3_000_000:
utxo_to_spend_or_burn = utxo
break
else:

def f(pi: pycardano.ScriptHash, an: pycardano.AssetName, a: int) -> bool:
return pi == script_hash and an.payload == tn_bytes and a >= -amount

for utxo in context.utxos(payment_address):
if utxo.output.amount.multi_asset.count(f):
utxo_to_spend_or_burn = utxo
assert utxo_to_spend_or_burn is not None, "UTxO not found to spend!"

# Build script
mint_script_path = own_path.parent / "contracts" / "signed_mint.py"
pkh = required_key.hash()
plutus_script = build(mint_script_path, pkh)

script_hash = pycardano.plutus_script_hash(plutus_script)

# Build the transaction
builder = pycardano.TransactionBuilder(context)
builder.add_minting_script(script=plutus_script, redeemer=pycardano.Redeemer(0))
builder.mint = pycardano.MultiAsset.from_primitive(
{bytes(script_hash): {tn_bytes: amount}}
)
builder.add_input(utxo_to_spend_or_burn)
if amount > 0:
# if not burning
builder.add_output(
pycardano.TransactionOutput(
payment_address,
amount=pycardano.Value(coin=amount, multi_asset=builder.mint),
)
)
# builder.required_signers = [VerificationKey,]

# sign the transation
signed_tx = builder.build_and_sign(
signing_keys=[
issuer_signing_key,
],
change_address=payment_address,
auto_required_signers=True,
)

context.submit_tx(signed_tx)
51 changes: 51 additions & 0 deletions tests/test_mint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import pathlib

import pycardano
import pytest
from pycardano import TransactionFailedException

from plutus_bench import MockChainContext, MockUser
from plutus_bench.mock import MockFrostApi

from tests.mint import mint_coin_with_contract
from plutus_bench.tool import address_from_script, load_contract, ScriptType

own_path = pathlib.Path(__file__)


def test_mint_contract():
api = MockFrostApi()
context = MockChainContext(api=api)
minting_user = MockUser(api)
minting_user.fund(100_000_000)

mint_coin_with_contract(
"My_token",
100,
minting_user.signing_key,
minting_user.verification_key,
context,
)


def test_wrong_signature_mint_contract():
api = MockFrostApi()
context = MockChainContext(api=api)
minting_user = MockUser(api)
minting_user.fund(100_000_000)

other_user = MockUser(api)
pytest.raises(
TransactionFailedException,
mint_coin_with_contract,
"My_token",
100,
minting_user.signing_key,
other_user.verification_key,
context,
)


if __name__ == "__main__":
test_mint_contract()
test_wrong_signature_mint_contract()
74 changes: 74 additions & 0 deletions tests/test_mint_mockfrost.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import pathlib
from multiprocessing import Process
from time import sleep

import pycardano
import pytest
import uvicorn
from pycardano import TransactionFailedException
from starlette.testclient import TestClient

from plutus_bench import MockChainContext, MockUser
from plutus_bench.mock import MockFrostApi

from tests.mint import mint_coin_with_contract
from plutus_bench.tool import address_from_script, load_contract, ScriptType
from plutus_bench.mockfrost.client import MockFrostClient, MockFrostUser
from plutus_bench.mockfrost.server import app

own_path = pathlib.Path(__file__)


def run_server():
uvicorn.run(app, port=8000)


@pytest.fixture
def server():
proc = Process(target=run_server, args=(), daemon=True)
proc.start()
sleep(1) # Wait for server to start
yield
proc.kill() # Cleanup after test


def test_mint_contract(server):
client = MockFrostClient(base_url="http://127.0.0.1:8000")
session = client.create_session()
context = session.chain_context()
minting_user = MockFrostUser(session)
minting_user.fund(100_000_000)

mint_coin_with_contract(
"My_token",
100,
minting_user.signing_key,
minting_user.verification_key,
context,
)


def test_wrong_signature_mint_contract(server):
client = MockFrostClient(base_url="http://127.0.0.1:8000")
session = client.create_session()
context = session.chain_context()
minting_user = MockFrostUser(session)
minting_user.fund(100_000_000)

other_user = MockFrostUser(session)

pytest.raises(
TransactionFailedException,
mint_coin_with_contract,
"My_token",
100,
minting_user.signing_key,
other_user.verification_key,
context,
)


if __name__ == "__main__":
test_mint_contract()
# test_spend_from_gift_contract()
# test_other_user_spend_from_gift_contract()

0 comments on commit 1d81955

Please sign in to comment.