Skip to content

Commit

Permalink
Updated nuklai-cli and added last bit of unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kpachhai committed Oct 8, 2024
1 parent 7a713e5 commit 147dce1
Show file tree
Hide file tree
Showing 22 changed files with 929 additions and 304 deletions.
48 changes: 21 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,8 @@ If successful, the balance response should look like this:
```bash
address: 00c4cb545f748a28770042f893784ce85b107389004d6a0e0d6d7518eeae1292d9
chainID: 2F1QmuxSSVntNHXnEevYHBZzyhsNGvAE5Y2pqJW2a4iBugTMWd
uri: http://127.0.0.1:9650/ext/bc/nuklaivm
address: 00c4cb545f748a28770042f893784ce85b107389004d6a0e0d6d7518eeae1292d9 balance: 853000000.000000000 NAI
chainID: PAroBtUb83kcU5m3XiD37D263cB8kaZsiZ1rG7DLKxs8EX7Cq
address: 00cf77495ce1bdbf11e5e45463fad5a862cb6cc0a20e00e658c4ac3355dcdc64bb balance: 853000000.000000000 NAI
```
You can also check the balance of another address by passing in the address as the argument
Expand All @@ -285,15 +284,8 @@ You can also check the balance of another address by passing in the address as t
Should give output
```bash
address: 01b27c7ce992cdb7ff039294d7901851902394bb85fa4f3dc4cbb960b07284b7f9
chainID: 2F1QmuxSSVntNHXnEevYHBZzyhsNGvAE5Y2pqJW2a4iBugTMWd
assetID (use NAI for native token): NAI
assetID: 11111111111111111111111111111111LpoYY
name: nuklaivm
symbol: NAI
balance: 0
please send funds to 01b27c7ce992cdb7ff039294d7901851902394bb85fa4f3dc4cbb960b07284b7f9
exiting...
chainID: PAroBtUb83kcU5m3XiD37D263cB8kaZsiZ1rG7DLKxs8EX7Cq
address: 00cf77495ce1bdbf11e5e45463fad5a862cb6cc0a20e00e658c4ac3355dcdc64bb balance: 0.000000000 NAI
```
### Generate Another Address
Expand All @@ -311,8 +303,8 @@ Note that we are now generating a key with curve secp256r1 instead of ed25519 li
If successful, the `nuklai-cli` will emit the new address:
```bash
created address: 01b27c7ce992cdb7ff039294d7901851902394bb85fa4f3dc4cbb960b07284b7f9
Private Key String: h3geZh5VQ4JEe829BTvaKaECnrVUGA1fEUY4imgnzbg=
created address: 011ddbf62f227dd32deea73b31945d65bb6676cccae6cf0b829dfc21b290387bac
Private Key String(Base64): J5kwBjyvMuvV4PfjTUOO8ZF40Db3KzhFidhH7ER+9Jg=
```
We can also generate a bls key doing
Expand All @@ -331,11 +323,14 @@ the following command to set it back to `demo.pk`:
You should see something like this:
```bash
chainID: 2F1QmuxSSVntNHXnEevYHBZzyhsNGvAE5Y2pqJW2a4iBugTMWd
chainID: PAroBtUb83kcU5m3XiD37D263cB8kaZsiZ1rG7DLKxs8EX7Cq
stored keys: 3
0) address: 00c4cb545f748a28770042f893784ce85b107389004d6a0e0d6d7518eeae1292d9 balance: 853000000.000000000 NAI
1) address: 01b27c7ce992cdb7ff039294d7901851902394bb85fa4f3dc4cbb960b07284b7f9 balance: 0.000000000 NAI
2) address: 023d4f5711f36fc407e114a86b513b8c51ae124224d11eee5430c27e2d8e673893 balance: 0.000000000 NAI
chainID: PAroBtUb83kcU5m3XiD37D263cB8kaZsiZ1rG7DLKxs8EX7Cq
0) address: 00cf77495ce1bdbf11e5e45463fad5a862cb6cc0a20e00e658c4ac3355dcdc64bb balance: 853000000.000000000 NAI
chainID: PAroBtUb83kcU5m3XiD37D263cB8kaZsiZ1rG7DLKxs8EX7Cq
1) address: 00cf77495ce1bdbf11e5e45463fad5a862cb6cc0a20e00e658c4ac3355dcdc64bb balance: 0.000000000 NAI
chainID: PAroBtUb83kcU5m3XiD37D263cB8kaZsiZ1rG7DLKxs8EX7Cq
2) address: 00cf77495ce1bdbf11e5e45463fad5a862cb6cc0a20e00e658c4ac3355dcdc64bb balance: 0.000000000 NAI
set default key: 0
```
Expand Down Expand Up @@ -376,15 +371,14 @@ The `nuklai-cli` will emit the following logs when the transfer is successful:
```bash
address: 00c4cb545f748a28770042f893784ce85b107389004d6a0e0d6d7518eeae1292d9
chainID: 2hKDi8QVgngBxCbakibVqQFa3EV8YzA957q7nPT5vrQRpx8Z9E
assetID (use NAI for native token): NAI
balance: 853000000.000000000 NAI
recipient: 00fa92500595699234176c32afbf5c6558df21deb10ba4d2d691e5e5148658c64a
amount: 1
chainID: PAroBtUb83kcU5m3XiD37D263cB8kaZsiZ1rG7DLKxs8EX7Cq
assetAddress (use NAI for native token): NAI
address: 00cf77495ce1bdbf11e5e45463fad5a862cb6cc0a20e00e658c4ac3355dcdc64bb balance: 853000000.000000000 NAI
✔ amount: 1█
continue (y/n): y
✅ txID: X4HTZbkvrXy8Ka3VBdEJLGj1eUVNQf9LoWZyLZCxham1D1zND
fee consumed: 0.000032100
output: &{SenderBalance:852999998999967900 ReceiverBalance:1000000000}
✅ txID: wjzqXJeYedVSyBWfapoGiHYC9EQr2HgkA7xrVW4KZQyP1jxxG
txID: wjzqXJeYedVSyBWfapoGiHYC9EQr2HgkA7xrVW4KZQyP1jxxG
fee consumed: 0.000048500 NAI
```
### Bonus: Watch Activity in Real-Time
Expand All @@ -408,7 +402,7 @@ select chainID: 0 [auto-selected]
uri: http://127.0.0.1:9650/ext/bc/nuklaivm
watching for new blocks on 2F1QmuxSSVntNHXnEevYHBZzyhsNGvAE5Y2pqJW2a4iBugTMWd 👀
height:3003 txs:1 root:uNXBoJRGNo8JCJ8XDEioqVnJjwrVSSKBMgbaTd9AWFiUke2vE size:0.30KB units consumed: [bandwidth=224 compute=7 storage(read)=14 storage(allocate)=50 storage(write)=26] unit prices: [bandwidth=100 compute=100 storage(read)=100 storage(allocate)=100 storage(write)=100] [TPS:0.10 latency:66ms gap:142ms]
X3VcRchV8E8CoK38qEWYG9mNFLTwxm5V1mhZzsF4KCdkuwfPB actor: 00c4cb545f748a28770042f893784ce85b107389004d6a0e0d6d7518eeae1292d9 summary (*actions.Transfer): [assetID: 11111111111111111111111111111111LpoYY amount: 100000000000 -> 01b27c7ce992cdb7ff039294d7901851902394bb85fa4f3dc4cbb960b07284b7f9
2deLZJJpfXm1Wrad1f8uZL1aZnrCkEtBZ6aFXNcR7stFYN8Rm8 actor: 00c4cb545f748a28770042f893784ce85b107389004d6a0e0d6d7518eeae1292d9 summary (*actions.Transfer): [assetID: 00cf77495ce1bdbf11e5e45463fad5a862cb6cc0a20e00e658c4ac3355dcdc64bb amount: 1000000000 -> 00cf77495ce1bdbf11e5e45463fad5a862cb6cc0a20e00e658c4ac3355dcdc64bb
]
```
Expand Down
221 changes: 221 additions & 0 deletions actions/claim_marketplace_payment_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
// Copyright (C) 2024, Nuklai. All rights reserved.
// See the file LICENSE for licensing terms.

package actions

import (
"context"
"testing"

"github.com/nuklai/nuklaivm/emission"
"github.com/nuklai/nuklaivm/storage"
"github.com/nuklai/nuklaivm/utils"
"github.com/stretchr/testify/require"

"github.com/ava-labs/hypersdk/chain/chaintest"
"github.com/ava-labs/hypersdk/codec"
"github.com/ava-labs/hypersdk/codec/codectest"
"github.com/ava-labs/hypersdk/state"

nconsts "github.com/nuklai/nuklaivm/consts"
)

func TestClaimMarketplacePaymentAction(t *testing.T) {
actor := codectest.NewRandomAddress()
datasetAddress := storage.AssetAddress(nconsts.AssetFractionalTokenID, []byte("Valid Name"), []byte("DATASET"), 0, []byte("metadata"), actor)
baseAssetAddress := storage.NAIAddress
marketplaceAssetAddress := storage.AssetAddressFractional(datasetAddress)

emission.MockNewEmission(&emission.MockEmission{LastAcceptedBlockHeight: 100})

tests := []chaintest.ActionTest{
{
Name: "WrongOwner",
Actor: codectest.NewRandomAddress(), // Not the owner of the asset
Action: &ClaimMarketplacePayment{
MarketplaceAssetAddress: marketplaceAssetAddress,
PaymentAssetAddress: baseAssetAddress,
},
State: func() state.Mutable {
store := chaintest.NewInMemoryStore()
metadata := map[string]string{
"datasetAddress": datasetAddress.String(),
"marketplaceAssetAddress": marketplaceAssetAddress.String(),
"datasetPricePerBlock": "100",
"paymentAssetAddress": baseAssetAddress.String(),
"publisher": actor.String(),
"lastClaimedBlock": "0",
"subscriptions": "0",
"paymentRemaining": "0",
"paymentClaimed": "0",
}
metadataBytes, err := utils.MapToBytes(metadata)
require.NoError(t, err)
require.NoError(t, storage.SetAssetInfo(context.Background(), store, marketplaceAssetAddress, nconsts.AssetMarketplaceTokenID, []byte("name"), []byte("SYM"), 0, metadataBytes, []byte(marketplaceAssetAddress.String()), 0, 0, actor, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress))
return store
}(),
ExpectedErr: ErrWrongOwner,
},
{
Name: "BaseAssetNotSupported",
Actor: actor,
Action: &ClaimMarketplacePayment{
MarketplaceAssetAddress: marketplaceAssetAddress,
PaymentAssetAddress: codec.EmptyAddress, // Invalid base asset ID
},
State: func() state.Mutable {
store := chaintest.NewInMemoryStore()
metadata := map[string]string{
"datasetAddress": datasetAddress.String(),
"marketplaceAssetAddress": marketplaceAssetAddress.String(),
"datasetPricePerBlock": "100",
"paymentAssetAddress": baseAssetAddress.String(),
"publisher": actor.String(),
"lastClaimedBlock": "0",
"subscriptions": "0",
"paymentRemaining": "0",
"paymentClaimed": "0",
}
metadataBytes, err := utils.MapToBytes(metadata)
require.NoError(t, err)
require.NoError(t, storage.SetAssetInfo(context.Background(), store, marketplaceAssetAddress, nconsts.AssetMarketplaceTokenID, []byte("name"), []byte("SYM"), 0, metadataBytes, []byte(marketplaceAssetAddress.String()), 0, 0, actor, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress))
return store
}(),
ExpectedErr: ErrPaymentAssetNotSupported,
},
{
Name: "NoPaymentRemaining",
Actor: actor,
Action: &ClaimMarketplacePayment{
MarketplaceAssetAddress: marketplaceAssetAddress,
PaymentAssetAddress: baseAssetAddress,
},
State: func() state.Mutable {
store := chaintest.NewInMemoryStore()
metadata := map[string]string{
"datasetAddress": datasetAddress.String(),
"marketplaceAssetAddress": marketplaceAssetAddress.String(),
"datasetPricePerBlock": "100",
"paymentAssetAddress": baseAssetAddress.String(),
"publisher": actor.String(),
"lastClaimedBlock": "50",
"subscriptions": "0",
"paymentRemaining": "0",
"paymentClaimed": "0",
}
metadataBytes, err := utils.MapToBytes(metadata)
require.NoError(t, err)
require.NoError(t, storage.SetAssetInfo(context.Background(), store, marketplaceAssetAddress, nconsts.AssetMarketplaceTokenID, []byte("name"), []byte("SYM"), 0, metadataBytes, []byte(marketplaceAssetAddress.String()), 0, 0, actor, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress))
return store
}(),
ExpectedErr: ErrNoPaymentRemaining,
},
{
Name: "ValidPaymentClaim",
Actor: actor,
Action: &ClaimMarketplacePayment{
MarketplaceAssetAddress: marketplaceAssetAddress,
PaymentAssetAddress: baseAssetAddress,
},
State: func() state.Mutable {
store := chaintest.NewInMemoryStore()
metadata := map[string]string{
"datasetAddress": datasetAddress.String(),
"marketplaceAssetAddress": marketplaceAssetAddress.String(),
"datasetPricePerBlock": "100",
"paymentAssetAddress": baseAssetAddress.String(),
"publisher": actor.String(),
"lastClaimedBlock": "0",
"subscriptions": "0",
"paymentRemaining": "100",
"paymentClaimed": "0",
}
metadataBytes, err := utils.MapToBytes(metadata)
require.NoError(t, err)
require.NoError(t, storage.SetAssetInfo(context.Background(), store, marketplaceAssetAddress, nconsts.AssetMarketplaceTokenID, []byte("name"), []byte("SYM"), 0, metadataBytes, []byte(marketplaceAssetAddress.String()), 0, 0, actor, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress))
return store
}(),
Assertion: func(ctx context.Context, t *testing.T, store state.Mutable) {
// Check if the payment was correctly claimed
balance, err := storage.GetAssetAccountBalanceNoController(ctx, store, baseAssetAddress, actor)
require.NoError(t, err)
require.Equal(t, uint64(100), balance) // 100 units claimed

// Check if metadata was updated correctly
_, _, _, _, metadata, _, _, _, _, _, _, _, _, err := storage.GetAssetInfoNoController(ctx, store, marketplaceAssetAddress)
require.NoError(t, err)
metadataMap, err := utils.BytesToMap(metadata)
require.NoError(t, err)
require.Equal(t, "0", metadataMap["paymentRemaining"]) // 1000 - 100 claimed
require.Equal(t, "100", metadataMap["paymentClaimed"])
require.Equal(t, "100", metadataMap["lastClaimedBlock"])
},
ExpectedOutputs: &ClaimMarketplacePaymentResult{
LastClaimedBlock: 100,
PaymentClaimed: 100,
PaymentRemaining: 0,
DistributedReward: 100,
DistributedTo: actor,
},
},
}

for _, tt := range tests {
tt.Run(context.Background(), t)
}
}

func BenchmarkClaimMarketplacePayment(b *testing.B) {
require := require.New(b)
actor := codectest.NewRandomAddress()
datasetAddress := storage.AssetAddress(nconsts.AssetFractionalTokenID, []byte("Valid Name"), []byte("DATASET"), 0, []byte("metadata"), actor)
baseAssetAddress := storage.NAIAddress
marketplaceAssetAddress := storage.AssetAddressFractional(datasetAddress)

emission.MockNewEmission(&emission.MockEmission{LastAcceptedBlockHeight: 100})

claimMarketplacePaymentBenchmark := &chaintest.ActionBenchmark{
Name: "ClaimMarketplacePaymentBenchmark",
Actor: actor,
Action: &ClaimMarketplacePayment{
MarketplaceAssetAddress: marketplaceAssetAddress,
PaymentAssetAddress: baseAssetAddress,
},
CreateState: func() state.Mutable {
store := chaintest.NewInMemoryStore()
metadata := map[string]string{
"datasetAddress": datasetAddress.String(),
"marketplaceAssetAddress": marketplaceAssetAddress.String(),
"datasetPricePerBlock": "100",
"paymentAssetAddress": baseAssetAddress.String(),
"publisher": actor.String(),
"lastClaimedBlock": "0",
"subscriptions": "0",
"paymentRemaining": "100",
"paymentClaimed": "0",
}
metadataBytes, err := utils.MapToBytes(metadata)
require.NoError(err)
require.NoError(storage.SetAssetInfo(context.Background(), store, marketplaceAssetAddress, nconsts.AssetMarketplaceTokenID, []byte("name"), []byte("SYM"), 0, metadataBytes, []byte(marketplaceAssetAddress.String()), 0, 0, actor, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress))
return store
},
Assertion: func(ctx context.Context, b *testing.B, store state.Mutable) {
// Check if the payment was correctly claimed
balance, err := storage.GetAssetAccountBalanceNoController(ctx, store, baseAssetAddress, actor)
require.NoError(err)
require.Equal(uint64(100), balance) // 100 units claimed

// Check if metadata was updated correctly
_, _, _, _, metadata, _, _, _, _, _, _, _, _, err := storage.GetAssetInfoNoController(ctx, store, marketplaceAssetAddress)
require.NoError(err)
metadataMap, err := utils.BytesToMap(metadata)
require.NoError(err)
require.Equal("0", metadataMap["paymentRemaining"]) // 1000 - 100 claimed
require.Equal("100", metadataMap["paymentClaimed"])
require.Equal("100", metadataMap["lastClaimedBlock"])
},
}

ctx := context.Background()
claimMarketplacePaymentBenchmark.Run(ctx, b)
}
4 changes: 2 additions & 2 deletions actions/complete_contribute_dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (d *CompleteContributeDataset) Execute(
}

// Retrieve the asset info
assetType, name, symbol, _, _, _, totalSupply, _, _, _, _, _, _, err := storage.GetAssetInfoNoController(ctx, mu, d.DatasetAddress)
_, name, symbol, _, _, _, totalSupply, _, _, _, _, _, _, err := storage.GetAssetInfoNoController(ctx, mu, d.DatasetAddress)
if err != nil {
return nil, err
}
Expand All @@ -117,7 +117,7 @@ func (d *CompleteContributeDataset) Execute(
}
nftAddress := codec.CreateAddress(nconsts.AssetFractionalTokenID, d.DatasetContributionID)
symbol = utils.CombineWithSuffix(symbol, totalSupply, storage.MaxSymbolSize)
if err := storage.SetAssetInfo(ctx, mu, nftAddress, assetType, name, symbol, 0, metadataNFT, []byte(d.DatasetAddress.String()), 0, 1, d.DatasetContributor, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress); err != nil {
if err := storage.SetAssetInfo(ctx, mu, nftAddress, nconsts.AssetNonFungibleTokenID, name, symbol, 0, metadataNFT, []byte(d.DatasetAddress.String()), 0, 1, d.DatasetContributor, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress); err != nil {
return nil, err
}
if _, err := storage.MintAsset(ctx, mu, nftAddress, d.DatasetContributor, 1); err != nil {
Expand Down
4 changes: 2 additions & 2 deletions actions/complete_contribute_dataset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func TestCompleteContributeDatasetAction(t *testing.T) {
// Check if NFT was created correctly
assetType, name, symbol, decimals, metadata, uri, totalSupply, maxSupply, owner, mintAdmin, pauseUnpauseAdmin, freezeUnfreezeAdmin, enableDisableKYCAccountAdmin, err := storage.GetAssetInfoNoController(ctx, store, nftAddress)
require.NoError(t, err)
require.Equal(t, nconsts.AssetFractionalTokenID, assetType)
require.Equal(t, nconsts.AssetNonFungibleTokenID, assetType)
require.Equal(t, "name", string(name))
require.Equal(t, "SYM-1", string(symbol))
require.Equal(t, uint8(0), decimals)
Expand Down Expand Up @@ -238,7 +238,7 @@ func BenchmarkCompleteContributeDataset(b *testing.B) {
// Check if NFT was created correctly
assetType, name, symbol, decimals, metadata, uri, totalSupply, maxSupply, owner, mintAdmin, pauseUnpauseAdmin, freezeUnfreezeAdmin, enableDisableKYCAccountAdmin, err := storage.GetAssetInfoNoController(ctx, store, nftAddress)
require.NoError(err)
require.Equal(nconsts.AssetFractionalTokenID, assetType)
require.Equal(nconsts.AssetNonFungibleTokenID, assetType)
require.Equal("name", string(name))
require.Equal("SYM-1", string(symbol))
require.Equal(uint8(0), decimals)
Expand Down
2 changes: 1 addition & 1 deletion actions/create_asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func (c *CreateAsset) Execute(
nftAddress := storage.AssetAddressNFT(assetAddress, []byte(c.Metadata), actor)
output.DatasetParentNftAddress = nftAddress
symbol := utils.CombineWithSuffix([]byte(c.Symbol), 0, storage.MaxSymbolSize)
if err := storage.SetAssetInfo(ctx, mu, nftAddress, c.AssetType, []byte(c.Name), symbol, 0, []byte(c.Metadata), []byte(assetAddress.String()), 0, 1, actor, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress); err != nil {
if err := storage.SetAssetInfo(ctx, mu, nftAddress, nconsts.AssetNonFungibleTokenID, []byte(c.Name), symbol, 0, []byte(c.Metadata), []byte(assetAddress.String()), 0, 1, actor, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress, codec.EmptyAddress); err != nil {
return nil, err
}
newBalance, err := storage.MintAsset(ctx, mu, nftAddress, actor, amountOfToken)
Expand Down
4 changes: 2 additions & 2 deletions actions/create_asset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func TestCreateAssetAction(t *testing.T) {
// Check if NFT was created correctly
assetType, name, symbol, decimals, metadata, uri, totalSupply, maxSupply, owner, mintAdmin, pauseUnpauseAdmin, freezeUnfreezeAdmin, enableDisableKYCAccountAdmin, err = storage.GetAssetInfoNoController(ctx, store, nftAddress)
require.NoError(t, err)
require.Equal(t, nconsts.AssetFractionalTokenID, assetType)
require.Equal(t, nconsts.AssetNonFungibleTokenID, assetType)
require.Equal(t, "name", string(name))
require.Equal(t, "SYM-0", string(symbol))
require.Equal(t, uint8(0), decimals)
Expand Down Expand Up @@ -273,7 +273,7 @@ func BenchmarkCreateAsset(b *testing.B) {
// Check if the asset was created correctly
assetType, name, symbol, decimals, metadata, uri, totalSupply, maxSupply, owner, mintAdmin, pauseUnpauseAdmin, freezeUnfreezeAdmin, enableDisableKYCAccountAdmin, err := storage.GetAssetInfoNoController(ctx, store, assetFT)
require.NoError(err)
require.Equal(nconsts.AssetFungibleTokenID, assetType)
require.Equal(nconsts.AssetNonFungibleTokenID, assetType)
require.Equal("name", string(name))
require.Equal("SYM", string(symbol))
require.Equal(uint8(9), decimals)
Expand Down
3 changes: 2 additions & 1 deletion actions/initiate_contribute_dataset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"strings"
"testing"

nconsts "github.com/nuklai/nuklaivm/consts"
"github.com/nuklai/nuklaivm/dataset"
"github.com/nuklai/nuklaivm/storage"
"github.com/stretchr/testify/require"
Expand All @@ -17,6 +16,8 @@ import (
"github.com/ava-labs/hypersdk/codec"
"github.com/ava-labs/hypersdk/codec/codectest"
"github.com/ava-labs/hypersdk/state"

nconsts "github.com/nuklai/nuklaivm/consts"
)

func TestInitiateContributeDatasetAction(t *testing.T) {
Expand Down
Loading

0 comments on commit 147dce1

Please sign in to comment.