Basalt.Sdk.Contracts 0.3.0

dotnet add package Basalt.Sdk.Contracts --version 0.3.0
                    
NuGet\Install-Package Basalt.Sdk.Contracts -Version 0.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Basalt.Sdk.Contracts" Version="0.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Basalt.Sdk.Contracts" Version="0.3.0" />
                    
Directory.Packages.props
<PackageReference Include="Basalt.Sdk.Contracts" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Basalt.Sdk.Contracts --version 0.3.0
                    
#r "nuget: Basalt.Sdk.Contracts, 0.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Basalt.Sdk.Contracts@0.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Basalt.Sdk.Contracts&version=0.3.0
                    
Install as a Cake Addin
#tool nuget:?package=Basalt.Sdk.Contracts&version=0.3.0
                    
Install as a Cake Tool

Basalt.Sdk.Contracts

Smart contract SDK for Basalt. Provides the attributes, storage primitives, and runtime context that contract developers use to build Basalt smart contracts in C#.

Getting Started

using Basalt.Sdk.Contracts;

[BasaltContract]
public class MyToken
{
    private readonly StorageMap<byte[], UInt256> _balances = new("balances");
    private readonly StorageValue<UInt256> _totalSupply = new("totalSupply");

    [BasaltConstructor]
    public void Initialize(UInt256 initialSupply)
    {
        _balances.Set(Context.Caller, initialSupply);
        _totalSupply.Set(initialSupply);
    }

    [BasaltEntrypoint]
    public void Transfer(byte[] to, UInt256 amount)
    {
        var sender = Context.Caller;
        var senderBalance = _balances.Get(sender);
        Context.Require(senderBalance >= amount, "Insufficient balance");

        _balances.Set(sender, senderBalance - amount);
        _balances.Set(to, _balances.Get(to) + amount);

        Context.Emit(new TransferEvent { From = sender, To = to, Amount = amount });
    }

    [BasaltView]
    public UInt256 BalanceOf(byte[] account) => _balances.Get(account);

    [BasaltEvent]
    public class TransferEvent
    {
        [Indexed] public byte[] From { get; set; }
        [Indexed] public byte[] To { get; set; }
        public UInt256 Amount { get; set; }
    }
}

Attributes

Attribute Target Description
[BasaltContract] Class Marks a class as a Basalt smart contract
[BasaltEntrypoint] Method State-mutating entry point
[BasaltView] Method Read-only view function (no state changes)
[BasaltConstructor] Method One-time initialization on deploy
[BasaltEvent] Class Event emitted by contracts
[Indexed] Property Indexed event parameter for efficient filtering
[BasaltSerializable] Class/Struct Marks a type for automatic binary codec generation (WriteTo/ReadFrom/GetSerializedSize)
[BasaltJsonSerializable] Class/Struct Marks a type for automatic JSON serialization support with Basalt primitive converters

Storage Primitives

StorageValue<T> where T : struct

Single value with a fixed storage key. The type parameter T is constrained to struct (value types only).

var totalSupply = new StorageValue<UInt256>("totalSupply");
totalSupply.Set(1_000_000);
UInt256 current = totalSupply.Get();

StorageMap<TKey, TValue>

Key-value mapping. TKey is constrained to notnull, but TValue is unconstrained -- it allows both value types and reference types (including string).

var balances = new StorageMap<byte[], UInt256>("balances");
balances.Set(account, 1000);
UInt256 balance = balances.Get(account);
bool exists = balances.ContainsKey(account);
balances.Delete(account);

// Reference type values are supported:
var names = new StorageMap<string, string>("names");
names.Set("alice", "Alice");

StorageList<T>

Ordered collection with index-based access.

var items = new StorageList<ulong>("items");
items.Add(42);
ulong first = items.Get(0);
int count = items.Count;

Runtime Context

Access blockchain state from within contracts via Context:

Property Type Description
Context.Caller byte[] Address of the caller
Context.Self byte[] Address of the current contract
Context.TxValue UInt256 Value sent with the call
Context.BlockTimestamp long Current block timestamp (Unix seconds)
Context.BlockHeight ulong Current block number
Context.ChainId uint Chain identifier
Context.GasRemaining ulong Remaining gas
Context.IsDeploying bool True during first-time contract deployment (check before one-time side effects)
Context.IsStaticCall bool True during read-only re-entrant callbacks (storage writes blocked)
Context.CallDepth int Current call depth (0 = top-level call)
Context.MaxCallDepth int Maximum cross-contract call depth (const 8)
Context.ReentrancyGuard HashSet<string> Set of contract addresses currently on the call stack
Context.CrossContractCallHandler Func<...>? Delegate for cross-contract calls (set by the runtime/test host)

Utility Methods

Context.Require(condition, "Error message");         // Revert if false
Context.Revert("Error message");                     // Unconditional revert
Context.Emit(new MyEvent { ... });                   // Emit event
Context.CallContract<T>(addr, "method", args);       // Cross-contract call (returns T)
Context.CallContract(addr, "method", args);           // Cross-contract call (void return)
Context.Reset();                                      // Reset all context state (used between test runs)

Cross-contract calls enforce reentrancy protection via ReentrancyGuard and a maximum call depth of MaxCallDepth (8). The calling contract's address becomes the Caller for the target, and context is restored after the call returns.

Token Standards (Standards/)

The SDK includes interfaces and reference implementations for common token standards, located in the Standards/ subdirectory.

BST-20 Fungible Token (ERC-20 equivalent)

Interface: IBST20 -- defines Name(), Symbol(), Decimals(), TotalSupply() returns UInt256, BalanceOf(byte[]) returns UInt256, Transfer(byte[], UInt256), Allowance(byte[], byte[]) returns UInt256, Approve(byte[], UInt256), TransferFrom(byte[], byte[], UInt256).

Implementation: BST20Token -- reference implementation with full allowance mechanics, Mint(byte[], UInt256) and Burn(byte[], UInt256) protected methods for derived contracts. Uses hex-encoded address strings as internal storage keys.

Events: TransferEvent (From, To, Amount: UInt256), ApprovalEvent (Owner, Spender, Amount: UInt256).

var token = new BST20Token("MyToken", "MTK", decimals: 18);

BST-721 Non-Fungible Token (ERC-721 equivalent)

Interface: IBST721 -- defines Name(), Symbol(), OwnerOf(UInt256), BalanceOf(byte[]) returns UInt256, Transfer(byte[], UInt256), Approve(byte[], UInt256), GetApproved(UInt256), TokenURI(UInt256).

Implementation: BST721Token -- reference implementation with auto-incrementing token IDs (UInt256), per-token approval, and metadata URI storage. Includes a public Mint(byte[], string) entrypoint that returns the new token ID as UInt256.

Events: NftTransferEvent (From, To, TokenId: UInt256), NftApprovalEvent (Owner, Approved, TokenId: UInt256).

var nft = new BST721Token("MyNFT", "MNFT");
UInt256 tokenId = nft.Mint(recipient, "https://example.com/metadata/0");

BST-1155 Multi-Token (ERC-1155 equivalent)

Interface: IBST1155 -- defines BalanceOf(byte[], UInt256) returns UInt256, BalanceOfBatch(byte[][], UInt256[]), SafeTransferFrom(byte[], byte[], UInt256, UInt256), SafeBatchTransferFrom(byte[], byte[], UInt256[], UInt256[]), SetApprovalForAll(byte[], bool), IsApprovedForAll(byte[], byte[]), Uri(UInt256).

Implementation: BST1155Token -- reference implementation supporting both fungible and non-fungible tokens in a single contract. Includes Mint(byte[], UInt256, UInt256, string) and Create(byte[], UInt256, string) for creating new token types with optional initial supply.

Events: TransferSingleEvent (Operator, From, To, TokenId: UInt256, Amount: UInt256), TransferBatchEvent (Operator, From, To, TokenIds, Amounts), ApprovalForAllEvent (Owner, Operator, Approved).

var multi = new BST1155Token("https://example.com/tokens/");
UInt256 tokenId = multi.Create(recipient, initialSupply: 1000, "https://example.com/tokens/0");

BST-DID Decentralized Identity

Interface: IBSTDID -- defines RegisterDID(byte[]), ResolveDID(string), AddAttestation(string, string, string, long, byte[]), RevokeAttestation(string, string), HasValidAttestation(string, string), TransferDID(string, byte[]), DeactivateDID(string).

Implementation: BSTDIDRegistry -- on-chain decentralized identifier registry. DIDs are formatted as did:basalt:<hex-index>. Supports verifiable credential attestations (add/revoke), controller transfer, and DID deactivation. Only the DID controller can manage its attestations and lifecycle.

Data Types: DIDDocument (Id, Controller, CreatedAt, UpdatedAt, Active), Attestation (Id, CredentialType, Issuer, IssuedAt, ExpiresAt, Revoked, Data).

Events: DIDRegisteredEvent (DID, Controller), AttestationAddedEvent (DID, CredentialType, Issuer, AttestationId), AttestationRevokedEvent (DID, AttestationId).

var registry = new BSTDIDRegistry("did:basalt:");
string did = registry.RegisterDID(controller);
registry.AddAttestation(did, "KYC", issuerHex, expiresAt, data);
bool valid = registry.HasValidAttestation(did, "KYC");

BST-3525 Semi-Fungible Token (ERC-3525 equivalent)

Interface: IBST3525 -- three-component model: (tokenId, slot, value). Tokens in the same slot are fungible by value. Each token has a unique ID (like BST-721) but carries a fungible value (like BST-20) that is transferable within the same slot.

Implementation: BST3525Token -- reference implementation with auto-incrementing token IDs, per-token value allowances, slot-based URI metadata, and ERC-721-compatible token ownership transfer. Value transfers require matching slots between source and destination.

Events: TransferValueEvent (FromTokenId, ToTokenId, Value), SftTransferEvent (From, To, TokenId), ApproveValueEvent (TokenId, Operator, Value), SftApprovalEvent (Owner, Approved, TokenId), SftMintEvent (To, TokenId, Slot, Value).

var sft = new BST3525Token("Bond Token", "BOND", valueDecimals: 6);

// Mint: create tokens in a slot (slot = maturity date, value = principal)
UInt256 bondA = sft.Mint(alice, slot: 20251231, value: 1_000_000);
UInt256 bondB = sft.Mint(bob, slot: 20251231, value: 500_000);

// Transfer value between same-slot tokens
sft.TransferValueToId(bondA, bondB, 200_000);  // alice → bob: 200k

// Transfer value to a new address (creates new token)
UInt256 bondC = sft.TransferValueToAddress(bondA, charlie, 100_000);

// Value allowance (operator pattern)
sft.ApproveValue(bondA, operator, 50_000);
UInt256 remaining = sft.ValueAllowance(bondA, operator);

// ERC-721 compatible token transfer
sft.TransferToken(dave, bondA);

BST-4626 Tokenized Vault (ERC-4626 equivalent)

Interface: IBST4626 (extends IBST20) -- standardized vault pattern. Deposit underlying BST-20 assets, receive vault share tokens. Shares are themselves BST-20 fungible tokens. Exchange rate adjusts as yield accrues.

Implementation: BST4626Vault (extends BST20Token) -- reference implementation with virtual shares/assets offset to prevent inflation attacks, ceiling-division rounding for withdrawal/mint previews (favors the vault), and admin-only yield reporting via Harvest(). Uses cross-contract calls to the underlying BST-20 asset.

Events: VaultDepositEvent (Caller, Assets, Shares), VaultWithdrawEvent (Caller, Assets, Shares), VaultHarvestEvent (Caller, YieldAmount, NewTotalAssets).

var vault = new BST4626Vault("Vault Shares", "vUND", decimals: 18, assetAddress);

// Deposit underlying assets → receive shares
UInt256 shares = vault.Deposit(1000);

// Check exchange rate
UInt256 sharesPerAsset = vault.ConvertToShares(100);
UInt256 assetsPerShare = vault.ConvertToAssets(100);

// Preview operations (includes rounding)
UInt256 sharesToBurn = vault.PreviewWithdraw(500);  // rounds up
UInt256 assetsNeeded = vault.PreviewMint(100);      // rounds up

// Withdraw/redeem
UInt256 burned = vault.Withdraw(500);    // withdraw exact assets, burn shares
UInt256 received = vault.Redeem(shares); // redeem exact shares, receive assets

// Admin: report yield (increases exchange rate)
vault.Harvest(100);  // totalAssets += 100, shares unchanged → each share worth more

BST-VC Verifiable Credential Registry (W3C VC + eIDAS 2.0)

Interface: IBSTVC -- on-chain registry for verifiable credential lifecycle. Full VCs stored off-chain (IPFS), only hashes on-chain. Supports issuance, revocation, suspension, and reinstatement. Only the original issuer can manage a credential's status.

Implementation: BSTVCRegistry -- reference implementation with status tracking (Active/Revoked/Suspended), issuer-only lifecycle management, per-issuer credential counting, and temporal validity checks. Credential IDs are deterministic: vc:{issuerHex}:{hexIndex}.

Status Transitions: (none) → Active → Suspended ↔ Reinstated → Revoked (terminal).

Events: CredentialIssuedEvent (CredentialHash, Issuer, Subject, CredentialId), CredentialRevokedEvent (CredentialHash, Issuer, Reason), CredentialSuspendedEvent (CredentialHash, Issuer, Reason), CredentialReinstatedEvent (CredentialHash, Issuer).

var vcRegistry = new BSTVCRegistry();

// Issue a credential (hash stored on-chain, full VC off-chain)
string credId = vcRegistry.IssueCredential(credentialHash, subjectDid, schemaId,
    validUntil: 1735689600, metadataUri: "ipfs://Qm...");

// Check status
byte status = vcRegistry.GetCredentialStatus(credentialHash);  // 1 = Active
bool valid = vcRegistry.IsCredentialValid(credentialHash);     // true if active + not expired

// Lifecycle management (issuer only)
vcRegistry.SuspendCredential(credentialHash, "Under review");
vcRegistry.ReinstateCredential(credentialHash);
vcRegistry.RevokeCredential(credentialHash, "Fraud detected");

// Query
UInt256 count = vcRegistry.GetIssuerCredentialCount(issuerAddr);
bool issued = vcRegistry.HasIssuerIssuedCredential(issuerAddr, credentialHash);
bool verified = vcRegistry.VerifyCredentialSet(credentialHash);

Governance (System Contract)

On-chain governance with stake-weighted quadratic voting, single-hop delegation, timelock, and executable proposals. Integrates with StakingPool for vote weight derivation.

Type ID: 0x0102 | Genesis address: 0x...1003

var gov = new Governance();

// Create a proposal
string proposalId = gov.CreateProposal("Upgrade block gas limit", "technical",
    targetContract, callData, votingPeriod: 604800);

// Vote (weight derived from StakingPool stake via cross-contract call)
gov.Vote(proposalIdBytes, voteYes: true);

// Delegate voting power
gov.DelegateVote(delegateAddr);
gov.UndelegateVote();

// Execute after timelock
gov.ExecuteProposal(proposalIdBytes);

// Query
UInt256 weight = gov.GetVotingWeight(voterAddr);
byte status = gov.GetProposalStatus(proposalIdBytes);  // 0=Active, 1=Passed, 2=Failed, 3=Executed, 4=Expired

BridgeETH (System Contract)

EVM bridge contract for locking/unlocking native BST with M-of-N Ed25519 multisig relayer verification, admin controls, pause/unpause, and deposit lifecycle management.

Type ID: 0x0107 | Genesis address: 0x...1008

var bridge = new BridgeETH();

// Lock BST (call with TxValue)
bridge.Lock(ethRecipientAddr);

// Admin: add relayer, set threshold
bridge.AddRelayer(relayerAddr);
bridge.SetThreshold(3);

// Relayer: confirm and finalize deposits
bridge.ConfirmDeposit(depositId, 42);
bridge.FinalizeDeposit(depositId);

// Unlock (with relayer signatures)
bridge.Unlock(bstRecipientAddr, amount, depositId, signatures);

// Admin controls
bridge.Pause();
bridge.Unpause();
bridge.TransferAdmin(newAdminAddr);

// Query
UInt256 locked = bridge.GetLockedBalance();
byte status = bridge.GetDepositStatus(depositId);
bool paused = bridge.IsPaused();

SchemaRegistry (ZK Compliance)

On-chain registry of credential schema definitions. Anyone can register a schema (permissionless). A schema defines WHAT can be proved via ZK proofs. SchemaId is derived from BLAKE3(name).

Type ID: 0x0105 | Genesis address: 0x...1006

var registry = new SchemaRegistry();

// Register a schema with its Groth16 verification key
string schemaIdHex = registry.RegisterSchema("KYC_Basic", fieldDefinitionsJson, verificationKeyBytes);

// Update VK (creator only)
registry.UpdateVerificationKey(schemaIdBytes, newVkBytes);

// Query
string name = registry.GetSchema(schemaIdBytes);
string vkHex = registry.GetVerificationKey(schemaIdBytes);
bool exists = registry.SchemaExists(schemaIdBytes);

Events: SchemaRegisteredEvent (SchemaId, Creator, Name), VerificationKeyUpdatedEvent (SchemaId, UpdatedBy).

IssuerRegistry (ZK Compliance)

On-chain registry of credential issuers with trust tiers and collateral staking. Issuers maintain their own Sparse Merkle Tree for credential revocation off-chain and publish the root on-chain.

Type ID: 0x0106 | Genesis address: 0x...1007

Issuer Tiers:

  • Tier 0: Self-attestation (anyone, no collateral)
  • Tier 1: Regulated entity (admin-approved, no collateral)
  • Tier 2: Accredited provider (requires BST collateral stake)
  • Tier 3: Sovereign/eIDAS (admin-approved, no collateral)
var issuerRegistry = new IssuerRegistry();

// Register (Tier 0: anyone, Tier 1/3: admin only, Tier 2: anyone + stake)
issuerRegistry.RegisterIssuer("Acme KYC Provider", tier: 2);
issuerRegistry.StakeCollateral();  // sends BST via TxValue

// Manage schemas and revocation
issuerRegistry.AddSchemaSupport(schemaIdBytes);
issuerRegistry.UpdateRevocationRoot(newMerkleRootBytes);

// Admin operations
issuerRegistry.SlashIssuer(issuerAddr, "Fraud detected");
issuerRegistry.DeactivateIssuer(issuerAddr);
issuerRegistry.TransferAdmin(newAdminAddr);

// Query
byte tier = issuerRegistry.GetIssuerTier(issuerAddr);
bool active = issuerRegistry.IsActiveIssuer(issuerAddr);
string rootHex = issuerRegistry.GetRevocationRoot(issuerAddr);
UInt256 stake = issuerRegistry.GetCollateralStake(issuerAddr);
bool supports = issuerRegistry.SupportsSchema(issuerAddr, schemaIdBytes);

Events: IssuerRegisteredEvent, CollateralStakedEvent, RevocationRootUpdatedEvent, IssuerSlashedEvent, IssuerDeactivatedEvent, IssuerReactivatedEvent, AdminTransferredEvent.

Policy Hooks (Policies/)

The SDK provides a standardized policy enforcement layer for all token standards. Deploy modular compliance policies as independent contracts, then register them on any BST token. All transfers are automatically checked against registered policies before execution -- zero policies means near-zero overhead (single storage read).

Architecture

BST-20/721/1155/3525/4626 Token
  |
  +-- PolicyEnforcer (storage-backed list of policy addresses)
        |
        +-- Policy A (ITransferPolicy) -- cross-contract call: CheckTransfer()
        +-- Policy B (ITransferPolicy) -- cross-contract call: CheckTransfer()
        +-- Policy C (INftTransferPolicy) -- cross-contract call: CheckNftTransfer()

Interfaces

  • ITransferPolicy -- CheckTransfer(byte[] token, byte[] from, byte[] to, UInt256 amount) returns bool
  • INftTransferPolicy -- CheckNftTransfer(byte[] token, byte[] from, byte[] to, ulong tokenId) returns bool

Reference Policies

Contract Type ID Description
HoldingLimitPolicy 0x0008 Max balance per address per token. Queries BalanceOf() via cross-contract call.
LockupPolicy 0x0009 Time-based transfer lockup. Checks Context.BlockTimestamp against per-address unlock time.
JurisdictionPolicy 0x000A Country whitelist/blacklist. Maps addresses to ISO 3166 country codes.
SanctionsPolicy 0x000B Admin-managed sanctions list. Denies transfers involving sanctioned addresses.

Policy Management on Tokens

Every BST token (BST-20, BST-721, BST-1155, BST-3525, BST-4626) exposes four policy entrypoints:

token.AddPolicy(byte[] policyAddress);     // Admin only -- register a policy
token.RemovePolicy(byte[] policyAddress);   // Admin only -- unregister a policy
token.PolicyCount();                        // View -- number of registered policies
token.GetPolicyAt(ulong index);             // View -- policy address at index

Usage Example

// Deploy token and policy
var token = new BST20Token("RegulatedToken", "RSEC", 18, new UInt256(1_000_000));
var sanctions = new SanctionsPolicy();

// Configure and register
sanctions.AddSanction(badActor);
token.AddPolicy(sanctionsAddress);

// All transfers are now enforced -- sanctioned addresses are blocked
token.Transfer(bob, new UInt256(1000));          // OK
token.Transfer(badActor, new UInt256(1000));      // Reverts: "transfer denied by policy"

Admin Transfer

All policy contracts support two-step admin transfer to prevent accidental lockout:

policy.TransferAdmin(newAdminAddr);  // Current admin proposes
policy.AcceptAdmin();                 // New admin accepts (must be called by pending admin)

Design Notes

  • Max 16 policies per token (PolicyEnforcer.MaxPolicies) -- prevents unbounded gas cost
  • Mint/burn bypass policies -- admin-only operations, matching ERC-20 convention
  • BST-4626 inherits BST-20 -- vault share policies propagate automatically
  • BST-1155 batch atomicity -- all policy checks run before any state mutations
  • Reentrancy safe -- policies can query token state (e.g. BalanceOf) via static-mode re-entrant callbacks (Context.IsStaticCall blocks writes)
  • Corrupted slot detection -- PolicyEnforcer reverts on empty policy slots instead of silently skipping
  • Jurisdiction whitelist mode -- unregistered addresses (no KYC) are denied in whitelist mode, allowed in blacklist mode

ContractRegistry Type IDs

All contract types are registered with ContractRegistry.CreateDefault() and identified by a 2-byte type ID in the deployment manifest ([0xBA, 0x5A][typeId BE][ctor args]).

Token Standards

Type ID Contract Description
0x0001 BST20Token Fungible token (ERC-20)
0x0002 BST721Token Non-fungible token (ERC-721)
0x0003 BST1155Token Multi-token (ERC-1155)
0x0004 BSTDIDRegistry Decentralized identity
0x0005 BST3525Token Semi-fungible token (ERC-3525)
0x0006 BST4626Vault Tokenized vault (ERC-4626)
0x0007 BSTVCRegistry Verifiable credentials (W3C VC)

Policy Contracts

Type ID Contract Description
0x0008 HoldingLimitPolicy Max balance per address per token
0x0009 LockupPolicy Time-based transfer lockup
0x000A JurisdictionPolicy Country whitelist/blacklist
0x000B SanctionsPolicy Admin-managed sanctions list

System Contracts

Type ID Contract Genesis Address
0x0100 WBSLT 0x...1001
0x0101 BNS 0x...1002
0x0102 Governance 0x...1003
0x0103 Escrow 0x...1004
0x0104 StakingPool 0x...1005
0x0105 SchemaRegistry 0x...1006
0x0106 IssuerRegistry 0x...1007
0x0107 BridgeETH 0x...1008

Dependencies

Package Purpose
Basalt.Crypto BLAKE3 hashing (SchemaRegistry schema ID derivation)

No dependency on the node or execution engine.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Basalt.Sdk.Contracts:

Package Downloads
Basalt.Sdk.Testing

Unit testing framework for Basalt smart contracts — in-memory test host with storage, events, and cross-contract call simulation

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.0 142 3/17/2026
0.2.0 107 2/22/2026
0.1.0 117 2/15/2026