Experimental · v0.5.0-preview.5

Build and deploy ZBL contracts

Replay an offline ZCT or compile and deploy native ZBX Program v1 through signed v2 on a local or private devnet.

WorkflowArtifactExecution evidence
Offline ZBL, zct-v1Binary ZCT v1 containing ZBC2Local ZBR replay receipt with fuel. Counter replay returns state 42 and 36 fuel.
Native ZBX, zbx-program-v1Schema 1 JSON artifact with Program v1Signed transaction v2, admitted by authenticated RPC, then a finalized validator receipt with gas, events and state root.

Run an offline replay

The browser Contract Playground compiles single-file ZBL source to offline ZCT. Its share link contains source in the URL fragment. Use the matching CLI to save and independently verify a local receipt.

zebvix contract --target zct-v1 build counter.zct
zebvix contract receipt counter.zct counter.receipt.json 40 2 -1 1
zebvix contract verify-receipt counter.zct counter.receipt.json

Run these commands in the SDK's examples/local-contract project, using fresh output names. See the offline receipt guide for the trust boundary. Local replay, ZBR fuel, and the offline V3 journal profile provide separate evidence from live validator finality.

Compile and inspect a native artifact

On Windows x64, use the SDK candidate and the matching reviewed ZBX executable from the same local handoff. Make the required loader dependencies available through the trusted toolchain. The SDK checks the executable size and SHA-256 before it starts the CLI, checks its version, and reports the selected chain commit and CLI digest in the verification JSON.

Use a fresh working directory. Set $Sdk and $Zbx to the absolute executable paths and $Source to the reviewed native payment_vault.native.zbl file from the SDK examples. Native ZBX uses its existing brace-delimited contract grammar.

$env:ZEBVIX_ZBX_CLI = $Zbx
$target = @('contract', '--target', 'zbx-program-v1')

function Invoke-Checked([string]$Exe, [string[]]$Arguments) {
    $result = & $Exe @Arguments
    if ($LASTEXITCODE -ne 0) { throw "Command failed with exit $LASTEXITCODE" }
    $result
}

Invoke-Checked $Sdk ($target + @('compile', '--source', $Source, '--out', 'vault.artifact.json'))
$verified = Invoke-Checked $Sdk ($target + @('inspect', '--source', $Source, '--artifact', 'vault.artifact.json')) | ConvertFrom-Json
$verified | Select-Object commit, cli_sha256, artifact_sha256, verification

Deploy, fund and upgrade on a local or private devnet

Set $RpcConfig, $WalletProfile, $ChainId and $Genesis from the independently approved TLS devnet configuration. Set $Wallet to the existing funded operator wallet name. Use the native wallet prompt and the approved RPC token file through ZBX_API_TOKEN_FILE. Use a fresh 32-byte contract ID.

$ContractId = [Convert]::ToHexString([Security.Cryptography.RandomNumberGenerator]::GetBytes(32)).ToLowerInvariant()
$network = @('--config', $RpcConfig, '--chain-id', "$ChainId", '--genesis', $Genesis, '--id', $ContractId)
$builder = @('--profile', $WalletProfile, '--from', $Wallet)
$native = @('--profile', $WalletProfile, '--config', $RpcConfig, '--output', 'json')

function Submit-Reviewed([string]$Label) {
    $unsigned = "$Label.unsigned.json"
    $signedFile = "$Label.signed.json"
    $signed = Invoke-Checked $Zbx ($native + @('tx', 'sign', '--wallet', $Wallet, '--file', $unsigned, '--out', $signedFile)) | ConvertFrom-Json
    $admission = Invoke-Checked $Zbx ($native + @('tx', 'broadcast', '--file', $signedFile)) | ConvertFrom-Json
    if ($admission.outcome -ne 'accepted') { throw 'Transaction admission failed' }
    Write-Host "Accepted into queue $($signed.id)"
    for ($i = 0; $i -lt 30; $i++) {
        $finalized = Invoke-Checked $Zbx ($native + @('tx', 'receipt', '--hash', $signed.id)) | ConvertFrom-Json
        if ($null -ne $finalized) {
            if (!$finalized.receipt.success) { throw "Finalized failure $($finalized.receipt.error)" }
            return $finalized
        }
        Start-Sleep -Seconds 3
    }
    throw "Receipt pending for $($signed.id)"
}

Invoke-Checked $Sdk ($target + @('deploy') + $network + $builder + @('--source', $Source, '--artifact', 'vault.artifact.json', '--out', 'deploy.unsigned.json'))
$deployment = Submit-Reviewed 'deploy'
$contract = Invoke-Checked $Sdk ($target + @('get') + $network) | ConvertFrom-Json
$contract.result

Confirm the finalized owner and artifact ID before funding. An accepted broadcast acknowledges queue admission. The finalized receipt separately reports success or execution failure and carries gas, fee and event data.

Invoke-Checked $Sdk ($target + @('call') + $network + $builder + @('--value', '100', '--out', 'fund.unsigned.json'))
$funded = Submit-Reviewed 'fund'

# Set $ReplacementSource to your independently reviewed replacement source.
Invoke-Checked $Sdk ($target + @('compile', '--source', $ReplacementSource, '--out', 'vault-upgrade.artifact.json'))
Invoke-Checked $Sdk ($target + @('inspect', '--source', $ReplacementSource, '--artifact', 'vault-upgrade.artifact.json'))
$contract = Invoke-Checked $Sdk ($target + @('get') + $network) | ConvertFrom-Json
$version = [string]$contract.result.contract.version
Invoke-Checked $Sdk ($target + @('upgrade') + $network + $builder + @('--expected-version', $version, '--source', $ReplacementSource, '--artifact', 'vault-upgrade.artifact.json', '--out', 'upgrade.unsigned.json'))
$upgraded = Submit-Reviewed 'upgrade'

The fixture pays a fixed amount to a demonstration address. Use it only on the disposable chain. Wait for each transaction to finalize before building the next one. See production readiness for qualification scope.