NFT lecture material

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2024-12-16 17:29:49 +03:00
commit 190d272daa
16 changed files with 1523 additions and 0 deletions

10
.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
.idea
nft/market/*.json
nft/market/*.nef
nft/nep11/*.json
nft/nep11/*.nef
nft/nep17/*.json
nft/nep17/*.nef

56
commands.sh Normal file
View file

@ -0,0 +1,56 @@
#!/bin/bash
# d2a4cff31913016155e38e474a2c06d08be276cf
neo-go wallet nep17 balance --token GAS -r http://localhost:30333 -w /path/to/frostfs-aio/wallets/wallet1.json
####################
# Custom NFT nep11 #
####################
neo-go contract compile -i nep11/contract.go -o nep11/contract.nef -m nep11/contract.manifest.json -c nep11/contract.yml
neo-go contract deploy -i nep11/contract.nef -m nep11/contract.manifest.json -r http://localhost:30333 -w /path/to/frostfs-aio/wallets/wallet1.json [ NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk ] # d9ab2450c7cc775f747cde591a65c4735c97831c NNWjkFL2TneXjgbHbNPEooiEpxb9KqDnoF
neo-go contract testinvokefunction -r http://localhost:30333 d9ab2450c7cc775f747cde591a65c4735c97831c symbol | jq -r '.stack[0].value' | base64 -d && echo
neo-go contract testinvokefunction -r http://localhost:30333 d9ab2450c7cc775f747cde591a65c4735c97831c decimals
neo-go contract testinvokefunction -r http://localhost:30333 d9ab2450c7cc775f747cde591a65c4735c97831c totalSupply
neo-go contract testinvokefunction -r http://localhost:30333 d9ab2450c7cc775f747cde591a65c4735c97831c balanceOf NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk # NivQRezLwGP8xFPr87DD5XaYGUKK3BMsTa
neo-go contract testinvokefunction -r http://localhost:30333 d9ab2450c7cc775f747cde591a65c4735c97831c tokensOfList NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk | jq -r '.stack[].value | .[].value' | base64 -d | xxd -ps -c 32
neo-go contract testinvokefunction -r http://localhost:30333 d9ab2450c7cc775f747cde591a65c4735c97831c properties bytes:55d14c99e63092ecd8492180de6e672b539e8dc23eebea5708722a4458e04270 | jq -r '.stack[].value | .[] .value.value' | while IFS=$'\n' read -r line; do echo $line |base64 -d && echo ; done
neo-go contract testinvokefunction -r http://localhost:30333 d9ab2450c7cc775f747cde591a65c4735c97831c ownerOf bytes:55d14c99e63092ecd8492180de6e672b539e8dc23eebea5708722a4458e04270 | jq -r '.stack[0].value' | base64 -d | xxd -ps -c 32
neo-go contract testinvokefunction -r http://localhost:30333 d9ab2450c7cc775f747cde591a65c4735c97831c tokensList | jq -r '.stack[].value | .[] .value' | base64 -d | xxd -ps -c 32
neo-go wallet nep17 transfer -r http://localhost:30333 -w /path/to/frostfs-aio/wallets/wallet1.json --from NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk --to NNWjkFL2TneXjgbHbNPEooiEpxb9KqDnoF --amount 20 --token GAS nft-name --await
neo-go wallet nep11 transfer -r http://localhost:30333 -w /path/to/frostfs-aio/wallets/wallet1.json --from NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk --to NivQRezLwGP8xFPr87DD5XaYGUKK3BMsTa --token NICENAMES --id 79aef731091472c4395b63b32b2c00c919b9d9538dc1c990381cc8c4609fe9f8 --await
######################
# Custom Token nep17 #
######################
neo-go contract compile -i nep17/contract.go -o nep17/contract.nef -m nep17/contract.manifest.json -c nep17/contract.yml
neo-go contract deploy -i nep17/contract.nef -m nep17/contract.manifest.json -r http://localhost:30333 -w /path/to/frostfs-aio/wallets/wallet1.json [ NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk 100 ] # 7724e3048f013163e97015f00850da015154af18
neo-go contract testinvokefunction -r http://localhost:30333 7724e3048f013163e97015f00850da015154af18 symbol | jq -r '.stack[0].value' | base64 -d && echo
neo-go contract testinvokefunction -r http://localhost:30333 7724e3048f013163e97015f00850da015154af18 decimals
neo-go contract testinvokefunction -r http://localhost:30333 7724e3048f013163e97015f00850da015154af18 totalSupply
neo-go contract testinvokefunction -r http://localhost:30333 7724e3048f013163e97015f00850da015154af18 balanceOf NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk # NivQRezLwGP8xFPr87DD5XaYGUKK3BMsTa
neo-go wallet nep17 transfer -r http://localhost:30333 -w /path/to/frostfs-aio/wallets/wallet1.json --from NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk --to NivQRezLwGP8xFPr87DD5XaYGUKK3BMsTa --amount 20 --token MYTKN --await
##########
# Market #
##########
#LE ScriptHash to Address NNAwRTMyVYpvJY2bYuM1qruvQaBXuAxyPR for transfer
neo-go contract compile -i market/contract.go -o market/contract.nef -m market/contract.manifest.json -c market/contract.yml
neo-go contract deploy -i market/contract.nef -m market/contract.manifest.json -r http://localhost:30333 -w /path/to/frostfs-aio/wallets/wallet1.json [ NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk 7724e3048f013163e97015f00850da015154af18 d9ab2450c7cc775f747cde591a65c4735c97831c ] # 7724e3048f013163e97015f00850da015154af18
neo-go contract testinvokefunction -r http://localhost:30333 84adbcd44b941e9446a331f12cf2bfecc504c518 list | jq -r '.stack[0].value | .[] .value | .[] .value.value' | while IFS=$'\n' read -r line; do echo $line |base64 -d && echo ; done
neo-go wallet nep11 transfer -r http://localhost:30333 -w /path/to/frostfs-aio/wallets/wallet1.json --from NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk --to NNAwRTMyVYpvJY2bYuM1qruvQaBXuAxyPR --token d9ab2450c7cc775f747cde591a65c4735c97831c --id cec6d08d9f18169e74e4540566994ea81cac2df30a298229f50262459b4cd3fc --await
neo-go wallet nep17 transfer -r http://localhost:30333 -w /path/to/frostfs-aio/wallets/wallet1.json --from NhCHDEtGgSph1v6PmjFC1gtzJWNKtNSadk --to NNAwRTMyVYpvJY2bYuM1qruvQaBXuAxyPR --amount 10 --token 7724e3048f013163e97015f00850da015154af18 bytes:cec6d08d9f18169e74e4540566994ea81cac2df30a298229f50262459b4cd3fc --await
############
# Wrappers #
############
neo-go contract generate-rpcwrapper -o wrappers/nep11/rpc_wrapper.go -m nep11/contract.manifest.json -c nep11/contract.yml --hash d9ab2450c7cc775f747cde591a65c4735c97831c
neo-go contract generate-rpcwrapper -o wrappers/nep11/rpc_wrapper.go -m nep11/contract.manifest.json -c nep11/contract.yml
neo-go contract generate-rpcwrapper -o wrappers/nep17/rpc_wrapper.go -m nep17/contract.manifest.json -c nep17/contract.yml
neo-go contract generate-rpcwrapper -o wrappers/market/rpc_wrapper.go -m market/contract.manifest.json -c market/contract.yml

BIN
nft/NFT.pdf Normal file

Binary file not shown.

48
nft/go.mod Normal file
View file

@ -0,0 +1,48 @@
module contract
go 1.22
require (
github.com/nspcc-dev/neo-go v0.107.1
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec
)
require (
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/holiman/uint256 v1.3.1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b // indirect
github.com/nspcc-dev/hrw/v2 v2.0.1 // indirect
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 // indirect
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12 // indirect
github.com/nspcc-dev/rfc6979 v0.2.3 // indirect
github.com/nspcc-dev/tzhash v1.7.2 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/prometheus/client_golang v1.20.2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect
github.com/twmb/murmur3 v1.1.8 // indirect
go.etcd.io/bbolt v1.3.11 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect
google.golang.org/grpc v1.62.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

256
nft/go.sum Normal file
View file

@ -0,0 +1,256 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.14.2 h1:YXVoyPndbdvcEVcseEovVfp0qjJp7S+i5+xgp/Nfbdc=
github.com/bits-and-blooms/bitset v1.14.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E=
github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0=
github.com/containerd/containerd v1.7.13 h1:wPYKIeGMN8vaggSKuV1X0wZulpMz4CrgEsZdaCyB6Is=
github.com/containerd/containerd v1.7.13/go.mod h1:zT3up6yTRfEUa6+GsITYIJNgSVL9NQ4x4h1RPzk0Wu4=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0=
github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs=
github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nspcc-dev/dbft v0.3.1 h1:3qoc65CVJMtdL/627JZH+1Jz839LmdsVN52L4mlP5z8=
github.com/nspcc-dev/dbft v0.3.1/go.mod h1:BNvJkPKTE28r+qRaAk2C3VoL2J9qzox3fvEeJbh7EWE=
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b h1:DRG4cRqIOmI/nUPggMgR92Jxt63Lxsuz40m5QpdvYXI=
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b/go.mod h1:d3cUseu4Asxfo9/QA/w4TtGjM0AbC9ynyab+PfH+Bso=
github.com/nspcc-dev/hrw/v2 v2.0.1 h1:CxYUkBeJvNfMEn2lHhrV6FjY8pZPceSxXUtMVq0BUOU=
github.com/nspcc-dev/hrw/v2 v2.0.1/go.mod h1:iZAs5hT2q47EGq6AZ0FjaUI6ggntOi7vrY4utfzk5VA=
github.com/nspcc-dev/neo-go v0.107.1 h1:Mef1nLhYj96G6nX8uxKh1tIXFk4PbxgRwOAGAtUsuTY=
github.com/nspcc-dev/neo-go v0.107.1/go.mod h1:YdaKw8mfdXrECqKzLPzJYysJnoey48g5EG+NTdEfjn8=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 h1:arN0Ypn+jawZpu1BND7TGRn44InAVIqKygndsx0y2no=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12 h1:mdxtlSU2I4oVZ/7AXTLKyz8uUPbDWikZw4DM8gvrddA=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12/go.mod h1:JdsEM1qgNukrWqgOBDChcYp8oY4XUzidcKaxY4hNJvQ=
github.com/nspcc-dev/rfc6979 v0.2.3 h1:QNVykGZ3XjFwM/88rGfV3oj4rKNBy+nYI6jM7q19hDI=
github.com/nspcc-dev/rfc6979 v0.2.3/go.mod h1:q3sCL1Ed7homjqYK8KmFSzEmm+7Ngyo7PePbZanhaDE=
github.com/nspcc-dev/tzhash v1.7.2 h1:iRXoa9TJqH/DQO7FFcqpq9BdruF9E7/xnFGlIghl5J4=
github.com/nspcc-dev/tzhash v1.7.2/go.mod h1:oHiH0qwmTsZkeVs7pvCS5cVXUaLhXxSFvnmnZ++ijm4=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU=
github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4=
github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs=
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
github.com/testcontainers/testcontainers-go v0.24.1 h1:gJdZuQIVWnMJTo+CmQMEP7/CAagNk/0jbcUPn3OWvD8=
github.com/testcontainers/testcontainers-go v0.24.1/go.mod h1:MGBiAkCm86yXQoCiipmQCqZLVdk1uFqtMqaU1Or0MRk=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8=
github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=

224
nft/main.go Normal file
View file

@ -0,0 +1,224 @@
package main
import (
"context"
"fmt"
"math/big"
"os"
"os/signal"
"runtime/debug"
"strconv"
"syscall"
nftmarket "contract/wrappers/market"
nicenamesnft "contract/wrappers/nep11"
awesomeneotoken "contract/wrappers/nep17"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/gas"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neo-go/pkg/wallet"
)
func main() {
ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
rpcCli, err := rpcclient.New(ctx, "http://localhost:30333", rpcclient.Options{})
die(err)
w, err := wallet.NewWalletFromFile("/home/denis/github/tcl/neofs-aio/wallets/wallet1.json")
die(err)
acc := w.GetAccount(w.GetChangeAddress())
err = acc.Decrypt("", w.Scrypt)
die(err)
act, err := actor.NewSimple(rpcCli, acc)
die(err)
hashNFT, err := util.Uint160DecodeStringLE("d9ab2450c7cc775f747cde591a65c4735c97831c")
die(err)
contractNFT := nicenamesnft.New(act, hashNFT)
_ = contractNFT
hashMarket, err := util.Uint160DecodeStringLE("c6a0eb7e12c4a6e1abe293ade33cd62436c46b24")
die(err)
contractMarket := nftmarket.New(act, hashMarket)
_ = contractMarket
hashToken, err := util.Uint160DecodeStringLE("7724e3048f013163e97015f00850da015154af18")
die(err)
contractToken := awesomeneotoken.New(act, hashToken)
contractGAS := gas.New(act)
printBalances(contractGAS, contractToken, acc.ScriptHash())
printMarketNFT(contractMarket)
buyNFT(act, contractMarket, contractToken, hashMarket, "my-itmo-nft")
printMarketNFT(contractMarket)
printNFTs(contractNFT, acc.ScriptHash())
printBalances(contractGAS, contractToken, acc.ScriptHash())
//printNFTs(contractNFT, acc.ScriptHash())
//createNFT(act, contractGAS, hashNFT, "my-itmo-nft")
//printNFTs(contractNFT, acc.ScriptHash())
//transferMyTKN(act, contractMarket, acc.ScriptHash())
//printMarketNFT(contractMarket)
//sellNFT(act, contractNFT, hashMarket, "for-market")
//byNFT(act, contractMarket, contractToken, hashMarket, "for-market")
//printMarketNFT(contractMarket)
//printNFTs(contractNFT, acc.ScriptHash())
}
func createNFT(act *actor.Actor, contractGAS *nep17.Token, hashNFT util.Uint160, name string) {
_, err := act.WaitSuccess(contractGAS.Transfer(act.Sender(), hashNFT, big.NewInt(10_0000_0000), name))
die(err)
}
func printBalances(contractGAS *nep17.Token, contractToken *awesomeneotoken.Contract, owner util.Uint160) {
fmt.Println("Balances:")
gasBalance, err := contractGAS.BalanceOf(owner)
die(err)
fmt.Println("GAS balance: ", gasBalance.Uint64())
mytknBalance, err := contractToken.BalanceOf(owner)
die(err)
fmt.Println("MYTKN balance: ", mytknBalance.Uint64())
fmt.Println()
}
func sellNFT(act *actor.Actor, c *nicenamesnft.Contract, to util.Uint160, name string) {
for _, nft := range listNFTs(c, act.Sender()) {
if nft.Name == name {
_, err := act.WaitSuccess(c.Transfer(to, nft.ID, nil))
die(err)
return
}
}
fmt.Println("not found nft: ", name)
fmt.Println()
}
func transferMyTKN(act *actor.Actor, c *nftmarket.Contract, to util.Uint160) {
_, err := act.WaitSuccess(c.TransferTokens(to, big.NewInt(10_0000_0000)))
die(err)
}
func buyNFT(act *actor.Actor, c *nftmarket.Contract, ct *awesomeneotoken.Contract, marketHash util.Uint160, name string) {
for _, nft := range listMarketNFT(c) {
if nft.Name == name {
_, err := act.WaitSuccess(ct.Transfer(act.Sender(), marketHash, big.NewInt(10_0000_0000), nft.ID))
die(err)
return
}
}
fmt.Println("not found market nft: ", name)
fmt.Println()
}
func printNFTs(c *nicenamesnft.Contract, owner util.Uint160) {
res := listNFTs(c, owner)
fmt.Println("owner nfts:")
fmt.Println(res)
fmt.Println()
}
func listNFTs(c *nicenamesnft.Contract, owner util.Uint160) []NFTItem {
res, err := c.TokensOfExpanded(owner, 10)
die(err)
var list []NFTItem
for _, re := range res {
prop, err := c.Properties(re)
die(err)
list = append(list, parseMap(prop.Value().([]stackitem.MapElement)))
}
return list
}
func printMarketNFT(c *nftmarket.Contract) {
res := listMarketNFT(c)
fmt.Println("market nfts:")
fmt.Println(res)
fmt.Println()
}
func listMarketNFT(c *nftmarket.Contract) []NFTItem {
res, err := c.List()
die(err)
var list []NFTItem
for _, re := range res {
items := re.Value().([]stackitem.MapElement)
list = append(list, parseMap(items))
}
return list
}
type NFTItem struct {
ID []byte
Owner util.Uint160
Name string
PrevOwners int
Created int
Bought int
}
func (n NFTItem) String() string {
return fmt.Sprintf("%x\nowner: %s\nname: %s\nprevOwners: %d\ncreated block: %d\nlast bought block: %d\n",
n.ID, address.Uint160ToString(n.Owner), n.Name, n.PrevOwners, n.Created, n.Bought)
}
func parseMap(items []stackitem.MapElement) NFTItem {
var res NFTItem
for _, item := range items {
k, err := item.Key.TryBytes()
die(err)
v, err := item.Value.TryBytes()
die(err)
kStr := string(k)
switch kStr {
case "id":
res.ID = v
case "owner":
res.Owner, err = address.StringToUint160(string(v))
die(err)
case "name":
res.Name = string(v)
case "preOwners":
res.PrevOwners, err = strconv.Atoi(string(v))
die(err)
case "created":
res.Created, err = strconv.Atoi(string(v))
die(err)
case "bought":
res.Bought, err = strconv.Atoi(string(v))
die(err)
}
}
return res
}
func die(err error) {
if err == nil {
return
}
debug.PrintStack()
_, _ = fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}

138
nft/market/contract.go Normal file
View file

@ -0,0 +1,138 @@
package contract
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/interop/util"
)
// Prefixes used for contract data storage.
const (
ownerKey = 'o'
tokenKey = 't'
nftKey = 'n'
tokensPrefix = "tt"
)
type NFTItem struct {
ID []byte
Owner interop.Hash160
Name string
PrevOwners int
Created int
Bought int
}
func _deploy(data interface{}, isUpdate bool) {
if isUpdate {
return
}
args := data.(struct {
Admin interop.Hash160
Token interop.Hash160
Market interop.Hash160
})
if args.Admin == nil {
panic("invalid admin")
}
if len(args.Admin) != 20 {
panic("invalid admin hash length")
}
ctx := storage.GetContext()
storage.Put(ctx, ownerKey, args.Admin)
storage.Put(ctx, tokenKey, args.Token)
storage.Put(ctx, nftKey, args.Market)
}
func OnNEP11Payment(from interop.Hash160, amount int, token []byte, data any) {
ctx := storage.GetContext()
callingHash := runtime.GetCallingScriptHash()
if !callingHash.Equals(storage.Get(ctx, nftKey).(interop.Hash160)) {
panic("invalid nft")
}
if amount != 1 {
panic("invalid amount")
}
key := append([]byte(tokensPrefix), token...)
if data == nil {
data = []byte{}
}
storage.Put(ctx, key, data)
}
func List() []map[string]string {
ctx := storage.GetContext()
nft := storage.Get(ctx, nftKey).(interop.Hash160)
res := []map[string]string{}
iter := storage.Find(ctx, []byte(tokensPrefix), storage.KeysOnly|storage.RemovePrefix)
for iterator.Next(iter) {
token := iterator.Value(iter).([]byte)
prop := contract.Call(nft, "properties", contract.All, token).(map[string]string)
res = append(res, prop)
}
return res
}
func OnNEP17Payment(from interop.Hash160, amount int, data any) {
defer func() {
if r := recover(); r != nil {
runtime.Log(r.(string))
util.Abort()
}
}()
ctx := storage.GetContext()
callingHash := runtime.GetCallingScriptHash()
if !callingHash.Equals(storage.Get(ctx, tokenKey).(interop.Hash160)) {
panic("invalid token")
}
if amount < 10_0000_0000 {
panic("insufficient funds")
}
token := data.([]byte)
key := append([]byte(tokensPrefix), token...)
if storage.Get(ctx, key) == nil {
panic("token not found")
}
storage.Delete(ctx, key)
nft := storage.Get(ctx, nftKey).(interop.Hash160)
contract.Call(nft, "transfer", contract.All, from, token)
}
func TransferTokens(to interop.Hash160, amount int) {
defer func() {
if r := recover(); r != nil {
runtime.Log(r.(string))
util.Abort()
}
}()
ctx := storage.GetContext()
owner := storage.Get(ctx, ownerKey).(interop.Hash160)
if !runtime.CheckWitness(owner) {
panic("not witnessed")
}
tokenHash := storage.Get(ctx, tokenKey).(interop.Hash160)
contract.Call(tokenHash, "transfer", contract.All, runtime.GetExecutingScriptHash(), to, amount, nil)
}

6
nft/market/contract.yml Normal file
View file

@ -0,0 +1,6 @@
name: "NFT market"
safemethods: [ "list" ]
permissions:
- methods: [ "properties","transfer" ]
# - contract:

342
nft/nep11/contract.go Normal file
View file

@ -0,0 +1,342 @@
package contract
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
"github.com/nspcc-dev/neo-go/pkg/interop/native/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/native/gas"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/interop/util"
)
// Prefixes used for contract data storage.
const (
balancePrefix = "b"
accountPrefix = "a"
tokenPrefix = "t"
ownerKey = 'o'
totalSupplyKey = 's'
)
const (
minNameLen = 3
)
type NFTItem struct {
ID []byte
Owner interop.Hash160
Name string
PrevOwners int
Created int
Bought int
}
func _deploy(data interface{}, isUpdate bool) {
if isUpdate {
return
}
args := data.(struct {
Admin interop.Hash160
})
if args.Admin == nil {
panic("invalid admin")
}
if len(args.Admin) != 20 {
panic("invalid admin hash length")
}
ctx := storage.GetContext()
storage.Put(ctx, ownerKey, args.Admin)
name := ownerAddress(args.Admin)
nft := NFTItem{
ID: crypto.Sha256([]byte(name)),
Owner: args.Admin,
Name: name,
PrevOwners: 0,
Created: ledger.CurrentIndex(),
Bought: ledger.CurrentIndex(),
}
setNFT(ctx, nft.ID, nft)
addToBalance(ctx, nft.Owner, 1)
addToken(ctx, nft.Owner, nft.ID)
storage.Put(ctx, totalSupplyKey, 1)
}
// Symbol returns token symbol, it's NICENAMES.
func Symbol() string {
return "NICENAMES"
}
// Decimals returns token decimals, this NFT is non-divisible, so it's 0.
func Decimals() int {
return 0
}
// TotalSupply is a contract method that returns the number of tokens minted.
func TotalSupply() int {
return storage.Get(storage.GetReadOnlyContext(), totalSupplyKey).(int)
}
// BalanceOf returns the number of tokens owned by the specified address.
func BalanceOf(holder interop.Hash160) int {
if len(holder) != 20 {
panic("bad owner address")
}
ctx := storage.GetReadOnlyContext()
return getBalanceOf(ctx, mkBalanceKey(holder))
}
// OwnerOf returns the owner of the specified token.
func OwnerOf(token []byte) interop.Hash160 {
ctx := storage.GetReadOnlyContext()
return getNFT(ctx, token).Owner
}
// Properties returns properties of the given NFT.
func Properties(token []byte) map[string]string {
ctx := storage.GetReadOnlyContext()
nft := getNFT(ctx, token)
result := map[string]string{
"id": string(nft.ID),
"owner": ownerAddress(nft.Owner),
"name": nft.Name,
"prevOwners": std.Itoa10(nft.PrevOwners),
"created": std.Itoa10(nft.Created),
"bought": std.Itoa10(nft.Bought),
}
return result
}
// Tokens returns an iterator that contains all the tokens minted by the contract.
func Tokens() iterator.Iterator {
ctx := storage.GetReadOnlyContext()
key := []byte(tokenPrefix)
iter := storage.Find(ctx, key, storage.RemovePrefix|storage.KeysOnly)
return iter
}
func TokensList() []string {
ctx := storage.GetReadOnlyContext()
key := []byte(tokenPrefix)
iter := storage.Find(ctx, key, storage.RemovePrefix|storage.KeysOnly)
keys := []string{}
for iterator.Next(iter) {
k := iterator.Value(iter)
keys = append(keys, k.(string))
}
return keys
}
// TokensOf returns an iterator with all tokens held by the specified address.
func TokensOf(holder interop.Hash160) iterator.Iterator {
if len(holder) != 20 {
panic("bad owner address")
}
ctx := storage.GetReadOnlyContext()
key := mkAccountPrefix(holder)
iter := storage.Find(ctx, key, storage.ValuesOnly)
return iter
}
func TokensOfList(holder interop.Hash160) [][]byte {
if len(holder) != 20 {
panic("bad owner address")
}
ctx := storage.GetReadOnlyContext()
key := mkAccountPrefix(holder)
res := [][]byte{}
iter := storage.Find(ctx, key, storage.ValuesOnly)
for iterator.Next(iter) {
res = append(res, iterator.Value(iter).([]byte))
}
return res
}
// Transfer token from its owner to another user, notice that it only has three
// parameters because token owner can be deduced from token ID itself.
func Transfer(to interop.Hash160, token []byte, data any) bool {
if len(to) != 20 {
panic("invalid 'to' address")
}
ctx := storage.GetContext()
nft := getNFT(ctx, token)
from := nft.Owner
if !runtime.CheckWitness(from) {
return false
}
if !from.Equals(to) {
nft.Owner = to
nft.Bought = ledger.CurrentIndex()
nft.PrevOwners += 1
setNFT(ctx, token, nft)
addToBalance(ctx, from, -1)
removeToken(ctx, from, token)
addToBalance(ctx, to, 1)
addToken(ctx, to, token)
}
postTransfer(from, to, token, data)
return true
}
func getNFT(ctx storage.Context, token []byte) NFTItem {
key := mkTokenKey(token)
val := storage.Get(ctx, key)
if val == nil {
panic("no token found")
}
serializedNFT := val.([]byte)
deserializedNFT := std.Deserialize(serializedNFT)
return deserializedNFT.(NFTItem)
}
func nftExists(ctx storage.Context, token []byte) bool {
key := mkTokenKey(token)
return storage.Get(ctx, key) != nil
}
func setNFT(ctx storage.Context, token []byte, item NFTItem) {
key := mkTokenKey(token)
val := std.Serialize(item)
storage.Put(ctx, key, val)
}
// postTransfer emits Transfer event and calls onNEP11Payment if needed.
func postTransfer(from interop.Hash160, to interop.Hash160, token []byte, data any) {
runtime.Notify("Transfer", from, to, 1, token)
if management.GetContract(to) != nil {
contract.Call(to, "onNEP11Payment", contract.All, from, 1, token, data)
}
}
// OnNEP17Payment mints tokens if at least 10 GAS is provided. You don't call
// this method directly, instead it's called by GAS contract when you transfer
// GAS from your address to the address of this NFT contract.
func OnNEP17Payment(from interop.Hash160, amount int, data any) {
defer func() {
if r := recover(); r != nil {
runtime.Log(r.(string))
util.Abort()
}
}()
callingHash := runtime.GetCallingScriptHash()
if !callingHash.Equals(gas.Hash) {
panic("only GAS is accepted")
}
name := data.(string)
if len(name) < 3 {
panic("name length at least 3 character")
}
price := 10_0000_0000
if len(name) < 10 {
price += 5_0000_0000
}
if len(name) < 6 {
price += 5_0000_0000
}
if amount < price {
panic("insufficient GAS for minting NFT")
}
ctx := storage.GetContext()
tokenID := crypto.Sha256([]byte(name))
if nftExists(ctx, tokenID) {
panic("token already exists")
}
nft := NFTItem{
ID: tokenID,
Owner: from,
Name: name,
PrevOwners: 0,
Created: ledger.CurrentIndex(),
Bought: ledger.CurrentIndex(),
}
setNFT(ctx, tokenID, nft)
addToBalance(ctx, from, 1)
addToken(ctx, from, tokenID)
total := storage.Get(ctx, totalSupplyKey).(int) + 1
storage.Put(ctx, totalSupplyKey, total)
postTransfer(nil, from, tokenID, nil)
}
// mkAccountPrefix creates DB key-prefix for the account tokens specified
// by concatenating accountPrefix and account address.
func mkAccountPrefix(holder interop.Hash160) []byte {
res := []byte(accountPrefix)
return append(res, holder...)
}
// mkBalanceKey creates DB key for the account specified by concatenating balancePrefix
// and account address.
func mkBalanceKey(holder interop.Hash160) []byte {
res := []byte(balancePrefix)
return append(res, holder...)
}
// mkTokenKey creates DB key for the token specified by concatenating tokenPrefix
// and token ID.
func mkTokenKey(tokenID []byte) []byte {
res := []byte(tokenPrefix)
return append(res, tokenID...)
}
// getBalanceOf returns the balance of an account using database key.
func getBalanceOf(ctx storage.Context, balanceKey []byte) int {
val := storage.Get(ctx, balanceKey)
if val != nil {
return val.(int)
}
return 0
}
// addToBalance adds an amount to the account balance. Amount can be negative.
func addToBalance(ctx storage.Context, holder interop.Hash160, amount int) {
key := mkBalanceKey(holder)
old := getBalanceOf(ctx, key)
old += amount
if old > 0 {
storage.Put(ctx, key, old)
} else {
storage.Delete(ctx, key)
}
}
// addToken adds a token to the account.
func addToken(ctx storage.Context, holder interop.Hash160, token []byte) {
key := mkAccountPrefix(holder)
storage.Put(ctx, append(key, token...), token)
}
// removeToken removes the token from the account.
func removeToken(ctx storage.Context, holder interop.Hash160, token []byte) {
key := mkAccountPrefix(holder)
storage.Delete(ctx, append(key, token...))
}
func ownerAddress(owner interop.Hash160) string {
b := append([]byte{0x35}, owner...)
return std.Base58CheckEncode(b)
}

16
nft/nep11/contract.yml Normal file
View file

@ -0,0 +1,16 @@
name: "NICENAMES NFT"
supportedstandards: ["NEP-11"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "tokens", "properties"]
events:
- name: Transfer
parameters:
- name: from
type: Hash160
- name: to
type: Hash160
- name: amount
type: Integer
- name: tokenId
type: ByteArray
permissions:
- methods: ["onNEP11Payment"]

114
nft/nep17/contract.go Normal file
View file

@ -0,0 +1,114 @@
package contract
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
)
// Prefixes used for contract data storage.
const (
ownerKey = 'o'
totalSupplyKey = 's'
)
const (
decimals = 8
multiplier = 100000000
)
func _deploy(data interface{}, isUpdate bool) {
if isUpdate {
return
}
args := data.(struct {
Admin interop.Hash160
Total int
})
if args.Admin == nil {
panic("invalid admin")
}
if len(args.Admin) != 20 {
panic("invalid admin hash length")
}
if args.Total <= 0 {
panic("invalid total supply")
}
ctx := storage.GetContext()
storage.Put(ctx, ownerKey, args.Admin)
total := args.Total * multiplier
storage.Put(ctx, args.Admin, total)
storage.Put(ctx, totalSupplyKey, total)
}
// Symbol returns the token symbol
func Symbol() string {
return "MYTKN"
}
// Decimals returns the token decimals
func Decimals() int {
return decimals
}
// TotalSupply returns the token total supply value
func TotalSupply() int {
return storage.Get(storage.GetReadOnlyContext(), totalSupplyKey).(int)
}
// BalanceOf returns the amount of token on the specified address
func BalanceOf(holder interop.Hash160) int {
if len(holder) != 20 {
panic("bad owner address")
}
return storage.Get(storage.GetReadOnlyContext(), holder).(int)
}
// Transfer token from one user to another
func Transfer(from interop.Hash160, to interop.Hash160, amount int, data any) bool {
ctx := storage.GetContext()
if len(from) != 20 || len(to) != 20 {
panic("invalid addresses")
}
if amount < 0 {
panic("invalid amount")
}
if !runtime.CheckWitness(from) {
return false
}
amountFrom := getIntFromDB(ctx, from)
if amountFrom < amount {
return false
}
storage.Put(ctx, from, amountFrom-amount)
amountTo := getIntFromDB(ctx, to)
storage.Put(ctx, to, amountTo+amount)
runtime.Notify("Transfer", from, to, amount)
if management.GetContract(to) != nil {
contract.Call(to, "onNEP17Payment", contract.All, from, amount, data)
}
return true
}
func getIntFromDB(ctx storage.Context, key []byte) int {
var res int
val := storage.Get(ctx, key)
if val != nil {
res = val.(int)
}
return res
}

14
nft/nep17/contract.yml Normal file
View file

@ -0,0 +1,14 @@
name: "Awesome NEO Token"
supportedstandards: ["NEP-17"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
events:
- name: Transfer
parameters:
- name: from
type: Hash160
- name: to
type: Hash160
- name: amount
type: Integer
permissions:
- methods: ["onNEP17Payment"]

View file

@ -0,0 +1,80 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package nftmarket contains RPC wrappers for NFT market contract.
package nftmarket
import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big"
)
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
Invoker
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
SendRun(script []byte) (util.Uint256, uint32, error)
}
// ContractReader implements safe contract methods.
type ContractReader struct {
invoker Invoker
hash util.Uint160
}
// Contract implements all contract methods.
type Contract struct {
ContractReader
actor Actor
hash util.Uint160
}
// NewReader creates an instance of ContractReader using provided contract hash and the given Invoker.
func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
return &ContractReader{invoker, hash}
}
// New creates an instance of Contract using provided contract hash and the given Actor.
func New(actor Actor, hash util.Uint160) *Contract {
return &Contract{ContractReader{actor, hash}, actor, hash}
}
// List invokes `list` method of contract.
func (c *ContractReader) List() ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.Call(c.hash, "list"))
}
// TransferTokens creates a transaction invoking `transferTokens` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) TransferTokens(to util.Uint160, amount *big.Int) (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "transferTokens", to, amount)
}
// TransferTokensTransaction creates a transaction invoking `transferTokens` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) TransferTokensTransaction(to util.Uint160, amount *big.Int) (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "transferTokens", to, amount)
}
// TransferTokensUnsigned creates a transaction invoking `transferTokens` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) TransferTokensUnsigned(to util.Uint160, amount *big.Int) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "transferTokens", nil, to, amount)
}

View file

@ -0,0 +1,99 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package nicenamesnft contains RPC wrappers for NICENAMES NFT contract.
package nicenamesnft
import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
nep11.Invoker
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
Invoker
nep11.Actor
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
SendRun(script []byte) (util.Uint256, uint32, error)
}
// ContractReader implements safe contract methods.
type ContractReader struct {
nep11.NonDivisibleReader
invoker Invoker
hash util.Uint160
}
// Contract implements all contract methods.
type Contract struct {
ContractReader
nep11.BaseWriter
actor Actor
hash util.Uint160
}
// NewReader creates an instance of ContractReader using provided contract hash and the given Invoker.
func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
return &ContractReader{*nep11.NewNonDivisibleReader(invoker, hash), invoker, hash}
}
// New creates an instance of Contract using provided contract hash and the given Actor.
func New(actor Actor, hash util.Uint160) *Contract {
var nep11ndt = nep11.NewNonDivisible(actor, hash)
return &Contract{ContractReader{nep11ndt.NonDivisibleReader, actor, hash}, nep11ndt.BaseWriter, actor, hash}
}
// TokensList creates a transaction invoking `tokensList` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) TokensList() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "tokensList")
}
// TokensListTransaction creates a transaction invoking `tokensList` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) TokensListTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "tokensList")
}
// TokensListUnsigned creates a transaction invoking `tokensList` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) TokensListUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "tokensList", nil)
}
// TokensOfList creates a transaction invoking `tokensOfList` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) TokensOfList(holder util.Uint160) (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "tokensOfList", holder)
}
// TokensOfListTransaction creates a transaction invoking `tokensOfList` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) TokensOfListTransaction(holder util.Uint160) (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "tokensOfList", holder)
}
// TokensOfListUnsigned creates a transaction invoking `tokensOfList` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) TokensOfListUnsigned(holder util.Uint160) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "tokensOfList", nil, holder)
}

View file

@ -0,0 +1,73 @@
// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]; DO NOT EDIT.
// Package nicenamesnft contains wrappers for NICENAMES NFT contract.
package nicenamesnft
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
)
// Hash contains contract hash in big-endian form.
const Hash = "\x1c\x83\x97\x5c\x73\xc4\x65\x1a\x59\xde\x7c\x74\x5f\x77\xcc\xc7\x50\x24\xab\xd9"
// BalanceOf invokes `balanceOf` method of contract.
func BalanceOf(holder interop.Hash160) int {
return neogointernal.CallWithToken(Hash, "balanceOf", int(contract.ReadOnly), holder).(int)
}
// Decimals invokes `decimals` method of contract.
func Decimals() int {
return neogointernal.CallWithToken(Hash, "decimals", int(contract.ReadOnly)).(int)
}
// OnNEP17Payment invokes `onNEP17Payment` method of contract.
func OnNEP17Payment(from interop.Hash160, amount int, data any) {
neogointernal.CallWithTokenNoRet(Hash, "onNEP17Payment", int(contract.All), from, amount, data)
}
// OwnerOf invokes `ownerOf` method of contract.
func OwnerOf(token []byte) interop.Hash160 {
return neogointernal.CallWithToken(Hash, "ownerOf", int(contract.ReadOnly), token).(interop.Hash160)
}
// Properties invokes `properties` method of contract.
func Properties(token []byte) map[string]any {
return neogointernal.CallWithToken(Hash, "properties", int(contract.ReadOnly), token).(map[string]any)
}
// Symbol invokes `symbol` method of contract.
func Symbol() string {
return neogointernal.CallWithToken(Hash, "symbol", int(contract.ReadOnly)).(string)
}
// Tokens invokes `tokens` method of contract.
func Tokens() any {
return neogointernal.CallWithToken(Hash, "tokens", int(contract.ReadOnly)).(any)
}
// TokensList invokes `tokensList` method of contract.
func TokensList() []any {
return neogointernal.CallWithToken(Hash, "tokensList", int(contract.All)).([]any)
}
// TokensOf invokes `tokensOf` method of contract.
func TokensOf(holder interop.Hash160) any {
return neogointernal.CallWithToken(Hash, "tokensOf", int(contract.ReadOnly), holder).(any)
}
// TokensOfList invokes `tokensOfList` method of contract.
func TokensOfList(holder interop.Hash160) []any {
return neogointernal.CallWithToken(Hash, "tokensOfList", int(contract.All), holder).([]any)
}
// TotalSupply invokes `totalSupply` method of contract.
func TotalSupply() int {
return neogointernal.CallWithToken(Hash, "totalSupply", int(contract.ReadOnly)).(int)
}
// Transfer invokes `transfer` method of contract.
func Transfer(to interop.Hash160, token []byte, data any) bool {
return neogointernal.CallWithToken(Hash, "transfer", int(contract.All), to, token, data).(bool)
}

View file

@ -0,0 +1,47 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package awesomeneotoken contains RPC wrappers for Awesome NEO Token contract.
package awesomeneotoken
import (
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
nep17.Invoker
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
Invoker
nep17.Actor
}
// ContractReader implements safe contract methods.
type ContractReader struct {
nep17.TokenReader
invoker Invoker
hash util.Uint160
}
// Contract implements all contract methods.
type Contract struct {
ContractReader
nep17.TokenWriter
actor Actor
hash util.Uint160
}
// NewReader creates an instance of ContractReader using provided contract hash and the given Invoker.
func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
return &ContractReader{*nep17.NewReader(invoker, hash), invoker, hash}
}
// New creates an instance of Contract using provided contract hash and the given Actor.
func New(actor Actor, hash util.Uint160) *Contract {
var nep17t = nep17.New(actor, hash)
return &Contract{ContractReader{nep17t.TokenReader, actor, hash}, nep17t.TokenWriter, actor, hash}
}