Skip to content
LogoLogo

Migrating from v1

A call-by-call map from nautilus v1 to v2

nautilus v2 keeps the builder pattern but sits on a different stack: @oceanprotocol/lib 9.x instead of 3.4.6, ethers v6 instead of v5, ocean-node instead of Aquarius and Provider, and DDO v5 instead of v4.1.0.

This is a call-by-call map. If something is not listed, it did not change.

1. Dependencies

"@oceanprotocol/lib": "3.4.6", 
"ethers": "^5.7.2"
"@oceanprotocol/lib": "^9.2.1", 
"ethers": "^6.17.0"

@oceanprotocol/lib re-exports only the v4 DDO type. The DDO v5 types — AssetV5, ServiceV5, MetadataV5 and the rest — are exported by @deltadao/nautilus itself, so you do not need a direct @oceanprotocol/ddo-js dependency:

import type { AssetV5, MetadataV5, ServiceV5 } from '@deltadao/nautilus'

ocean.js 9.2.1 still nests an older ddo-js under @oceanprotocol/lib for its own internals. It is harmless and needs no override.

ddo-js 1.0.0 also makes credentials mandatory on the asset and on every service. The builders always emit one ({} when no access rules are set), so this only affects DDOs you assemble or patch by hand — see Validation.

2. Setting up

ethers v6 removed the providers namespace.

import { Wallet, providers } from 'ethers'
const provider = new providers.JsonRpcProvider('https://rpc.dev.pontus-x.eu') 
import { JsonRpcProvider, Wallet } from 'ethers'
const provider = new JsonRpcProvider('https://rpc.dev.pontus-x.eu') 
 
const signer = new Wallet('0x…', provider)

Nautilus.create now takes an options object rather than a bare Partial<Config>:

const nautilus = await Nautilus.create(signer, { providerUri: '…' }) 
const nautilus = await Nautilus.create(signer, { 
  config: { oceanNodeUri: 'https://node.example.org' } 
}) 

Config fields

v1v2
metadataCacheUrioceanNodeUri
providerUrioceanNodeUri
subgraphUriremoved — pricing comes from chain reads
—escrow, accessListFactory, sdk: 'evm' | 'oasis'

ConfigHelper ships Pontus-X devnet (chain 32456). For any other deltaDAO network, pass the addresses explicitly in config.

3. Reading assets

const asset = await nautilus.getAquariusAsset(did) 
const assets = await nautilus.getAquariusAssets(dids) 
const asset = await nautilus.getAsset(did) 
const assets = await nautilus.getAssets(dids) 

DDO v5 nests everything under credentialSubject, so read through the helpers rather than indexing into the document — that way a future DDO v6 does not break your code:

asset.metadata.name 
asset.services[0].id 
asset.nft.owner 
asset.nft.state 
import { getMetadata, getServices, getOwner, getLifecycleState } from '@deltadao/nautilus'
getMetadata(asset).name 
getServices(asset)[0].id 
getOwner(asset) 
getLifecycleState(asset) 

New: nautilus.query(searchQuery) and nautilus.waitForIndexer(did, txid?).

4. Publishing

Publishing now signs the DDO as a verifiable credential and stores it off chain, writing only a {remote} pointer. So it needs a remote store — see remote stores and signing:

import { NodePersistentRemoteStore, Nautilus } from '@deltadao/nautilus'
 
const bootstrap = await Nautilus.create(signer, { config })
 
const nautilus = await Nautilus.create(signer, {
  config,
  // Uses the node's own storage — no external IPFS needed.
  remoteStore: new NodePersistentRemoteStore(bootstrap.getNodeClient())
})

Or with IPFS:

import { IpfsRemoteStore } from '@deltadao/nautilus'
 
remoteStore: new IpfsRemoteStore({ uploadUrl: 'http://127.0.0.1:5001/api/v0/add' })

publish() gained options and returns a little more:

const { nftAddress, services, ddo, setMetadataTxReceipt } = await nautilus.publish(asset) 
const { nftAddress, services, ddo, setMetadataTxReceipt, credential, indexed } =
  await nautilus.publish(asset, { waitForIndexer: true }) 

It is also cheaper: the NFT, its first datatoken and that service's pricing are created in one transaction rather than three.

5. AssetBuilder

Every v1 method still exists. Three behave differently, and there are new ones.

new AssetBuilder(aquariusAsset) 
new AssetBuilder(asset)   // the asset from nautilus.getAsset()
v1v2
setDescription('text')same call; wrapped into a language-tagged object
setLicense('url')same call; wrapped into { name }. Also accepts a License object
addLinks(['url'])same call; projected into v5's { label: url } map. Also accepts a map
setContentLanguage('en')repurposed: no longer a metadata field, it now sets the @language/@direction tag applied to every language-tagged value

Now required: setProvidedBy(). DDO v5's schema requires providedBy, and build() rejects a new asset without it (alongside name and type).

New:

builder
  .setDisplayTitle('A nicer title')
  .addAttachments([{ name: 'terms', fileType: 'pdf', sha256: '…', mirrors: [] }])
  .setIssuer('did:web:example.org')
  .addCredentialAccessList(CredentialListTypes.ALLOW, { chainId: 32456, accessList: '0x…' })
  .addRequestCredentials(CredentialListTypes.ALLOW, [
    { type: 'VerifiableId', format: 'jwt_vc_json' }
  ])
  .setVcPolicies(CredentialListTypes.ALLOW, ['signature', 'not-before'])
  .setVpPolicies(CredentialListTypes.ALLOW, [{ policy: 'minimum-credentials', args: '1' }])
  .setCredentialMatchRules({ match_allow: 'all', match_deny: 'any' })

Also fixed: reset() now returns to the loaded asset in edit mode rather than emptying the builder, and NFT defaults no longer leak between assets built in the same process.

6. ServiceBuilder

new ServiceBuilder({ aquariusAsset, serviceId }) 
new ServiceBuilder({ asset, serviceId }) 

File types changed, because ocean-node changed what it can read:

v1 FileTypesv2
URLURL — but the object is now UrlFileObject
IPFSIPFS — { type, hash }
ARWEAVEARWEAVE — { type, transactionId }
GRAPHQLremoved
SMARTCONTRACTremoved
—S3, FTP, NODE_PERSISTENT_STORAGE (new)

setName() is effectively required now (v5 requires Service.name); build() defaults it rather than failing.

addTrustedAlgorithms() finally honours serviceIds, because v5's PublisherTrustedAlgorithms carries a required serviceId:

builder.addTrustedAlgorithms([{ did: 'did:ope:…', serviceIds: ['service-a', 'service-b'] }])

New: setState(), setDisplayName(), setDataSchema(), setInputSchema(), setOutputSchema(), and per-service gating via addCredentialAddresses() / addRequestCredentials().

7. ConsumerParameterBuilder

Two v1 workarounds are gone, because v5 fixed what forced them:

builder.setType('select').addOption({ eu: 'Europe' })
// v4 emitted options as a JSON string
// v5 emits a structured array
 
builder.setDefault(false)
// v4 coerced this to the string "false"
// v5 keeps the boolean

8. Access

const url: string = await nautilus.access({ assetDid }) 
const { url, transferTxId, reusedOrder } = await nautilus.access({ assetDid }) 

If the service is credential-gated, nautilus resolves the policy before placing any order — so a failed presentation costs nothing. See §10.

9. Compute

Compute changed the most, because C2D v2 is a different model.

const job = await nautilus.compute({ dataset, algorithm, additionalDatasets }) 
const { jobs, environment, orders } = await nautilus.compute({ 
  dataset, algorithm, additionalDatasets, 
  computeEnv: env.id,          // pick deliberately; v1 silently used [0]
  resources: [{ id: 'cpu', amount: 2 }, { id: 'ram', amount: 2 }], 
  paymentToken: '0x…', 
  maxJobDuration: 3600
}) 
  • Environments: nautilus.getComputeEnvironments() lists them with their resources, limits and per-chain fees. resources and paymentToken default from the environment.
  • Escrow: paid jobs lock funds in the Escrow contract. nautilus funds and authorises it from what the node quotes.
  • Free compute: nautilus.freeCompute({ dataset, algorithm }) — no order, no escrow, no payment token. Requires an environment exposing free.
  • Output: ComputeOutput is now { remoteStorage?, encryption? }. The old publishAlgorithmLog / publishOutput flags no longer exist.
  • Renamed: getComputeEnviroment (sic) → getComputeEnvironments.
  • New: nautilus.streamComputeResult(), nautilus.getComputeLogs().

stopCompute and getComputeStatus no longer need a providerUri; they default to the node the instance is configured with.

10. Credential-gated assets

New in v2. Configure a credential provider and nautilus handles the whole presentation exchange — initiate, fetch the presentation definition, authenticate to the wallet, match credentials, present, and carry the resulting session into the download or compute call.

import { Nautilus, WaltIdCredentialProvider } from '@deltadao/nautilus'
 
const bootstrap = await Nautilus.create(signer, { config })
 
const nautilus = await Nautilus.create(signer, {
  config,
  credentials: new WaltIdCredentialProvider(bootstrap.getNodeClient(), {
    walletApi: 'https://wallet.example.org'
    // Headless by default: all matching credentials, the wallet's first DID.
    // Supply onSelectCredentials / onSelectDid to drive a UI instead.
  })
})
 
// Nothing else changes at the call site.
const { url } = await nautilus.access({ assetDid: 'did:ope:…' })

See credential-gated assets for the full picture.

11. Validation

New in v2, and worth using: DDO validation is entirely local, so it costs nothing and it names the failing field.

import { validate } from '@deltadao/nautilus'
 
const { valid, errors } = await validate(ddo)
// errors: { providedBy: ['Less than 1 values'] }

publish() and edit() run this automatically before spending gas. See validation.

12. Removed

The full removal table
RemovedReplacement
utils/aquarius.ts, utils/provider.tsOceanNodeClient
utils/subgraph/*, getAccessDetailschain reads — getPricingInfo, getOrderPrice
AccessDetails, AssetWithAccessDetails, OrderPriceAndFeesPricingInfo, OrderPrice
local ComputeAsset / ComputeAlgorithmComputeAssetRef / ComputeAlgorithmRef
transformAquariusAssetToDDOunnecessary — v5 keeps indexed data separate
getComputeEnviromentgetComputeEnvironments