Skip to content

Manifests: Calls

The calls section declares contract-to-contract dependencies. It is the caller-side allowlist for nested calls. If contract A wants to call contract B, contract A's manifest must name contract B and the target methods.

calls is about dependency declaration. It does not by itself authorize the target method. The target contract must also allow the caller contract principal in the target method's invoke.allow policy.

Shape

json
{
  "calls": [
    {
      "contractId": "contract-report-index",
      "methods": ["indexReport"],
      "requiredBuckets": [
        {
          "bucketId": "bucket-reports",
          "access": ["bucket:read_metadata"],
          "availability": "metadata"
        }
      ]
    }
  ]
}

Fields:

FieldMeaning
contractIdTarget contract instance id.
methodsTarget method names this contract may call.
requiredBucketsBucket requirements associated with the outbound edge.

An empty calls array means the contract is not expected to call other contracts.

Caller And Target Manifests

The caller contract declares the outbound edge:

json
{
  "name": "report-store",
  "version": "0.1.0",
  "runtime": "wasm-assemblyscript-v1",
  "exports": {
    "methods": {
      "saveReport": {
        "entrypoint": "saveReport",
        "invoke": { "allow": [{ "principalType": "anyUser" }] },
        "buckets": []
      }
    }
  },
  "calls": [
    {
      "contractId": "contract-report-index",
      "methods": ["indexReport"],
      "requiredBuckets": []
    }
  ]
}

The target method allows the caller contract:

json
{
  "name": "report-index",
  "version": "0.1.0",
  "runtime": "wasm-assemblyscript-v1",
  "exports": {
    "methods": {
      "indexReport": {
        "entrypoint": "indexReport",
        "invoke": {
          "allow": [
            { "principalType": "contract", "principalId": "contract-report-store" }
          ]
        },
        "buckets": []
      }
    }
  }
}

Both sides matter. If the caller does not declare the edge, the nested call is undeclared. If the target method does not allow the caller contract, the nested call is unauthorized.

Target invoke.allow

For a C2C-only target method, the narrowest pattern is an exact contract principal:

json
{
  "invoke": {
    "allow": [
      { "principalType": "contract", "principalId": "contract-report-store" }
    ]
  }
}

This matches only the contract actor whose contract id is contract-report-store.

invoke.allow is not contract-only. The manifest schema supports:

json
{ "principalType": "anyUser" }
json
{ "principalType": "anyContract" }
json
{ "principalType": "any" }
json
{ "principalType": "system" }
json
{ "principalType": "user", "principalId": "user-admin" }
json
{ "principalType": "organization", "principalId": "org-noos" }
json
{ "principalType": "contract", "principalId": "contract-report-store" }

anyContract allows any deployed contract caller and is useful only for reviewed extension points. any allows both authenticated users and deployed contracts; packaging and validation tooling warn when it appears in a method policy.

Organization-Scoped Allows

An organization rule:

json
{
  "invoke": {
    "allow": [
      { "principalType": "organization", "principalId": "org-noos" }
    ]
  }
}

allows callers whose resolved organizationId is org-noos. In the current matcher, that includes user, node, and contract actors from the organization. Use this only when broad organization-level access is intentional.

It is not equivalent to "all contracts in this organization." If you need only specific contracts, list exact contract principals. If you need a reviewed aggregation point for many contracts, publish a facade/router contract and allow that contract id.

What anyUser Means

anyUser allows user callers. It does not allow contract callers:

json
{
  "invoke": {
    "allow": [
      { "principalType": "anyUser" }
    ]
  }
}

Do not use anyUser for a method intended to be called by contracts. For C2C, use explicit contract principals, anyContract for reviewed open contract extension points, or an intentionally broad organization rule.

What any Means

any allows either caller class:

json
{
  "invoke": {
    "allow": [
      { "principalType": "any" }
    ]
  }
}

Use any only when a method is intentionally public to both authenticated users and contracts. It is broader than anyUser, so tooling warns before packaging.

contractId

contractId is the deployed target contract instance id, not the target package name. This makes C2C dependencies explicit and environment-specific.

If you deploy a replacement target contract, update the caller manifest and publish a new caller package/version. Do not silently redirect a dependency by changing package metadata.

methods

methods is the list of target method names this contract may call:

json
{
  "methods": ["indexReport", "removeReport"]
}

The list must contain at least one method. Keep it narrow. Declaring a target contract does not imply permission to call every method on that target.

requiredBuckets

requiredBuckets declares bucket requirements associated with the outbound edge:

json
{
  "requiredBuckets": [
    {
      "bucketId": "bucket-reports",
      "access": ["bucket:read_metadata"],
      "availability": "metadata"
    }
  ]
}

Use this when the nested call depends on a bucket policy or local availability condition that reviewers and readiness checks should understand. The same bucket permission and availability meanings from Methods apply here.

Authorization And Readiness

A nested call must satisfy:

  • caller contract manifest declares the outbound edge;
  • target contract exists and is active;
  • target method exists;
  • target method invoke.allow allows the immediate caller actor;
  • bucket requirements and permissions are satisfied;
  • runtime, fuel, depth, and readiness checks pass.

The root signed caller is still important for bucket authorization and audit, but the immediate target invocation policy sees the caller contract principal. See Authorization.

Design Guidance

  • Keep C2C graphs small.
  • Avoid cycles unless they are explicitly reviewed and tested.
  • Use exact contract principals for target methods intended only for one caller contract.
  • Use anyContract only for target methods intentionally open to all deployed contracts.
  • Avoid anyUser for methods intended for C2C; it does not match contract callers.
  • Treat any as a broad public surface for both users and contracts.
  • Treat organization as broad access for users, nodes, and contracts in that organization.
  • Version caller contracts when target ids or target method names change.
  • Treat C2C dependencies as production dependencies during deactivation review.

Common Failures

FailureTypical causeFix
Outbound call not declaredCaller manifest lacks the target contract/method edge.Add the edge and publish a new caller version.
Target invoke unauthorizedTarget method does not allow the caller contract principal.Update the target method policy and publish a compatible target version.
Target method missingTarget manifest does not expose the method.Call the correct method or publish the target with the method.
Target deactivatedTarget contract is inactive.Move caller to a replacement target.
Bucket permission missingCaller, caller contract, target contract, or bucket requirements do not line up.Repair bucket access rules or manifest declarations.
anyUser used for C2CanyUser matches user callers, not contract callers.Use an exact contract principal, anyContract, or an intentional organization rule.
organization used expecting only contractsOrganization rules also match users and nodes with the same organizationId.Use explicit contract ids or a facade/router contract.
Need "all contracts"The method is a reviewed contract extension point.Use anyContract, or list contracts explicitly when the caller set should be bounded.
any warning appearsMethod allows both users and contracts.Switch to anyUser, anyContract, or a narrower principal unless the broad surface is intentional.

Next Steps

Audience-first NOOSChain documentation.