Skip to content

Commit

Permalink
Implement NFT functionality (#242)
Browse files Browse the repository at this point in the history
* esdt system sc initial implementation

* add runtime json files

* legacy async calls

* implement NFTs

* add tests

* Set Version: 0.1.41

* format

* Makefile: build esdt system sc mock before basic features tests

* delete `managedVerifyEd25519`

* add comment about tx hash in Mandos

* complete `getESDTLocalRoles` implementation

* mandos: set/check NFTs

* remove unused parameter

* mandos: increment nonce in transferTx

* update simple tests

* last nonce

* fix return code argument for callback

* fix last transfer and callback esdt transfers

* multisig add sendEsdt test

* cleanup

* ESDTNFTTransfer builtin

* add more composability tests

* format

* Set Version: 0.1.44

* Update Makefile

* fix makefile

* Set Version: 0.1.45

* composability_contracts: add forwarder

* transfer NFT: FROM == TO

* add proxy-test-second

* add recursive-caller

* fix `mandos_to_esdt_metadata`

* implement nft add uri

* implement `getCurrentESDTNFTNonce` host function

* fix unused variable warning

* add default value 0 for empty string nonce

* fixes after review

---------

Co-authored-by: devops <devops@runtimeverification.com>
bbyalcinkaya and devops authored Apr 30, 2024
1 parent ab6e536 commit 17f0b02
Showing 39 changed files with 6,439 additions and 148 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test-pr.yml
Original file line number Diff line number Diff line change
@@ -79,6 +79,8 @@ jobs:
run: docker exec -t elrond-semantics-ci-${GITHUB_SHA} make test-elrond-crowdfunding-esdt
- name: 'Contract Test: Multisig'
run: docker exec -t elrond-semantics-ci-${GITHUB_SHA} make test-elrond-multisig
- name: 'Contract Test: NFT Minter'
run: docker exec -t elrond-semantics-ci-${GITHUB_SHA} make test-elrond-nft-minter
- name: 'Contract Tests: Custom'
run: docker exec -t elrond-semantics-ci-${GITHUB_SHA} make test-custom-contracts
- name: 'Tear down Docker'
52 changes: 38 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
test-elrond-multisig test-elrond-basic-features \
test-elrond-alloc-features test-elrond-composability-features \
test-elrond-addercaller test-elrond-callercallee test-custom-contracts \
rule-coverage clean-coverage \
rule-coverage clean-coverage runtime-json test-elrond-nft-minter \


# Settings
@@ -50,6 +50,18 @@ build-all: kmultiversx
.PHONY: clean
clean: kmultiversx
$(POETRY) run kdist clean
$(MAKE) -C $(PLUGIN_SUBMODULE) clean

# Runtime
# -------

ESDT_SYSTEM_SC_DIR := src/esdt-system-sc
ESDT_SYSTEM_SC_WASM := $(ESDT_SYSTEM_SC_DIR)/output/esdt-system-sc.wasm

$(ESDT_SYSTEM_SC_WASM): sc-build/$(ESDT_SYSTEM_SC_DIR)

runtime-json: build-mandos build-kasmer $(ESDT_SYSTEM_SC_WASM)
$(POETRY) run runtime $(ESDT_SYSTEM_SC_WASM)


# Testing
@@ -124,21 +136,31 @@ elrond_multisig_tests=$(shell cat tests/multisig.test)
test-elrond-multisig: build sc-build/$(ELROND_MULTISIG_DIR)
$(TEST_MANDOS) $(elrond_multisig_tests)

# NFT Tests

test-elrond-nft-minter: build sc-build/$(ELROND_CONTRACT_EXAMPLES)/nft-minter
$(TEST_MANDOS) $(shell find $(ELROND_CONTRACT_EXAMPLES)/nft-minter -name "*.scen.json")

## Basic Feature Test

ELROND_BASIC_FEATURES_DIR=$(ELROND_CONTRACT)/feature-tests/basic-features
ELROND_BASIC_FEATURES_WASM=$(ELROND_BASIC_FEATURES_DIR)/output/basic-features.wasm
elrond_basic_features_tests=$(shell cat tests/basic_features.test)


ELROND_ESDT_SC_MOCK_DIR=$(ELROND_CONTRACT)/feature-tests/esdt-system-sc-mock
ELROND_ESDT_SC_MOCK_WASM=$(ELROND_ESDT_SC_MOCK_DIR)/output/esdt-system-sc-mock.wasm

$(ELROND_BASIC_FEATURES_WASM): sc-build/$(ELROND_BASIC_FEATURES_DIR)
$(ELROND_ESDT_SC_MOCK_WASM): sc-build/$(ELROND_ESDT_SC_MOCK_DIR)

# TODO optimize test runner and enable logging
test-elrond-basic-features: $(elrond_basic_features_tests:=.mandos)

$(ELROND_BASIC_FEATURES_DIR)/scenarios/%.scen.json.mandos: build $(ELROND_BASIC_FEATURES_WASM)
$(ELROND_BASIC_FEATURES_DIR)/scenarios/%.scen.json.mandos: build $(ELROND_BASIC_FEATURES_WASM) $(ELROND_ESDT_SC_MOCK_WASM)
$(TEST_MANDOS) $(ELROND_BASIC_FEATURES_DIR)/scenarios/$*.scen.json --log-level none

tests/custom-scenarios/basic-features/%.scen.json.mandos: build $(ELROND_BASIC_FEATURES_WASM)
tests/custom-scenarios/basic-features/%.scen.json.mandos: build $(ELROND_BASIC_FEATURES_WASM) $(ELROND_ESDT_SC_MOCK_WASM)
$(TEST_MANDOS) tests/custom-scenarios/basic-features/$*.scen.json --log-level none

## Alloc Features Test
@@ -157,23 +179,25 @@ $(ELROND_ALLOC_FEATURES_DIR)/scenarios/%.scen.json.mandos: build $(ELROND_ALLOC_

## Composability Features Test

ELROND_VAULT_DIR=$(ELROND_CONTRACT)/feature-tests/composability/vault
ELROND_VAULT_WASM=$(ELROND_VAULT_DIR)/output/vault.wasm
$(ELROND_VAULT_WASM): sc-build/$(ELROND_VAULT_DIR)

ELROND_PROMISES_DIR=$(ELROND_CONTRACT)/feature-tests/composability/promises-features
ELROND_PROMISES_WASM=$(ELROND_PROMISES_DIR)/output/promises-features.wasm
$(ELROND_PROMISES_WASM): sc-build/$(ELROND_PROMISES_DIR)

elrond_composability_features_tests=$(shell cat tests/composability_features.test)
test-elrond-composability-features: $(elrond_composability_features_tests:=.mandos)

ELROND_COMPOSABILITY_FEATURES_DIR=$(ELROND_CONTRACT)/feature-tests/composability

$(ELROND_COMPOSABILITY_FEATURES_DIR)/scenarios-promises/%.scen.json.mandos: build $(ELROND_VAULT_WASM) $(ELROND_PROMISES_WASM)
$(TEST_MANDOS) $(ELROND_COMPOSABILITY_FEATURES_DIR)/scenarios-promises/$*.scen.json --log-level none
composability_contracts := vault \
promises-features \
forwarder \
forwarder-queue \
forwarder-raw \
proxy-test-first \
proxy-test-second \
recursive-caller
composability_builds := $(patsubst %,sc-build/$(ELROND_COMPOSABILITY_FEATURES_DIR)/%,$(composability_contracts))

$(ELROND_COMPOSABILITY_FEATURES_DIR)/%.scen.json.mandos: build $(composability_builds)
$(TEST_MANDOS) $(ELROND_COMPOSABILITY_FEATURES_DIR)/$*.scen.json --log-level none

tests/custom-scenarios/composability-features/%.scen.json.mandos: $(llvm_kompiled) $(ELROND_VAULT_WASM) $(ELROND_PROMISES_WASM)
tests/custom-scenarios/composability-features/%.scen.json.mandos: build $(composability_builds)
$(TEST_MANDOS) tests/custom-scenarios/composability-features/$*.scen.json --log-level none

# Custom contract tests
3 changes: 2 additions & 1 deletion kmultiversx/pyproject.toml
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "kmultiversx"
version = "0.1.44"
version = "0.1.45"
description = "Python tools for Elrond semantics"
authors = [
"Runtime Verification, Inc. <contact@runtimeverification.com>",
@@ -14,6 +14,7 @@ authors = [
mandos = "kmultiversx.scenario:run_tests"
kasmer = "kmultiversx.kasmer:main"
kelrond = "kmultiversx.scripts.kelrond:main"
runtime = "kmultiversx.runtime:main"

[tool.poetry.plugins.kdist]
mx-semantics = "kmultiversx.kdist.plugin"
4 changes: 2 additions & 2 deletions kmultiversx/src/kmultiversx/kasmer.py
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@
mandos_argument_to_kbytes,
wrapBytes,
)
from kmultiversx.utils import GENERATED_TOP_CELL, KasmerRunError, kast_to_json_str, krun_config, load_wasm
from kmultiversx.utils import KasmerRunError, kast_to_json_str, krun_config, load_wasm, read_kasmer_runtime

if TYPE_CHECKING:
from hypothesis.strategies import SearchStrategy
@@ -123,7 +123,7 @@ def deploy_test(krun: KRun, test_wasm: KInner, contract_wasms: dict[bytes, KInne
)

# create an empty config and embed init steps
empty_conf = krun.definition.init_config(GENERATED_TOP_CELL)
empty_conf = read_kasmer_runtime()

conf, subst = split_config_from(empty_conf)
subst['K_CELL'] = init_steps
14 changes: 0 additions & 14 deletions kmultiversx/src/kmultiversx/kdist/mx-semantics/elrond-config.md
Original file line number Diff line number Diff line change
@@ -311,20 +311,6 @@ TODO: Implement [reserved keys and read-only runtimes](https://github.com/Elrond
<bytesStack> BS : STACK => STACK </bytesStack>
```

### Output

```k
syntax InternalInstr ::= "#appendToOutFromBytesStack"
| #appendToOut ( Bytes )
// -----------------------------------------------
rule <instrs> #appendToOutFromBytesStack => .K ... </instrs>
<bytesStack> OUT : STACK => STACK </bytesStack>
<out> ... (.ListBytes => ListItem(wrap(OUT))) </out>
rule <instrs> #appendToOut(OUT) => .K ... </instrs>
<out> ... (.ListBytes => ListItem(wrap(OUT))) </out>
```

### Parsing

```k
38 changes: 35 additions & 3 deletions kmultiversx/src/kmultiversx/kdist/mx-semantics/elrond-node.md
Original file line number Diff line number Diff line change
@@ -32,6 +32,8 @@ module ELROND-NODE
// gas
<gasProvided> 0 </gasProvided>
<gasPrice> 0 </gasPrice>
// tx ID
<txHash> .Bytes </txHash>
</vmInput>
// executional
// every contract call uses its own wasm module instance, managed data heaps, and bytesStack.
@@ -58,6 +60,9 @@ module ELROND-NODE
<esdtId> .Bytes </esdtId>
<esdtBalance> 0 </esdtBalance>
<esdtRoles> .Set </esdtRoles>
<esdtProperties> .Bytes </esdtProperties>
<esdtMetadata> .esdtMetadata </esdtMetadata>
<esdtLastNonce> 0 </esdtLastNonce>
</esdtData>
</esdtDatas>
```
@@ -139,8 +144,8 @@ Storage maps byte arrays to byte arrays.
syntax Bool ::= nonZeroOutputTransfer(OutputTransfer) [function, total]
// ---------------------------------------------------------------------------
rule nonZeroOutputTransfer(OutputTransfer(_, I:Int)) => I =/=Int 0
rule nonZeroOutputTransfer(OutputTransfer(_, esdtTransfer(_, I, _))) => I =/=Int 0
rule nonZeroOutputTransfer(OutputTransfer(_, I:Int)) => I =/=Int 0
rule nonZeroOutputTransfer(OutputTransfer(_, L:List)) => size(L) >Int 0
syntax OutputAccount ::= appendToOutTransfers(OutputAccount, OutputTransfer) [function, total]
// -------------------------------------------------------------------------------------------------
@@ -170,7 +175,7 @@ Storage maps byte arrays to byte arrays.
[priority(61)]
syntax TransferValue ::= Int // EGLD transfer
| ESDTTransfer
| List
syntax Address ::= Bytes
| WasmStringToken
@@ -190,6 +195,15 @@ Storage maps byte arrays to byte arrays.
syntax ESDTTransfer ::= esdtTransfer( tokenName : Bytes , tokenValue : Int , tokenNonce : Int ) [klabel(esdtTransfer), symbol]
syntax ESDTMetadata ::= ".esdtMetadata" [klabel(.esdtMetadata), symbol]
| esdtMetadata(
name: Bytes,
nonce: Int,
creator: Bytes,
royalties: Int,
hash: Bytes,
uris: ListBytes,
attributes: Bytes ) [klabel(esdtMetadata), symbol]
```

### Bytes Stack
@@ -200,13 +214,17 @@ Storage maps byte arrays to byte arrays.
syntax BytesOp ::= #pushBytes ( Bytes )
| "#dropBytes"
| "#appendBytes"
// ---------------------------------------
rule <instrs> #pushBytes(BS) => .K ... </instrs>
<bytesStack> STACK => BS : STACK </bytesStack>
rule <instrs> #dropBytes => .K ... </instrs>
<bytesStack> _ : STACK => STACK </bytesStack>
rule <instrs> #appendBytes => .K ... </instrs>
<bytesStack> BS1 : BS2 : BSS => (BS1 +Bytes BS2) : BSS </bytesStack>
syntax InternalInstr ::= "#returnLength"
// ----------------------------------------
rule <instrs> #returnLength => i32.const lengthBytes(BS) ... </instrs>
@@ -219,6 +237,20 @@ Storage maps byte arrays to byte arrays.
```

### Output

```k
syntax InternalInstr ::= "#appendToOutFromBytesStack"
| #appendToOut ( Bytes )
// -----------------------------------------------
rule <instrs> #appendToOutFromBytesStack => .K ... </instrs>
<bytesStack> OUT : STACK => STACK </bytesStack>
<out> ... (.ListBytes => ListItem(wrap(OUT))) </out>
rule <instrs> #appendToOut(OUT) => .K ... </instrs>
<out> ... (.ListBytes => ListItem(wrap(OUT))) </out>
```

## Call State

The `<callStack>` cell stores a list of previous contract execution states. These internal commands manages the callstack when calling and returning from a contract.
Loading

0 comments on commit 17f0b02

Please sign in to comment.