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

# Overview

> Learn about how to interact with an ERC20 Variable Criteria Incentive using the SDK

The ERC20 Variable Criteria Incentive is a protocol incentive that allows for a variable distribution of native and ERC-20 assets, with each claim amount being determined dynamically at claim time depending on a value extracted from a provided transaction.

On Boost creation, a predetermined amount of the specified asset is transferred into this incentive from the associated budget.

<Warning>
  The One-Time Actions docs are under active development and will be subject to changes.
</Warning>

<CardGroup cols={3}>
  <Card title="Smart Contract" icon="file-contract" href="https://github.com/boostxyz/boost-protocol/blob/main/packages/evm/contracts/incentives/ERC20VariableCriteriaIncentive.sol">
    Read the smart contracts
  </Card>

  <Card title="Typedoc" icon="file-lines" href="https://sdk.boost.xyz/classes/ERC20VariableCriteriaIncentive.html">
    See technical documentation
  </Card>

  <Card title="SDK Implementation" icon="file-code" href="https://github.com/boostxyz/boost-protocol/blob/main/packages/sdk/src/Incentives/ERC20VariableCriteriaIncentive.ts">
    See the source
  </Card>
</CardGroup>

## Key Features

* Supports native assets as well as any ERC20
* Rewards dynamic at claim time, depending on the value of a field extracted from a transaction log or function argument.

<Info>
  Unlike budgets, allowlists, and validators, incentives cannot be re-used between multiple Boosts.
</Info>

### Create a new ERC20VariableCriteriaIncentive

<CodeGroup>
  ```ts index.ts theme={null}
  import { events as eventSelectors } from '@boostxyz/signatures/events'
  import { BoostCore } from '@boostxyz/sdk/BoostCore'
  import { selectors as eventSelectors } from "@boostxyz/signatures/events";
  import { config } from "./config";

  const core = new BoostCore({ config });

  await core.createBoost({
    maxParticipants: 10n,
    budget,
    action,
    allowList,
    incentives: [
      core.ERC20VariableCriteriaIncentive({
        asset: '0xERC20' || zeroAddress, // use zero address for native assets
        reward: parseEther('0.5'), // Amount to multiply a claim amount by, if 0n or 1 ether, user will be transferred the whole amount asserted at claim time.
        limit: parseEther('10'), // The total budget allocated to this incentive
        maxReward: parseEther('5'), // The maximum amount that can be claimed at a time, if the amount extracted from the transaction given the criteria is more than this value, then the claim value will be this max reward value.
        criteria: {
          criteriaType: SignatureType.EVENT,
          signature: eventSelectors[
            "Transfer(address indexed,address indexed,uint256 indexed)"
          ] as Hex, // Function selector for mint
          fieldIndex: 2, // Field index where the dynamic claim value resides
          targetContract: '0xERC721',
        }
      }),
    ],
  });
  ```

  ```ts config.ts theme={null}
  import { http, createConfig } from '@wagmi/core'
  import { mainnet, sepolia } from '@wagmi/core/chains'

  export const config = createConfig({
    chains: [mainnet, sepolia],
    transports: {
      [mainnet.id]: http(),
      [sepolia.id]: http(),
    },
  })
  ```
</CodeGroup>

### Get an existing ERC20VariableCriteriaIncentive

<CodeGroup>
  ```ts index.ts theme={null}
  // if an incentive address is known, directly construct it
  const incentive = core.ERC20VariableCriteriaIncentive("0xc55F719709bDad022B320E76f9DfF7e6F5680767")

  // or if you want a budget from a specific chain
  const incentiveOnBase = core.ERC20VariableCriteriaIncentive(
    "0xc55F719709bDad022B320E76f9DfF7e6F5680767",
    { chainId: 8453 }
  )

  // or accessible off of a a pre-exiting Boost
  const boost = await core.getBoost(0n)
  const incentive = boost.incentives.find(incentive => incentive instanceof ERC20VariableCriteriaIncentive)
  ```
</CodeGroup>

## Setting Up Incentive Criteria

The incentive criteria determines how the reward amount is extracted from transaction data. You can configure it to read values from either contract events or function calls.

### Criteria Configuration

The criteria object requires four fields:

* `criteriaType`: Either `SignatureType.EVENT` for event logs or `SignatureType.FUNC` for function calls
* `signature`: The event or function signature to match against
* `fieldIndex`: Which parameter in the event/function to extract the value from (0-based index)
* `targetContract`: The contract address to watch for the event/function

<Info>
  You can use the `@boostxyz/signatures` package to get pre-defined event signatures instead of using raw hex values. For example: `import { selectors } from '@boostxyz/signatures/events'`
</Info>

### Example: Event-based Criteria

Here's an example setting up criteria to extract an amount from a Transfer event:

```ts theme={null}
import { selectors } from '@boostxyz/signatures/events'
import { SignatureType } from '@boostxyz/sdk'

const criteria = {
  criteriaType: SignatureType.EVENT,
  // Use pre-defined signature for Transfer(address,address,uint256)
  signature: selectors['Transfer(address indexed,address indexed,uint256)'],
  fieldIndex: 2, // Extract amount from the third parameter
  targetContract: '0xTokenContract' // Contract to watch for events
}
```

### Example: Function-based Criteria

Here's an example setting up criteria to extract an amount from a mint function:

```ts theme={null}
import { selectors } from '@boostxyz/signatures/functions'
import { SignatureType } from '@boostxyz/sdk/claiming'

const criteria = {
  criteriaType: SignatureType.FUNC,
  // Use pre-defined signature for mint(uint256)
  signature: selectors['mint(uint256)'],
  fieldIndex: 0, // Extract amount from the first parameter (quantity)
  targetContract: '0xNFTContract' // Contract to watch for function calls
}
```

The extracted value will be used to calculate the reward amount, which is then capped by the `maxReward` parameter if necessary.

### Sign a claim amount

```ts theme={null}
// Get the index of the incentive to claim
const incentiveIndex = boost.incentives.findIndex(incentive => incentive instanceof ERC20VariableCriteriaIncentive)

// build claim data, signing a variable amount for the incentive
const allClaimData = boost.incentives.map(incentive => {
  if (incentive instanceof ERC20VariableCriteriaIncentive || incentive instanceof ERC20VariableCriteriaIncentive) {
    const rewardAmount = parseEther("1");
    return incentive.buildClaimData(rewardAmount);
  } else {
    return ''
  }
})

// Sign a valid transaction with the variable reward amount
const { data } = await axios.get('/signatures', {
  params: {
    boostId: `${chainId}:${boostCoreAddress}:${boost.id}`,
    txHash,
    claimData: allClaimData.join(',')
  }
});

// claim the ERC20VariableCriteriaIncentive
const { signature, incentiveId, claimant } = data.at(incentiveIndex);
await core.claimIncentive(
  boost.id,
  incentiveId,
  claimant,
  signature,
);
```
