This guide will demonstrate how to add the Forte Rules Engine to an existing project. Let’s get started!

NOTE: This guide was developed in a MacOS environment, some modification may be necessary to suit a Linux/Windows environment.

Environment Prerequisites

This guide assumes the following tools are installed and configured correctly. Please see each tool’s installation instructions for more details:

Install Dependencies

You will need to add both the Forte Rules Engine solidity package and the typescript SDK to your project. This guide also expects dotenv and @types/node. Install them via the command below.

npm install @thrackle-io/forte-rules-engine @thrackle-io/forte-rules-engine-sdk dotenv @types/node

Update your remappings.txt or foundry.toml to include the path to the Forte Rules Engine.

@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@thrackle-io/forte-rules-engine/=node_modules/@thrackle-io/forte-rules-engine

Choosing a Network

You can work with any EVM chain that the Forte Rules Engine is deployed to for your project. Check the current list of available networks here.

Working locally with an Anvil chain is also supported. To do so, fork an existing network where the protocol is deployed.

anvil --fork-url https://sepolia.base.org

You need to keep the anvil instance running in a separate tab from subsequent commands (or use a CLI tool like screen).

The rest of this guide assumes you’re working locally. If working with a live testnet or mainnet, make the relevant changes in your .env file.

Set Up Environment

Add the values for the following items to your existing environment file (or create a new .env file if necessary).

RPC_URL - The RPC endpoint to utilize when interacting with an EVM chain. This can be set to point to any testnet/mainnet RPC.

# local anvil rpc url, change this if working on a live testnet or mainnet
RPC_URL=http://127.0.0.1:8545

PRIV_KEY - The private key for the account that will be performing the actions outlined in this guide. This is defaulted to a widely known default Anvil account for the purposes of this guide. It is recommended that this be updated prior to deploying to any testnet or mainnet.

# deployer wallet private key - example below is an option for local anvil development
PRIV_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

RULES_ENGINE_ADDRESS - The address of the deployed Rules Engine instance on the target RPC’s chain. This is defaulted to the address where the Rules Engine is deployed on Base Sepolia. For additional chain locations, please see the supported networks page.

# address of the rules engine on the network you're targeting, value below is for base sepolia
RULES_ENGINE_ADDRESS=0xdaEba4085114A08CDB45383B113d65b72eb1aAd7

Once you are satisfied with the above configurations open a new terminal window (separate from the running anvil instance) and ensure the variables are exported in your local shell with the following command:

source .env

Configure Your Contract for Rules

Integrating the Rules Engine into your project is very simple. The SDK provides tooling to automatically generate a modifiers file and can even update the local copy of your contract to utilize them.

First, let’s define a basic policy with a single rule. Create a file named policy.json and add the content in the tab below.

Next, create a file named rulesSDK.ts and the content in the corresponding tab below. This script will be used throughout the guide.

{
  "Policy": "Test Policy",
  "ForeignCalls": [],
  "Trackers": [],
  "RulesJSON": [
    {
      "condition": "amount > 10000",
      "positiveEffects": ["emit TransferSuccessful"],
      "negativeEffects": ["revert(\"Transfer amount must be > 10,000\")"],
      "functionSignature": "transfer(address recipient, uint256 amount)",
      "encodedValues": "address recipient, uint256 amount"
    }
  ]
}

To register this policy with the Rules Engine, run the command below:

npx tsx rulesSDK.ts setupPolicy policy.json

You should see a message at the end of this output similar to:

Policy '1' created successfully.

Export that Policy ID for use later in this guide.

export POLICY_ID=<YOUR_POLICY_ID>

Next, you need to generate and apply the modifiers that will hook your function into the Rules Engine.

npx tsx rulesSDK.ts injectModifiers policy.json src/RulesEngineIntegration.sol src/TokenExample.sol

This will create two new files in your project, src/RulesEngineIntegration.sol and diff.diff. It will also update the existing TokenExample.sol file by adding the modifiers to the function(s) which you want to add rules to. In this example we added a rule to the transfer function, so that is where a modifier will be added.

The example repository extends Open Zeppelin’s ERC20 contract.

To be able to add rules to the transfer function via the SDK, you will need to override this function in your token contract. This will enable the SDK to locate the function signature and complete the configuration.

You can see how the example repo accomplishes this here: https://github.com/thrackle-io/fre-integrate-guide/blob/main/src/TokenExample.sol#L11

The diff.diff file will show exactly what was changed in the TokenExample.sol file for your reference.

Deploy Your Contract

Now you can deploy your contract using your normal workflow. For those following along with the example repo, you can deploy the TokenExample contract with the included script file.

forge script script/TokenExample.s.sol --ffi --broadcast -vvv --non-interactive --rpc-url $RPC_URL --private-key $PRIV_KEY

After deployment completes, take note of the contract address and export the address in your local terminal for subsequent testing.

export CONTRACT_ADDRESS=<0xYourContractAddress>

Next, you need to call the setRulesEngineAddress on your contract. This function is part of the abstract RulesEngineClient contract that your contract should be extending.

Here is the command you need to run to set the rules engine address:

cast send $CONTRACT_ADDRESS "setRulesEngineAddress(address)" $RULES_ENGINE_ADDRESS --rpc-url $RPC_URL --private-key $PRIV_KEY

Apply Your Policy

In setupPolicy step above you registered a policy with the Forte Rules Engine and received back a Policy ID. Now you need to apply that policy to the TokenExample contract that was just deployed.

npx tsx rulesSDK.ts applyPolicy $POLICY_ID $CONTRACT_ADDRESS

Test Your Rules

Success Condition

cast send $CONTRACT_ADDRESS "transfer(address,uint256)" 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 10001 --rpc-url $RPC_URL --private-key $PRIV_KEY

This will result in a successful transaction.

Failure Condition

cast send $CONTRACT_ADDRESS "transfer(address,uint256)" 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 9999 --rpc-url $RPC_URL --private-key $PRIV_KEY

You should receive a revert with the text execution reverted: Transfer amount must be > 10,000 within the response.

Conclusion

Well done! In just a few minutes you’ve installed the SDK, created and added custom modifiers to your smart contract, and registered a policy and rule within the Forte Rules Engine to control transfer amounts on your token contract!

Continue through these guides to learn how to build more sophisticated rules for your project.