Conditions Service

The ARN Client API allows you to check if certain conditions are true or not. These conditions can be related to the state of a blockchain (token gating) or project's data. The condition service is exposed through the arnClient.condition property.

Low-level API

The low-level API provides a flexible way to execute conditions. You can use the arnClient.condition.execute(conditionPayload) method to execute a condition based on the specified conditionPayload.

arnClient.**condition**

Higher-level Convenience APIs

The ARN Client also provides higher-level convenience APIs that serve as shortcuts to the low-level API. These APIs are specialized for performing specific types of condition checks. The available convenience APIs are:

  • condition.erc721: Used to perform NFT checks on the blockchain, such as ownership verification.
  • condition.arianee: Used to perform Arianee NFT checks, such as tag verification.
  • condition.user: Used to perform checks on the connected user, such as membership in a project's data list.

You can refer to the following pages for more information on each convenience API:

Please refer to the respective documentation for each convenience API to understand how to use them and the available methods.

📌

The above description focuses on the low-level API. For more specific information on the higher-level convenience APIs, please refer to the provided links.

Configuration

The configuration of the condition service is specified through the condition section of the ARN Client configuration.

Its properties are:

  • execute: the configuration for executing conditions
    • **url**: the URL to connect to when accessing your project conditions. You can leave this empty to use the defaults of your ARN Server conditions endpoint or specify a (relative or absolute) custom URL.

Token gating

Conditions can be checked against:

  • Standard NFTs
  • Arianee NFTs
  • Arianee Token Gating As a Service
  • User/wallet lists

Aside token gating, a condition can also be checked against the result of any HTTP call.

Standard NFTs

Since 1.38.0, you can check if the connected user owns some regular ERC721 NFT minted by a given contract.

For instance:

const minBalance = 1;  // At least one NFT
const nftOwnershipCondition = new **HasERC721Condition**({
  name: 'ownsAtLeastOneOfMyNFTs',
  chainId: 1, // Ethereum
  contractAddress: '0x776d77485578e703131b66ef50b1d77f225cc478',
  minBalance
});
const result = await arnClient.condition.execute({and: [nftOwnershipCondition]});
if (result.success) {
  console.log(`The user owns at least ${minBalance} NFT of the required collection`);
} else {
  console.log(`The user doesn't own enough NFT of the required collection`);
}

Note that is is also possible to keep the details of the check stored on the server side, provided you set the required options in conditions data associated with the relevant condition name:

const nftOwnershipCondition = new HasERC721Condition({**name**: 'serverSideOwnsAtLeastOneOfMyNFTs'});
const result = await arnClient.condition.execute({and: [nftOwnershipCondition]});
if (result.success) {
  console.log(`The user owns at least 1 NFT of the required collection`);
} else {
  console.log(`The user doesn't own any NFT of the required collection`);
}

💡

This API has a arnClient.condition.erc721.isOwnedFrom(contract) shortcut in the ARN Client ERC-721 Condition API.

Arianee NFTs

The client conditions API features the HasArianeeSmartAssetCondition to test Arianee’s specific NFT features (such as NFT tags) as part of a global condition check.

For instance:

const myTagsCondition = new HasArianeeSmartAssetCondition({
  tags: ['myTag1', 'myTag2']
});
const result = await arnClient.condition.execute({and: [myTagsCondition]});
if (result.success) {
  console.log(`The user has NFTs with all expected tags`);
} else {
  console.log(`The user doesn't have a NFT with all expected tags`);
}

💡

  • This API has a arnClient.condition.arianee.[hasNftWithTag](https://www.notion.so/ARN-Client-NFT-API-475b6d3044424aa7be8b9ffc3aec9631?pvs=21)s(tags) shortcut in the ARN Client Arianee Condition API.
  • Should you want to check tags to display some sections of HTML conditionally, consider using the arn-if-has alternative.

Token Gating Rules

Another way of checking on-chain conditions is to use the Token Gating API. This allows to check for on-chain conditions and has its own conditions syntax. Dig deeper into Strategies Definition and Strategies Combinations.

As most ARN conditions, they can be expressed on the client side:

const mySpkzCondition = new SpkzCondition([
  strategies: {
    name: 'erc-20-balance-of',
    params: {
      minBalance: '11',
      tokens: [
        {
          chainId: '1',
          networkId: '1', 
          address: '0xedf6568618a00c6f0908bf7758a16f76b6e04af9',
        },
      ],
    },
  },
]);
const result = await arnClient.condition.execute({and: [mySpkzCondition]});
if (result.success) {
  console.log(`The user has a at least 11 tokens`);
} else {
  console.log(`The user does not have enough tokens`);
}

or on the server side by just mentioning the name, provided you defined associated strategies in the project’s condition data:

const mySpkzCondition = new SpkzCondition({ name: 'myServerSpkzRule' });
const result = await arnClient.condition.execute({and: [mySpkzCondition]});
if (result.success) {
  console.log(`The user owns at least 11 tokens`);
} else {
  console.log(`The user does not own enough tokens`);
}

💡

This API has a arnClient.condition.arianee.[isSpkzVerified](https://arianee.github.io/arn/packages/arn-client/docs/interfaces/ArnArianeeNftConditionService.html#isSpkzVerified)(name | strategies) shortcut in the ARN Client Arianee Condition API.

Lists

Lists are defined on the server side:

  • Their data location must be specified in the ARN Server configuration.
  • Their data must comply with a list data structure.

The client conditions allow you to check them using their symbolic names.

For instance:

const isListedCondition = new **IsWhitelistedCondition**({name: 'isInMyList'});
const result = await arnClient.condition.execute({and: [isListedCondition]});
if (result.success) {
  console.log(`The user is in the list`);
} else {
  console.log(`The user is not part of the required list(s)`);
}

💡

This API has a arnClient.condition.user.isListedIn(lists) shortcut in the ARN Client User Condition API.

HTTP checks

Since 1.44.0, you can check if some HTTP request returns an expected response.

For instance:

const myHttpCondition = new **MatchHttpResponseCondition**({
  name: 'myHttpCheck',
  request: {
    url: 'https://dummyjson.com/users/1',
    method: 'GET',
  },
  response: {
    status: 200,
    jsonPath: {
      path: '$.firstName',
      value: 'Terry'
    }
  }
});
const result = await arnClient.condition.execute({and: [myHttpCondition]});
if (result.success) {
  console.log(`The user's firstname is Terry as expected`);
} else {
  console.log(`The user's firstname is not Terry`);
}

💡

This API has a arnClient.condition.http.requestReturns(req, res) shortcut in the ARN Client HTTP Condition API.

Optimizing conditions

Caching

Checking conditions will typically issue HTTP calls to the ARN Server hosting your project configuration.

Should you agree to assume that there is no need to double check à condition before a number of milliseconds, you might want to avoid those calls by not asking the same question twice for some amount of time or a web page loading for instance.

While you could manage such caching by yourself, this is also a service which can be provided though an ArnConditionContext.

To benefit from this, all conditions APIs can be previously set in such a context using the inContext() api. This will ensure next calls will cache the execution result, so that HTTP requests will be issued only if not fetched already:

class MyPage {

  myContext = new **ArnConditionContext**();
  myConditionPayload: ArnConditionsPayload = { ... };

  /**
   * 1st call will issue an HTTP request,
   * but next calls will not as the results for myConditionPayload are cached.
   */
  myCheck() {
    const result = await service
			.**inContext**(myContext)
			.execute(myConditionPayload);
  }
}

Note that the context’s cache can be cleared using arnConditionContext.cache.invalidate().

💡

Using the cache of a ArnConditionContext usually requires that you do not issue parallel requests, in order for subsequent requests to benefit from the results of previous ones. Otherwise parallel request might miss most of the cached results that will be stored too late.

Composing

As mentioned above, condition APIs have shortcuts in the ARN Client NFT API, so you might wonder what are the benefits of using the more sophisticated condition API.

A case where where the condition API is more performant than the NFT API is when you want to go beyond simple cases (only checking tags, only checking whitelists, etc.) but want to check a condition that is made of heterogenous operands. For instance:

const isInListCondition = new IsWhitelistedCondition({
   name: 'isInMyBothLists',
   whitelist: ['myList1', 'myList2'],
});
const hasTagCondition = new HasArianeeSmartAssetCondition({
  name: 'hasMyTags',
  tags: ['myTag1', 'myTag2'],
});
const myConditionPayload: ArnConditionsPayload = {
   and: [**hasTagCondition, isInListCondition**],
};
const result = await arnClient.condition.execute(myConditionPayload);

Such a check will issue 1 single HTTP call (if not cached) to check the combination of those conditions (whitelisted + has tags), whereas using the NFT API would issue 2 independent request to perform the same job.