# "Recipe" — Steps in series

Recipes combine Steps into functional, complex actions. Most integrations will require 1-2 Recipes, and a number of Steps for each Recipe. Steps are generic building blocks, making them multi-purpose and reusable for various Recipes. Upon execution (`recipe.getRecipeOutput(recipeInput)`), the Cookbook automatically sandwiches the Recipe's transactions inside of [Unshield](https://docs.railgun.org/wiki/learn/unshielding-tokens) and [Shield](https://docs.railgun.org/wiki/learn/shielding-tokens) calls, calculating the associated fees with each Step, and providing the developer with a formatted list of Steps, their outputs, and the final array of [populated transactions](https://docs.ethers.org/v5/api/utils/transactions/).

As an example, a simple 0x Exchange Swap call has a pre-requisite: the Sell Token must be approved for spending by the 0x contract. So, the [0x Swap Recipe](https://github.com/Railgun-Community/cookbook/blob/main/src/recipes/swap/zero-x-swap-recipe.ts) has two Steps: (1) Approve sell token, (2) Swap sell token for buy token. The full Recipe uses a Step called [ApproveERC20SpenderStep](https://github.com/Railgun-Community/cookbook/blob/main/src/steps/token/erc20/approve-erc20-spender-step.ts), which is a common Step among most integrations.

> Note that each Recipe must assume a clean slate – since it's executed in a public setting (the RAILGUN Relay Adapt Contract), developers should assume that the Relay Adapt contract does not have approval to spend tokens with any token contract. This is why the [ApproveERC20SpenderStep](https://github.com/Railgun-Community/cookbook/blob/main/src/steps/token/erc20/approve-erc20-spender-step.ts) is a basic requirement for nearly every Recipe.

**Annotated Example:** Beefy Vault Deposit

```typescript
export class BeefyDepositRecipe extends Recipe {
  // Simple name and description.
  readonly config = {
    name: 'Beefy Vault Deposit',
    description:
      'Auto-approves and deposits tokens into a yield-bearing Beefy Vault.',
  };

  // Private variable passed into the constructor.
  protected readonly vaultID: string;

  // Recipe constructors should contain details about the enclosed tokens 
  // (ERC20 or NFTs), but they should not contain specific amounts.
  // Input amounts are passed into `getInternalSteps()`, calculated for each
  // run based on prior Steps (which typically include Unshield and its Fees).
  constructor(vaultID: string) {
    super();
    this.vaultID = vaultID;
  }

  // A required implementation for all Recipes, which designates the networks
  // where the recipe is possible.
  // Switch statements highly recommended here.
  protected supportsNetwork(networkName: NetworkName): boolean {
    return BeefyAPI.supportsNetwork(networkName);
  }

  // This async call returns the steps to build this recipe.
  // These steps will be housed inside of a cross-contract call, sandwiched
  // by Unshield and Shield steps. 
  // The firstInternalStepInput contains the network details and erc20 amounts 
  // (adjusted for fees) that will be passed into the first Step of this Recipe.
  // Most Recipes will calculate amounts (for fees - or expected output values) 
  // which depend on the input amounts.
  protected async getInternalSteps(
    firstInternalStepInput: StepInput,
  ): Promise<Step[]> {
    const { networkName } = firstInternalStepInput;

    // Async Beefy API call to get Vault contract addresses and current rates.
    const vault = await BeefyAPI.getBeefyVaultForID(this.vaultID, networkName);
    const spender = vault.vaultContractAddress;
    
    // ERC20 token to approve before Beefy Deposit.
    const depositERC20Info: RecipeERC20Info = {
      tokenAddress: vault.depositERC20Address,
      decimals: vault.depositERC20Decimals,
    };
    
    // Two Steps in this Recipe - (1) Approval then (2) Deposit
    return [
      new ApproveERC20SpenderStep(spender, depositERC20Info),
      new BeefyDepositStep(vault),
    ];
  }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.railgun.org/developer-guide/cookbook/write/recipe.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
