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.
| Workflow | Artifact | Execution evidence |
|---|---|---|
Offline ZBL, zct-v1 | Binary ZCT v1 containing ZBC2 | Local ZBR replay receipt with fuel. Counter replay returns state 42 and 36 fuel. |
Native ZBX, zbx-program-v1 | Schema 1 JSON artifact with Program v1 | Signed 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.