Audited Contract Registry
Audited contract bytecode, ABI, and verification sources ship as the public
npm package
@upsideos/evm-rwa-artifacts.
Any client can install the package and check that an on-chain contract
matches the audited code. The ABIs and verification sources also ship as the
upsideos_evm_rwa_artifacts Ruby gem.
The first published release is EVM Security Token v5
(evm/comakery_security_token_v5/2026-09-17-quantstamp), pinned to source
commit 45b32eaeea1d96f1f64ef0d74796a5a80ec154ce (tag v2025-10-16).
Quantstamp audited this version. The audit report is available on request.
Install
npm install @upsideos/evm-rwa-artifacts
Package layout
| Export | Contents |
|---|---|
@upsideos/evm-rwa-artifacts/v5 | v5 artifacts (abi, bytecode) |
@upsideos/evm-rwa-artifacts/v5/manifest.json | Release record and hashes |
@upsideos/evm-rwa-artifacts/v5/artifacts/<Name>.json | ABI, creation code, runtime code, immutable slots |
@upsideos/evm-rwa-artifacts/v5/abis/<Name>.json | Per-contract ABI |
@upsideos/evm-rwa-artifacts/v5/verification-source-codes.json | solc standard-json input |
@upsideos/evm-rwa-artifacts/v5.1 | v5.1 artifacts |
@upsideos/evm-rwa-artifacts/recallable-payment | Recallable Payment artifacts |
Root of trust: an exact npm version (or git commit) plus the sha512
integrity in your lockfile. Public npm releases also carry Sigstore
provenance from the publish workflow in
upsideos/contract-artifacts.
Ruby
gem 'upsideos_evm_rwa_artifacts'
The gem carries the ABIs, the release manifests, and the verification sources, built from the same audited commit as the npm package. It ships no bytecode and no tooling, because a Ruby consumer reads contracts and verifies them but does not deploy them.
require 'upsideos_evm_rwa_artifacts'
UpsideosEvmRwaArtifacts.abi('v5', 'TransferRules')
UpsideosEvmRwaArtifacts.merged_abi('v5', 'RestrictedLockupToken')
UpsideosEvmRwaArtifacts.verification_source_codes_path('v5')
UpsideosEvmRwaArtifacts.commit('v5')
RubyGems trusted publishing signs each release to the workflow run that built it, the same OIDC model npm uses.
Manifest
The envelope is the same for EVM, Solana, and Sui. Only the build object
and the per-artifact code fields change. This release uses
build.kind = solc-standard-json.
runtimeCode.immutableReferences is required. Constructor-set immutables
(for example ERC2771Context.trustedForwarder) make each deployment's
eth_getCode output different. The verifier zeros those ranges before it
hashes.
callSurfaces holds the merged ABI. The token forwards unknown selectors
into its extensions, so a client that talks to the token address needs the
union of the token and extension ABIs, not the token ABI alone.
Verify a deployment on a block explorer
Explorer verification is tied to a deployed address, so it happens after
deployment. @upsideos/evm-explorer-verify submits the published bundle
with the right compiler version and constructor arguments:
npx evm-verify-explorer --release v5 --contract AccessControl \
--address 0x... --chain-id 84532 --api-key "$EXPLORER_API_KEY"
It also exports submitSourceVerification and checkVerificationStatus
for callers that run verification from a queue worker.
Client check without a compiler
const manifest = require('@upsideos/evm-rwa-artifacts/v5/manifest.json')
async function check(rpcUrl, address, name) {
const expected = manifest.artifacts.find(a => a.name === name)
const body = await fetch(rpcUrl, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'eth_getCode',
params: [address, 'latest'],
}),
}).then(r => r.json())
const hex = body.result.slice(2)
const bytes = new Uint8Array(hex.length / 2)
for (let i = 0; i < bytes.length; i++) {
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16)
}
for (const ranges of Object.values(expected.runtimeCode.immutableReferences || {})) {
for (const { start, length } of ranges) {
bytes.fill(0, start, start + length)
}
}
const digest = await crypto.subtle.digest('SHA-256', bytes)
const actual = [...new Uint8Array(digest)]
.map(b => b.toString(16).padStart(2, '0'))
.join('')
return actual === expected.runtimeCode.sha256
}
Client check with a compiler
- Load
verification-source-codes.json. - Check its canonical SHA-256 against
build.standardJson.sha256. - Compile with
solcLongVersionfrom the bundle (0.8.28+commit.7893614afor v5). - Compare creation bytecode to
artifacts/<Name>.json.
This is the full trustless path. It does not need the contracts git
repository because the bundle inlines every source
(metadata.useLiteralContent: true).
Creation-code path
Fetch the deployment transaction. The input prefix must match
creationCode. The suffix is the ABI-encoded constructor arguments. Decode
it with the published ABI.
Solana and Sui
The manifest schema already accepts solana-verifiable-build and
sui-move. Adapters for those families are not in this release.