# Subscription chain · Verify events across chains with ICCF · Learn Chromia

> The next step is the Subscription Chain. It needs two entities: account, which holds the account balance, and receipt, which records digital receipts for…

Source: https://chromia.com/learn/iccf-course/subscription-chain/

Verify events across chains with ICCFLesson 4 of 6

1. [01Confirm Events Across Blockchains](https://chromia.com/learn/iccf-course/introduction/)
2. [02Set up your project](https://chromia.com/learn/iccf-course/setup/)
3. [03System overview](https://chromia.com/learn/iccf-course/system-overview/)
4. [04Subscription chain](https://chromia.com/learn/iccf-course/subscription-chain/)
5. [05Digital warehouse chain](https://chromia.com/learn/iccf-course/digital-warehouse-chain/)
6. [06Testing the dapp](https://chromia.com/learn/iccf-course/manual-testing/)

[Learn](https://chromia.com/learn/)[Verify events across chains with ICCF](https://chromia.com/learn/iccf-course/)

04 / 06Intermediate

# Subscription chain

The next step is the Subscription Chain. It needs two entities: `account`, which holds the account balance, and `receipt`, which records digital receipts for logging. Start by configuring a new blockchain in `chromia.yml`.

yaml

```
blockchains:
  # ↓↓↓ Delete this code snippet ↓↓↓
  digital_warehouse_example:
    module: main
  # ↑↑↑ Delete this code snippet ↑↑↑

  # ↓↓↓ Add this code snippet ↓↓↓
  subscription_chain:
    module: subscription_chain
# ↑↑↑ Add this code snippet ↑↑↑
```

Then put the following code in `entities.rell` inside the `src/subscription_chain` directory:

src/subscription\_chain/entities.rell

```
entity account {
    key id: pubkey;
    mutable balance: integer = 10000;
}

@log
entity receipt {
    // We don't reference the account entity here since this entity may be removed
    account_id: pubkey;
    amount: integer;
    period;
    blockchain_rid: byte_array;
    index account_id, blockchain_rid;
}
```

An account is an entity with an ID and a mutable balance. To keep the example simple, every new account starts with 10,000 tokens.

note

Handle on-chain funds carefully. For real token management, use the FT token library.

The `receipt` entity carries the `@log` annotation, so its entries can never be changed once written. This immutability matters when you need a transparent record of monetary transactions. Each receipt points to its account through `account_id` rather than a direct reference to the `account` entity. That way, you can still delete an account if legal reasons require it.

A receipt stores the amount paid, the period purchased, and the blockchain RID (Resource IDentifier) of the Digital Warehouse Chain that the payment was meant for. With this information, the Warehouse Chain can confirm the payment and guard against the same payment being spent on more than one chain. An index on `account_id` and `blockchain_rid` speeds up queries.

## Account creation

In this example, an account is created on the fly the first time a user subscribes. Add the following function, which handles that, to `functions.rell` in the `src/subscription_chain` folder.

src/subscription\_chain/functions.rell

```
function get_or_create_account(id: pubkey) {
    require(op_context.is_signer(id));
    return account @? { id } ?: create account(id);
}
```

## Subscription

Subscribing is handled by an operation named `subscribe`. It takes the blockchain RID of the chain where the transaction will be confirmed, along with the `subscription` metadata.

src/subscription\_chain/operations.rell

```
operation subscribe(blockchain_rid: byte_array, subscription) {
    val account = get_or_create_account(subscription.account_id);
    val subscription_fee = period_price(subscription.period);
    require(account.balance >= subscription_fee, "Insufficient funds");
    account.balance-=subscription_fee;
    create receipt (
        account_id = subscription.account_id,
        subscription_fee,
        subscription.period,
        blockchain_rid
    );
}
```

The operation fetches the user's account or creates one if none exists, subtracts the cost from the balance, and writes a receipt.

## Queries

For monitoring, you will want to look up receipts by user or by transaction. To finish the dapp, add these queries to `queries.rell` in the `src/subscription_chain` directory.

src/subscription\_chain/queries.rell

```
query get_receipts(account_id: pubkey?, blockchain_rid: byte_array?, from: timestamp?)
    = (receipt, account) @* {
    if (account_id??) account.id == account_id else true,
    account.id == receipt.account_id,
    if (blockchain_rid??) .blockchain_rid == blockchain_rid else true,
    if (from??) .transaction.block.timestamp >= from else true
} (
    receipt_id = .transaction.tx_rid,
    account_id = account.id,
    period = .period,
    payment_amount = .amount,
    blockchain_rid = .blockchain_rid,
    timestamp = .transaction.block.timestamp
);
```

You can use this query to filter receipts by `account_id`, `blockchain_rid`, and `timestamp`.

## Unit test

Testing this blockchain takes little effort. Create a file called `subscription_chain_test.rell` in the `src/test` directory and paste in this code:

src/test/subscription\_chain\_test.rell

```
@test module;

import subscription_chain.{ subscribe, subscription, period, account, period_price, period, get_receipts };

val TEST_WAREHOUSE_CHAIN = x"ABAB";

function test_create_subscription() {

    rell.test.tx()
        .op(subscribe(TEST_WAREHOUSE_CHAIN, subscription(rell.test.pubkeys.alice, period.WEEK)))
        .sign(rell.test.keypairs.alice)
        .run();

    val test_account = account @? { rell.test.pubkeys.alice };

    assert_not_null(test_account);
    assert_equals(test_account.balance, 10000 - period_price(period.WEEK));
    val receipts = get_receipts(test_account.id, null, null);
    assert_equals(receipts.size(), 1);
    assert_equals(receipts[0].payment_amount, 30);
    assert_equals(receipts[0].blockchain_rid, TEST_WAREHOUSE_CHAIN);
}
```

You also need to extend `chromia.yml` with the following configuration:

chromia.yml

```
blockchains:
  subscription_chain:
    module: subscription_chain
    # ↓↓↓ Add this code snippet ↓↓↓
    test:
      modules:
        - test.subscription_chain_test
    # ↑↑↑ Add this code snippet ↑↑↑

# ↓↓↓ Delete this code snippet ↓↓↓
test:
  modules:
    - test
# ↑↑↑ Delete this code snippet ↑↑↑
```

The test subscribes the test user Alice and verifies that the resulting receipt has the expected amounts and target blockchain.

Run the test with:

text

```nolines
chr test
```

For reference, here is the project structure and the full chromia.yml file as they should look after these changes. Use them to check your work at this point in the course:

Project structure

text

```
digital_warehouse_example/
├── build/
├── src/
│   ├── lib/
│   ├── subscription_chain/
│   │   ├── entities.rell
│   │   ├── functions.rell
│   │   ├── module.rell
│   │   ├── operations.rell
│   │   └── queries.rell
│   ├── test/
│   │   └── subscription_chain_test.rell
│   └── main.rell
├── .gitignore
└── chromia.yml
```

Final version of the `chromia.yml` file

text

```
yaml title="chromia.yml"
blockchains:
  subscription_chain:
    module: subscription_chain
    test:
      modules:
        - test.subscription_chain_test
  digital_warehouse_chain:
    module: digital_warehouse_chain
    config:
      gtx:
        modules:
          - net.postchain.d1.iccf.IccfGTXModule
    moduleArgs:
      digital_warehouse_chain:
        warehouse_id: 1
    test:
      modules:
        - test.digital_warehouse_chain_test
compile:
  rellVersion: 0.14.9
database:
  schema: schema_digital_warehouse_example
libs:
  iccf:
    registry: https://gitlab.com/chromaway/core/directory-chain
    path: src/lib/iccf
    tagOrBranch: 1.87.0
    rid: x"9C359787B75927733034EA1CEE74EEC8829D2907E4FC94790B5E9ABE4396575D"
  iccf_test:
    registry: https://gitlab.com/chromaway/core/directory-chain
    path: src/lib/test/iccf
    tagOrBranch: 1.87.0
    rid: x"873D71557531E35E453587FA71C2D3CCB674F0EB49D18B30FA838C52C1155EB3"
```

Written for this site from Chromia’s public course. Code samples are the course’s own.

[← Previous**System overview**](https://chromia.com/learn/iccf-course/system-overview/)[Next →**Digital warehouse chain**](https://chromia.com/learn/iccf-course/digital-warehouse-chain/)

On this page

* [Account creation](#account-creation)
* [Subscription](#subscription)
* [Queries](#queries)
* [Unit test](#unit-test)
