Matrix logo

Financial Workflows

This layer connects the authenticated caller identity, the wallet rail, the on-chain service registry, and the manifest schema that describes each listing. It is the part of Deu...

Overview

This layer connects the authenticated caller identity, the wallet rail, the on-chain service registry, and the manifest schema that describes each listing. It is the part of Deus that turns a signed agent request into a validated service record, an on-chain registration, and a mirrored listing in the local store.

The code here is split across three concerns: request identity and trust boundaries in deus/internal/auth/auth.go, EVM and wallet transport in deus/internal/chain/*.go and deus/internal/wallet/client.go, and listing validation plus manifest hashing in deus/internal/registry/*.go and deus/pkg/manifest/*.go. The chain binding in deus/internal/chain/bindings/service_registry.go is the contract-facing core that the registry service uses to create, update, and observe service state on Paxeer chain 125.

Architecture Overview

Caller Authentication

Caller Identity Resolution

deus/internal/auth/auth.go

Caller is the authenticated agent identity passed through request context. Middleware extracts it from HTTP headers and either forwards the request with context attached or returns a JSON 401 response. ResolveRequest is the low-level header parser and is the only place that decides whether a request is treated as an agent bearer call or a dev-mode fallback.

Data shape

PropertyTypeDescription
DIDstringCaller DID resolved from the request.
WalletstringCaller wallet address forwarded from the request.
BearerstringBearer token preserved for downstream use.

Functions

MethodDescription
FromContextReads Caller from context.Context and reports whether it was present.
MiddlewareWraps an http.Handler and rejects unauthenticated requests with {"error":"unauthorized","message":"agent bearer required"}.
ResolveRequestParses Authorization, X-Caller-DID, and X-Caller-Wallet into a Caller.

Header behavior

HeaderBehavior
AuthorizationRequired bearer token in normal mode.
X-Caller-DIDOptional identity hint in dev mode and a fallback DID source when bearer auth is present.
X-Caller-WalletOptional wallet address copied into Caller.Wallet.

ResolveRequest accepts a Bearer token only when the Authorization header starts with Bearer . In dev mode, a missing bearer can still produce a Caller if X-Caller-DID is present, and a missing DID can fall back to the token itself when the token starts with did:. If no DID can be resolved, it fails before the request reaches the handler.

Chain Access

Chain Client

deus/internal/chain/client.go

Client wraps ethclient.Client and verifies that the connected RPC endpoint is on the expected chain. DefaultChainID is 125, and New can reject a connection if the remote chain ID does not match the expected value.

Data shape

PropertyTypeDescription
rpcURLrpcURLRPC endpoint used for the ethclient dial.
chainID*big.IntCached chain identifier returned by ChainID.
ethethUnderlying ethclient.Client.

Methods

MethodDescription
EthReturns the underlying ethclient.Client.
ChainIDReturns a copy of the configured chain ID.
PingIssues a lightweight BlockNumber RPC call.
CloseCloses the underlying RPC client if it exists.

Constructor dependencies

TypeDescription
context.ContextUsed for dialing and optional chain ID verification.
expectedChainID int64Expected EVM chain ID; verification is skipped when this is not positive.

New fails fast when rpcURL is empty, closes the RPC connection if the chain ID check fails, and preserves the configured chain ID even when verification is skipped.

Chain Client Checks

deus/internal/chain/client_test.go

TestBehavior
TestNewRequiresRPCURLVerifies that New rejects an empty RPC URL.
TestPingOptionalUses PAXEER_RPC_URL when present, constructs a client, and confirms Ping succeeds against a live endpoint.

On Chain Payer and Settlement

deus/internal/chain/payer.go

Payer is the chain-backed settlement executor. It holds the settler key, the chain client, the settlement anchor address, and ABI handles for the payment channel and settlement anchor contracts. It is the component that actually submits payout and settlement transactions after off-chain work has been accepted.

Data shapes

PropertyTypeDescription
paymentChannelABIconstMinimal ABI with payout, fundedWei, redeemedWei, and availableWei.
settlementAnchorABIconstMinimal ABI with anchor.
eth*ethclient.ClientRPC backend used for contract calls and transaction submission.
chainID*big.IntChain ID used to sign transactions.
key*ecdsa.PrivateKeySettler private key.
fromcommon.AddressOn-chain settler address derived from the private key.
anchorAddrcommon.AddressSettlement anchor contract address.
channelABIabi.ABIParsed payment channel ABI.
anchorABIabi.ABIParsed settlement anchor ABI.

Methods

MethodDescription
NewPayerBuilds a settlement payer from a chain client, settler key, and anchor address.
SettlerAddressReturns the derived on-chain settler address.
PayoutDeveloperSends payout to the escrowed payment channel and waits for a mined receipt.
AnchorSettlementSends anchor to record a settled batch root and waits for a mined receipt.
FundedWeiReads fundedWei from a payment channel contract and returns it as a decimal string.

Constructor dependencies

TypeDescription
*ClientSupplies the RPC client and chain ID.
settlerKeyHex stringHex-encoded private key used to sign settlement transactions.
anchorAddr stringSettlement anchor contract address.

NewPayer rejects a nil chain client, an empty anchor address, or an invalid private key. PayoutDeveloper also rejects the unset placeholder 0xescrow-dev, validates amountWei as base-10, submits payout, waits for mining, and confirms that the receipt status is successful. AnchorSettlement decodes the Merkle root with decodeRoot, verifies that it is exactly 32 bytes, and then submits anchor with the developer address, root, total value, and count.

Payment Streams Precompile

deus/internal/chain/precompiles.go

PaymentStreams is a calldata and read helper for the Paxeer precompile at 0x0000000000000000000000000000000000000906. It does not own transactions; it builds calldata for stream lifecycle operations and performs the accrued read against the precompile.

Data shapes

PropertyTypeDescription
PaymentStreamsAddrvarPrecompile address on chain 125.
paymentStreamsABIconstABI for open, settle, close, and accrued.
client*ClientChain client used for contract calls.
abiabi.ABIParsed precompile ABI.

Methods

MethodDescription
NewPaymentStreamsBuilds a precompile helper from a chain client.
EncodeOpenPacks calldata for open.
EncodeSettlePacks calldata for settle.
EncodeClosePacks calldata for close.
AccruedExecutes eth_call against the precompile and decodes the returned amount.

Constructor dependencies

TypeDescription
*ClientSupplies the RPC backend used by CallContract.

Accrued packs the accrued call, uses CallContract against PaymentStreamsAddr, and requires exactly one returned *big.Int. If decoding fails or the output shape does not match, it returns an explicit error.

Service Registry Binding

deus/internal/chain/bindings/service_registry.go

This generated binding is the contract surface used by the registry service to register listings, update them, and listen for contract events. ServiceRegistryMetaData carries the generated ABI JSON, and ServiceRegistryABI is the deprecated alias to ServiceRegistryMetaData.ABI.

Contract metadata values

ValueRole
ServiceRegistryMetaDataGenerated metadata wrapper containing ABI and constructor information.
ServiceRegistryABIDeprecated alias to the ABI string in ServiceRegistryMetaData.

Core wrapper types

TypeProperties
IServiceRegistryServiceId *big.Int, Owner common.Address, Payout common.Address, ManifestHash [32]byte, PricingHash [32]byte, Status uint8, Hosted bool, Confidential bool, RegisteredAt uint64, UpdatedAt uint64
ServiceRegistryEmbedded ServiceRegistryCaller, ServiceRegistryTransactor, ServiceRegistryFilterer
ServiceRegistryCallercontract *bind.BoundContract
ServiceRegistryTransactorcontract *bind.BoundContract
ServiceRegistryFilterercontract *bind.BoundContract
ServiceRegistrySessionContract *ServiceRegistry, CallOpts bind.CallOpts, TransactOpts bind.TransactOpts
ServiceRegistryCallerSessionContract *ServiceRegistryCaller, CallOpts bind.CallOpts
ServiceRegistryTransactorSessionContract *ServiceRegistryTransactor, TransactOpts bind.TransactOpts
ServiceRegistryRawContract *ServiceRegistry
ServiceRegistryCallerRawContract *ServiceRegistryCaller
ServiceRegistryTransactorRawContract *ServiceRegistryTransactor

Event payloads

TypeProperties
ServiceRegistryOwnerTransferredId *big.Int, From common.Address, To common.Address, Raw types.Log
ServiceRegistryPayoutChangedId *big.Int, Payout common.Address, Raw types.Log
ServiceRegistryServiceRegisteredId *big.Int, Owner common.Address, ManifestHash [32]byte, PricingHash [32]byte, Hosted bool, Confidential bool, Raw types.Log
ServiceRegistryServiceStatusChangedId *big.Int, Status uint8, Raw types.Log
ServiceRegistryServiceUpdatedId *big.Int, ManifestHash [32]byte, PricingHash [32]byte, Raw types.Log

Iterator types

TypeProperties
ServiceRegistryOwnerTransferredIteratorEvent *ServiceRegistryOwnerTransferred, contract *bind.BoundContract, event string, logs chan types.Log, sub ethereum.Subscription, done bool, fail error
ServiceRegistryPayoutChangedIteratorEvent *ServiceRegistryPayoutChanged, contract *bind.BoundContract, event string, logs chan types.Log, sub ethereum.Subscription, done bool, fail error
ServiceRegistryServiceRegisteredIteratorEvent *ServiceRegistryServiceRegistered, contract *bind.BoundContract, event string, logs chan types.Log, sub ethereum.Subscription, done bool, fail error
ServiceRegistryServiceStatusChangedIteratorEvent *ServiceRegistryServiceStatusChanged, contract *bind.BoundContract, event string, logs chan types.Log, sub ethereum.Subscription, done bool, fail error
ServiceRegistryServiceUpdatedIteratorEvent *ServiceRegistryServiceUpdated, contract *bind.BoundContract, event string, logs chan types.Log, sub ethereum.Subscription, done bool, fail error

Methods

MethodDescription
NewServiceRegistryBuilds a full read write filter binding for a deployed contract.
NewServiceRegistryCallerBuilds a read-only binding.
NewServiceRegistryTransactorBuilds a write-only binding.
NewServiceRegistryFiltererBuilds a log filter binding.
STATUSACTIVEReads the STATUS_ACTIVE constant.
STATUSDELISTEDReads the STATUS_DELISTED constant.
STATUSDRAFTReads the STATUS_DRAFT constant.
STATUSPAUSEDReads the STATUS_PAUSED constant.
GetServiceReads a full service tuple by id.
GovernorReads the governor address.
IsActiveReads whether a service is active.
NextIdReads the next service id.
OwnerOfReads the owner of a service id.
ServicesReads the service tuple from the public mapping.
ServicesByOwnerReads a service id by owner and index.
RegisterSends the register transaction.
SetPayoutSends the setPayout transaction.
SetStatusSends the setStatus transaction.
TransferOwnerSends the transferOwner transaction.
UpdateSends the update transaction.
FilterOwnerTransferredFilters historical OwnerTransferred logs.
WatchOwnerTransferredSubscribes to live OwnerTransferred logs.
ParseOwnerTransferredUnpacks a single OwnerTransferred log.
FilterPayoutChangedFilters historical PayoutChanged logs.
WatchPayoutChangedSubscribes to live PayoutChanged logs.
ParsePayoutChangedUnpacks a single PayoutChanged log.
FilterServiceRegisteredFilters historical ServiceRegistered logs.
WatchServiceRegisteredSubscribes to live ServiceRegistered logs.
ParseServiceRegisteredUnpacks a single ServiceRegistered log.
FilterServiceStatusChangedFilters historical ServiceStatusChanged logs.
WatchServiceStatusChangedSubscribes to live ServiceStatusChanged logs.
ParseServiceStatusChangedUnpacks a single ServiceStatusChanged log.
FilterServiceUpdatedFilters historical ServiceUpdated logs.
WatchServiceUpdatedSubscribes to live ServiceUpdated logs.
ParseServiceUpdatedUnpacks a single ServiceUpdated log.
CallRaw read-only call on ServiceRegistryRaw.
TransferRaw transfer on ServiceRegistryRaw and ServiceRegistryTransactorRaw.
TransactRaw write call on ServiceRegistryRaw and ServiceRegistryTransactorRaw.

The event watch methods use WatchLogs, wrap the stream in event.NewSubscription, and forward unpacked events into the sink channel until the sink, the quit channel, or sub.Err() ends the subscription. The iterator variants perform the same unpacking work for historical log scans and stop when Close unsubscribes the underlying subscription.

The generated ABI exposes the following contract errors: InvalidStatus, NotOwner, NotOwnerOrGovernor, ServiceNotFound, and ZeroAddress.

The read methods are also mirrored on ServiceRegistrySession and ServiceRegistryCallerSession with preset CallOpts, and the write methods are mirrored on ServiceRegistrySession and ServiceRegistryTransactorSession with preset TransactOpts.

Service Registry Orchestration

deus/internal/chain/registry.go

Registry is the chain transaction façade used by the higher-level registry service. It binds a deployed ServiceRegistry contract, signs transactions with the caller-provided private key, waits for receipts, and extracts the ServiceRegistered event that contains the on-chain service id.

Data shapes

PropertyTypeDescription
client*ethclient.ClientRPC client used for transaction submission and receipt waits.
contract*bindings.ServiceRegistryGenerated contract binding.
addresscommon.AddressDeployed contract address.
chainID*big.IntChain ID used to sign register transactions.
Payoutcommon.AddressPayout address sent to the contract from RegisterRequest.

Request and result shapes

TypeProperties
RegisterRequestPayout common.Address, ManifestHash [32]byte, PricingHash [32]byte, Hosted bool, Confidential bool, PrivateKeyHex string
RegisterResultChainServiceID uint64, TxHash string, BlockNumber uint64

Methods

MethodDescription
NewRegistryBinds a deployed ServiceRegistry at the supplied address.
AddressReturns the bound registry address.
RegisterSigns, sends, waits for mining, and extracts the new chain service id.
FilterRegisteredScans historical ServiceRegistered events from a starting block.

Constructor dependencies

TypeDescription
*ClientSupplies the RPC client and chain ID.
addr stringDeployed registry contract address.

Register trims an optional 0x prefix from PrivateKeyHex, constructs a keyed transactor, submits the transaction, waits for the receipt, and checks for ReceiptStatusSuccessful. After a successful receipt, it walks the logs from the registry address, parses the first ServiceRegistered event it can decode, and returns the chain service id, tx hash, and block number. If the event is absent, it returns chain: ServiceRegistered event not found.

FilterRegistered uses a bind.FilterOpts starting at fromBlock, requests all service and owner matches with nil filters, and collects the unpacked ServiceRegistryServiceRegistered values until the iterator finishes.

Chain Client Checks

deus/internal/chain/client_test.go

TestBehavior
TestNewRequiresRPCURLConfirms that an empty RPC URL is rejected before dialing.
TestPingOptionalReads PAXEER_RPC_URL, constructs a client, and exercises Ping against the live chain endpoint when configured.

Wallet Clients

Wallet HTTP Client

deus/internal/wallet/client.go

HTTPClient is the remote wallet transport. It forwards the caller bearer token to the wallet API, submits JSON bodies, maps HTTP 403 into PolicyDenied, and returns transaction hashes or stream identifiers for the spending rail. AuthorizeSpend is a configuration guard in this implementation; the actual policy enforcement happens on the money-moving call path when the wallet responds with 403.

Data shapes

PropertyTypeDescription
BaseURLstringWallet API base URL.
HTTP*http.ClientOptional custom HTTP client.
TxHashstringTransaction hash returned by the wallet.
StreamIDstringStream id returned by the wallet.
ErrorstringError code returned by the wallet API.
MessagestringHuman-readable error message returned by the wallet API.
CapWeistringDeclared spend cap from a forbidden wallet response.

Request and result shapes

TypeProperties
StreamOpenInputPayee string, RatePerSecondWei string, CapWei string, StopTime uint64, Token string
OpenStreamResultChainStreamID string, TxHash string
sendResponseTxHash string, StreamID string
walletErrorError string, Message string, CapWei string

Methods

MethodDescription
AuthorizeSpendPerforms the pre-flight wallet configuration check.
SendSends a direct native PAX transfer through /v1/agent/send.
OpenStreamOpens a PaymentStreams session through /v1/agent/precompiles/streams/open.
StreamSettleSettles a stream through /v1/agent/precompiles/streams/settle.
StreamCloseCloses a stream through /v1/agent/precompiles/streams/close.
ErrorReturns the formatted message for PolicyDenied.

Constructor and request dependencies

TypeDescription
bearer stringCaller bearer token forwarded from the gateway.
toAddress stringDestination address for direct sends.
amountWei stringTransfer amount in wei.
in StreamOpenInputStream open payload.

Every request sets Content-Type: application/json and Authorization: Bearer . do also caps the response body read to 1 MiB, maps 403 responses into PolicyDenied, and returns the parsed wallet response when the call succeeds. OpenStream sends stop_time only when it is greater than zero, and streamToken maps an empty token to the zero address string so native PAX streams do not require an explicit token address.

Dev client stub

PropertyTypeDescription
MaxPerCallWeistringOptional per-call allowance enforced by the stub.
Sends[]SendRecordRecorded direct transfers.
StreamOpens[]StreamOpenRecordRecorded stream opens.
StreamRefunds[]StreamRefundRecordRecorded stream close refunds.
streamSeqatomic.Uint64Synthetic stream id generator.
streamCapsmap[string]stringTracks funded cap by chain_stream_id.
TypeProperties
SendRecordTo string, AmountWei string
StreamOpenRecordPayee string, RatePerSecondWei string, CapWei string, ChainStreamID string, TxHash string
StreamRefundRecordChainStreamID string, RefundWei string, TxHash string

Methods

MethodDescription
AuthorizeSpendAllows spends up to MaxPerCallWei in dev mode.
SendRecords a synthetic send and returns a synthetic tx hash.
OpenStreamRecords a synthetic stream open and stores the funded cap.
StreamSettleReturns a synthetic stream settle tx hash.
StreamCloseRecords a refund and returns a synthetic stream close tx hash.

Wallet Client Checks

deus/internal/wallet/client_test.go

TestBehavior
TestHTTPClientSendReturnsTxHashVerifies the POST path, bearer header, JSON body, and tx_hash decoding for Send.
TestHTTPClientSendPolicyDeniedVerifies that HTTP 403 becomes PolicyDenied and preserves cap_wei.
TestHTTPClientSendRequiresConfigVerifies that Send rejects a missing BaseURL.

Registry Orchestration

Listing Service

deus/internal/registry/registry.go

Service is the orchestrator that creates draft listings, publishes them on chain, mirrors chain state back into the store, and optionally pushes raw listing payloads into a manifest indexer. It is the highest-level workflow in this section and ties together manifest validation, storage, chain registration, and discovery indexing.

Data shapes

PropertyTypeDescription
store*store.StoreBacking persistence layer for listings and related records.
registry*chain.RegistryChain registration façade used during publish.
indexer*indexer.IndexerIndex sync handle used after publishing.
embedIdxManifestIndexerOptional async manifest indexer hook.

Interface

MethodDescription
IndexServiceAccepts a service id and raw manifest JSON for discovery indexing.

Request and result shapes

TypeProperties
CreateInputManifest json.RawMessage, Owner string
CreateResultID string, Slug string, Status string, ManifestHash string, Validation ValidationResult
PublishInputServiceID string, Owner string, PrivateKeyHex string
PublishResultID string, ChainID uint64, Status string, ManifestHash string, TxHash string

Methods

MethodDescription
NewServiceWires the store, chain registry, and indexer into a listing service.
SetManifestIndexerRegisters the optional raw manifest indexer hook.
CreateValidates a manifest, inserts a draft service, and mirrors child rows.
PublishRegisters the service on chain and marks the mirrored service active.
GetReturns a stored service row by id.

Constructor dependencies

TypeDescription
*store.StorePersists services, endpoints, and pricing plans.
*chain.RegistryUsed to submit the on-chain register transaction.
*indexer.IndexerUsed to synchronize discovery state after publish.

Create validates the raw manifest bytes with manifest.ValidateBytes, then runs ValidateManifest and rejects manifests that fail schema or business rules. It normalizes the requested owner, verifies that it matches the manifest owner, hashes the manifest with manifest.Hash, creates or updates the developer record, inserts the draft service with status draft, and then calls syncChildren to persist endpoint and pricing rows. When embedIdx is present, it indexes the raw manifest after the draft row is inserted.

Publish loads the service row, looks up the developer wallet, and rejects the call when the provided owner does not match the stored wallet. It reparses and revalidates the stored manifest, requires an active deployment when Mode is hosted, computes both the manifest hash and pricing commitment hash, and sends the chain registration through chain.Registry.Register. After the transaction succeeds, it mirrors the chain service id and hashes back into the store, pushes the raw manifest into embedIdx when configured, and asks indexer.Sync to advance discovery from the mined block number.

The helper hexToBytes32 requires exactly 64 hexadecimal characters after 0x stripping, and syncChildren writes one endpoint row and one pricing row per manifest operation and pricing entry.

Registry Validation

deus/internal/registry/validate.go

ValidationResult is the structured validation outcome returned by CreateResult. It separates schema success from warnings, so a reachable listing can still surface a proxy URL warning without blocking the workflow.

Data shape

PropertyTypeDescription
OKboolOverall validation status.
Warnings[]stringNon-fatal validation warnings.
Errors[]stringFatal validation errors.

Functions

MethodDescription
ValidateManifestRuns schema validation and business rule checks against a manifest.
probeURLSends an HTTP HEAD request and treats 500-level responses as errors.

ValidateManifest always calls manifest.Validate first. When a manifest is in proxy mode and has a non-empty endpoint.proxy_url, it probes the URL with a HEAD request that times out after three seconds and appends a warning when the target is unreachable or returns a 500-level status. The warning does not prevent Create or Publish from continuing if the manifest is otherwise valid.

Manifest Model and Schema

Manifest Model

deus/pkg/manifest/manifest.go

Manifest is the machine-readable description of a Deus service. It captures identity, ownership, deployment mode, operations, pricing, routing hints, SLA targets, and optional attestation metadata. Operation, Pricing, Endpoint, and SLA are the nested data shapes that carry the per-operation and service-level details.

Data shapes

PropertyTypeDescription
SchemaVersionstringManifest schema version.
SlugstringService slug.
KindstringService kind.
DisplayNamestringHuman-readable name.
SummarystringShort description.
DescriptionstringOptional extended description.
Tags[]stringOptional tag list.
OwnerstringOwner identity.
PayoutAddressstringPayout wallet address.
ModestringDeployment mode.
ConfidentialboolConfidential listing flag.
Operations[]OperationCallable operations.
Pricing[]PricingPricing entries.
Endpoint*EndpointOptional routing hints.
SLA*SLAOptional service level targets.
AttestationanyOptional attestation payload.

Nested shapes

TypeProperties
OperationName string, Method string, InputSchema map[string]any, OutputSchema map[string]any, TimeoutMS int, MaxResponseBytes int
PricingOperation string, Model string, Unit string, PriceWei string, MinChargeWei string
EndpointProxyURL string
SLATargetUptimeBPS int, P99LatencyMS int

Canonicalization and Hashing

deus/pkg/manifest/canonical.go

CanonicalVersion is 1. CanonicalJSON marshals the manifest, rehydrates it into generic JSON, sorts object keys recursively, and returns stable UTF-8 bytes for hashing. Hash returns keccak256(canonical_json(manifest)) as a hex string, and PricingCommitmentHash hashes only schema_version and pricing after applying the same recursive sort logic.

Functions

MethodDescription
CanonicalJSONProduces stable canonical JSON bytes.
HashComputes the manifest hash from canonical JSON.
PricingCommitmentHashComputes the pricing-only commitment hash.
sortValueRecursively sorts JSON object keys and arrays.
ParseParses JSON into Manifest with unknown fields rejected.

Parse uses DisallowUnknownFields, so extra keys are rejected before schema validation runs.

Schema Validation

deus/pkg/manifest/schema.go

compiledSchema compiles the embedded schema once with sync.Once. Validate marshals the manifest, validates it against the embedded schema, and then enforces business rules that the schema alone cannot express. ValidateBytes is the raw JSON entrypoint used by the listing service.

Functions

MethodDescription
compiledSchemaCompiles and caches the embedded schema.
ValidateValidates a manifest against the schema and business rules.
ValidateBytesParses and validates raw JSON bytes.
validateBusinessRulesEnforces listing rules that complement the schema.

Business rules

RuleBehavior
Proxy mode requires a proxy URLmode == "proxy" requires endpoint.proxy_url.
Pricing must map to an operationEach pricing row must reference an existing operation name.
Pricing must be positiveA pricing row cannot have both price_wei and min_charge_wei equal to 0.
Attestation requires confidentialityattestation is only accepted when confidential is true.

Embedded Schema Contract

deus/pkg/manifest/schema.json

KeyConstraint
titleDeusServiceManifest
typeobject
additionalPropertiesfalse
requiredschema_version, slug, kind, display_name, summary, owner, payout_address, mode, operations, pricing
schema_versionMust equal 1.
kinddata or agent.
modeproxy or hosted.
operationsArray with at least one item; each item requires name, method, input_schema, output_schema.
pricingArray with at least one item; each item requires operation, model, unit, price_wei, min_charge_wei.
endpoint.proxy_urlOptional URI field, required by business rules when mode is proxy.
slaOptional object with target_uptime_bps and p99_latency_ms.
attestationobject or null.

Manifest Validation Checks

deus/pkg/manifest/manifest_test.go

TestBehavior
TestValidateFixtureLoads a fixture manifest, validates it, hashes it, and verifies canonical JSON stability.
TestValidateRejectsProxyWithoutURLConfirms that proxy mode without endpoint.proxy_url fails validation.

State Management

The workflow moves through a small set of explicit states that are proven in code.

State or signalWhere it appearsMeaning
draftCreate in deus/internal/registry/registry.goNewly inserted listing before chain registration.
activePublish in deus/internal/registry/registry.goListing mirrored after successful chain registration.
STATUS_ACTIVEdeus/internal/chain/bindings/service_registry.goContract constant returned by the generated binding.
STATUS_DRAFTdeus/internal/chain/bindings/service_registry.goContract constant returned by the generated binding.
STATUS_PAUSEDdeus/internal/chain/bindings/service_registry.goContract constant returned by the generated binding.
STATUS_DELISTEDdeus/internal/chain/bindings/service_registry.goContract constant returned by the generated binding.
ValidationResult.OKdeus/internal/registry/validate.goBoolean validation gate for create and publish.

The local mirror writes draft rows first, then transitions them to active only after the chain receipt is mined and the ServiceRegistered event is decoded. The contract binding reflects the same lifecycle via event emissions and status constants.

Error Handling

Each layer wraps its own failure mode and keeps the context specific:

  • auth.Middleware returns a fixed 401 JSON body for missing or invalid agent bearer credentials.
  • chain.New wraps dial failures, chain ID fetch failures, and chain ID mismatches with chain: prefixes.
  • Payer validates the private key, anchor address, payout amount, and Merkle root before broadcasting.
  • chain.Registry.Register reports private key parsing errors, transactor setup errors, transaction submission errors, receipt wait errors, and missing ServiceRegistered events separately.
  • HTTPClient.do maps wallet 403 responses into PolicyDenied so the caller can see cap_wei, while other 4xx and 5xx responses become formatted transport errors.
  • ValidateManifest returns structured ValidationResult data, and the listing service decides whether that result is fatal.

Integration Points

  • deus/internal/auth/auth.go supplies Caller to downstream services through request context.
  • deus/internal/registry/registry.go consumes manifest.ValidateBytes, manifest.Validate, manifest.Hash, and manifest.PricingCommitmentHash.
  • deus/internal/registry/registry.go depends on chain.Registry for on-chain registration and on the store for draft and active mirrors.
  • deus/internal/wallet/client.go forwards the caller bearer token to the wallet rail and interprets policy denials from the wallet API.
  • deus/internal/chain/registry.go bridges the higher-level registry service to deus/internal/chain/bindings/service_registry.go.
  • deus/internal/chain/precompiles.go and deus/internal/chain/payer.go cover stream and settlement side effects that sit outside the listing mirror.

Request Flows

Create and Publish a Listing

Wallet Spend and Stream Rails