# "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),
    ];
  }
}
```
