> ## Documentation Index
> Fetch the complete documentation index at: https://thrackle.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Airdrop Lockup

> Setting token lockup timeframes based on NFT possession

The scenario for this rule example is that an application has users that hold an NFT in their wallet associated with the project. A fungible token release is coming and includes an allocation to airdrop some of the fungible tokens to the existing NFT holders.

There will be three different token lockup periods depending on when the NFT was obtained, which are:

* Early Adopter
* Loyal Backer
* New Ally

These categories will be defined in the rules engine as [Tags](/v1/tags/overview). In this example, the tags will represent how long the wallet has been a supporter, but you can use tags for any arbitrary category you desire.

The rule that will be leveraged for this example is the [Account Min/Max Token Balance](/v1/rules/account-min-max-token-balance) rule, which relies on these tags to determine whether or not the tagged account can transfer their tokens (based on defined minimum required balance).

## Get Started

This guide requires that you've already deployed the client contracts and is written with the expectation you'll be working from a locally cloned copy of the Forte Rules Engine. Check the [Installation Guide](/guides/installation) and [Deploy App Manager Guide](/guides/client/deploy-app-manager) for more info.

## Preparation

You will need to create the rule and then register and activate it for your deployed application manager. The command below relies on some environment variables being available in your shell. Refer to the [environment variables guide](/guides/client/environment-variables) for more info.

### Determine the Tags

The `addAccountMinMaxTokenBalance` function that you must call requires that you first determine the `bytes32` values of your tag names. You can do this with the cast command built into foundry like so:

```bash
cast from-utf8 "Early Adopter" | cast to-bytes32
cast from-utf8 "Loyal Backer" | cast to-bytes32
cast from-utf8 "New Ally" | cast to-bytes32
```

The resulting `bytes32` values are:

```bash
# Early Adopter
0x4561726c792041646f7074657200000000000000000000000000000000000000
# Loyal Backer
0x4c6f79616c204261636b65720000000000000000000000000000000000000000
# New Ally
0x4e657720416c6c79000000000000000000000000000000000000000000000000
```

### Decide the Minimum Balance per Tag

You can define a distinct minimum token balance for each tag type, which works well for the use case here. Since the ERC-20 token default includes 18 decimals, you must take this into account when setting up the minimums.

| Tag Name      | Token Allocation |                    With all Decimals |
| ------------- | ---------------: | -----------------------------------: |
| Early Adopter |            1,000 | 1\_000\_000\_000\_000\_000\_000\_000 |
| Loyal Backer  |              500 |    500\_000\_000\_000\_000\_000\_000 |
| New Ally      |              100 |    100\_000\_000\_000\_000\_000\_000 |

<Tip>
  If you wanted to airdrop the same amount to each token holder, regardless of
  tag type, then it would make sense to define the same minimum balance for each
  tag type. To acheive this, you'd pass an array with the same value three times
  to the `min` argument of the create function instead of three distinct values.
</Tip>

### Define the Hold Times

Next, you need to decide the hold times associated with each tag. These values are defined in hours. The guide will proceed with the following values:

| Tag Name      | Hold Time | Value in hours |
| ------------- | :-------: | -------------: |
| Early Adopter |  30 days  |            720 |
| Loyal Backer  |  60 days  |          1,440 |
| New Ally      |  90 days  |          2,160 |

With these values figured out, you're ready to add the rule!

## Add the Rule to the Protocol

You will need to call the `addAccountMinMaxTokenBalance` function to create this rule, which requires the following arguments:

```solidity
address _appManagerAddr,
bytes32[] calldata _accountTypes,
uint256[] calldata _min,
uint256[] calldata _max,
uint16[] calldata _periods,
uint64 _startTime
```

The above sections have determined the `_accountTypes` (tags), `_min`, and `_periods` values to be used in the function call. You should already know the `_appManagerAddr` and have it defined in your `.env` file. The `$RULE_ADMIN_KEY` is simply the private key of a wallet that has been granted the [rule administrator](/v1/permissions/admin-roles#rule-admin) privilege in your application.

Since this example rule is only about setting a minimum required balance you can pass an array of the max `uint256` value for the `_max` argument. Finally, the protocol will accept `0` for the `_startTime` argument.

The command you need to run, with all of this in mind is outlined below:

```bash
cast send $RULE_PROCESSOR_DIAMOND \
    --private-key $RULE_ADMIN_KEY \
    --rpc-url $ETH_RPC_URL \
    "addAccountMinMaxTokenBalance(address,bytes32[],uint256[],uint256[],uint16[],uint64)" \
    $APPLICATION_APP_MANAGER \
    "[0x4561726c792041646f7074657200000000000000000000000000000000000000, 0x4c6f79616c204261636b65720000000000000000000000000000000000000000, 0x4e657720416c6c79000000000000000000000000000000000000000000000000]" \
    "[1000000000000000000000,500000000000000000000,100000000000000000000]" \
    "[115792089237316195423570985008687907853269984665640564039457584007913129639935,115792089237316195423570985008687907853269984665640564039457584007913129639935,115792089237316195423570985008687907853269984665640564039457584007913129639935]" \
    "[720,1440,2160]" \
    0
```

The output from that command should include a `blockNumber`, which can then be used to determine the rule ID that was assigned. First, check the output to determine the `blockNumber` and then export it as an environment variable like so:

```bash
export BLOCK_NUMBER=<block_number>
```

Then you can run this command to determine the assigned rule ID:

```bash
cast logs --from-block $BLOCK_NUMBER --address $RULE_PROCESSOR_DIAMOND
```

The last value in the returned `topics` array will contain the hex encoded value of the assigned rule ID.

<Accordion title="See an example">
  Here is a live example of a command you can run to help illustrate the point:

  The block number includes a transaction on Base Sepolia where this type of rule was created.

  ```bash
  cast logs --from-block 19573634 --address 0x8fe43b3bcf8410b913dd1c84dc8af28daafd9777
  ```

  Note the highlighted line below. That is the hex encoded value for Rule ID number 1.

  ```bash Output Example {10}
    address: 0x8Fe43b3bCF8410B913dD1C84DC8af28DAAFD9777
    blockHash: 0x29a60a62088b1ec3538c595e60b32abe4f097155e6d1dfed7fb554d471ee06be
    blockNumber: 19573634
    data: 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034561726c792041646f70746572000000000000000000000000000000000000004c6f79616c204261636b657200000000000000000000000000000000000000004e657720416c6c79000000000000000000000000000000000000000000000000
    logIndex: 52
    removed: false
    topics: [
          0xc8c31d1b3fae743175dd37c3ed86aca4d193c9fcd5732cc172fbd4e9bc170e8a
          0x4143434f554e545f4d494e5f4d41585f544f4b454e5f42414c414e4345000000
          0x0000000000000000000000000000000000000000000000000000000000000001
    ]
    transactionHash: 0x837ddb7565a3760bafaa0537ab12d4ca326dd0f6dd6a38482182cb67b5216e78
    transactionIndex: 27
  ```
</Accordion>

What you've accomplished so far is to register this new rule with the main processor diamond on the blockchain network your application is running on. Now you must add this rule to your application manager.

<Note>
  Rules are re-usable in the protocol. For example, if the rule parameters
  defined above exactly matched the rule that you wanted to implement and your
  application is on Base Sepolia you could actually skip the above and simply
  register this existing rule ID with your application. That is unlikely, but it
  does enable you to create a well defined rule and then apply it to multiple
  tokens within your application once it exists.
</Note>

## Add the Rule to Your Application

Now that the rule is registered in the protocol you can add it to your specific application.

In this step, you only need to define the [action types](/v1/rules/action-types) that you want the rule to be active for. Because of the way the rule was defined above, it only makes sense to apply it to `burn`, `sell`, and `transfer`, which are designated with `[0,2,4]`.

Before calling the below command, make sure you have the environment variables available in your shell:

```bash
# determined when you configure your token handler
# see: /guides/client/deploy-token-handlers
APPLICATION_ERC20_HANDLER_ADDRESS
# private key of an account with rule admin privilege
RULE_ADMIN_KEY
# RPC URL to direct the command to
ETH_RPC_URL
# determined above
RULEID
```

```bash
cast send $APPLICATION_ERC20_HANDLER_ADDRESS \
    --private-key $RULE_ADMIN_KEY \
    --rpc-url $ETH_RPC_URL \
    "setAccountMinMaxTokenBalanceId(uint8[],uint32)" \
    "[0,2,4]" \
    $RULEID
```

## Add Tags to Accounts

Finally, before you actually airdrop the token allocations to the existing NFT holders, you'll need to add a tag to them so the protocol properly limits that wallet's ability to transfer the airdropped tokens.

Consider an account with the public address `0x1234abcd...` in your application that should be assigned the "Early Adopter" tag. Here is the command you would run:

```bash
cast send $APPLICATION_APP_MANAGER \
    --private-key $APP_ADMIN_PRIVATE_KEY \
    "addTag(address,bytes32)" \
    0x1234abcd... 0x4561726c792041646f7074657200000000000000000000000000000000000000
```

<Note>
  Obviously, the address `0x1234abcd...` is an incomplete and example address.
  You must use the full address of a wallet related to a user of your project.
  The `0x4561726c792041646f707465720000...` value after that represents the
  `bytes32` value of the "Early Adopter" tag, which was determined above.
</Note>

The entire process here would involve using a script to programmatically assign tags to the appropriate accounts in your application followed up by confirming those tags are correctly set to ensure the airdropped tokens are locked up per the expected rules.

## Wrapping Up

You should now understand at a high level the specific steps required to enable this type of rule in your application. This guide purposefully did not cover the generalized steps of how you'd actually distribute the tokens after the rules are configured.

Lastly, this particular guide is only one example that illustrates one way you can leverage tag based rules to enforce minimum token balances for a specified period of time based on arbitrarily defined categories.

Let this be an inspiration for even more sophisticated use cases!

If you have questions about this guide and how the Forte Rules Engine can enable compliance and incentive alignment in your application [send us a message](https://www.forte.io/contact-us/) to talk more!
