# Programmatic Subscription
Source: https://docs.chain.link/vrf/v2/subscription/examples/programmatic-subscription

> For the complete documentation index, see [llms.txt](/llms.txt).

<VrfCommon callout="subscription" />

How you manage the subscription depends on your randomness needs. You can configure your subscriptions using the [Subscription Manager](/vrf/v2/subscription/ui), but these examples demonstrate how to create your subscription and add your consumer contracts programmatically. For these examples, the contract owns and manages the subscription. Any wallet can provide funding to those subscriptions.

You can view and monitor your subscriptions in the [Subscription Manager](/vrf/v2/subscription/ui) even if you create them programmatically. Go to [vrf.chain.link](https://vrf.chain.link) to open the Subscription Manager.

## Modifying subscriptions and configurations

Subscription configurations do not have to be static. You can change your subscription configuration dynamically by calling the following functions using the [VRFCoordinatorV2Interface](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol):

- Change the list of approved subscription consumers with:
  - `addConsumer(uint64 subId, address consumer)`.
  - `removeConsumer(uint64 subId, address consumer)`.
- Transfer the subscription ownership with:
  - `requestSubscriptionOwnerTransfer(uint64 subId, address newOwner)`.
  - `acceptSubscriptionOwnerTransfer(uint64 subId)`.
- View the subscription with `getSubscription(uint64 subId)`.
- Cancel the subscription with `cancelSubscription(uint64 subId)`.

To send LINK to the subscription balance, use the LINK token interface with `LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(subId))`. Any wallet can fund a subscription.

See the example in the [Subscription manager contract](#subscription-manager-contract) section to learn how to create a contract that can change your subscription configuration.

## Subscription manager contract

In this example, the contract operates as a subscription owner and can run functions to add consuming contracts to the subscription. The consuming contracts must include the `requestRandomWords()` function with the correct coordinator parameters and the correct subscription ID to request random values and use the subscription balance. The consuming contracts must also include the `fulfillRandomWords()` function to receive the random values.

Subscription owners and consumers do not have to be separate. This contract not only allows adding consumers with `addConsumer(address consumerAddress)` but can also act as a consumer by running its own `requestRandomWords()` function. This example contract includes a `createNewSubscription()` function in the `constructor()` that creates the subscription and adds itself as a consumer automatically when you deploy it.

```sol
// SPDX-License-Identifier: MIT
// An example of a consumer contract that also owns and manages the subscription
pragma solidity ^0.8.7;

import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol";

import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol";
import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol";

/**
 * Request testnet LINK and ETH here: https://faucets.chain.link/
 * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here:
 * https://docs.chain.link/docs/link-token-contracts/
 */

/**
 * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
 * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
 * DO NOT USE THIS CODE IN PRODUCTION.
 */
contract VRFv2SubscriptionManager is VRFConsumerBaseV2 {
  VRFCoordinatorV2Interface COORDINATOR;
  LinkTokenInterface LINKTOKEN;

  // Sepolia coordinator. For other networks,
  // see https://docs.chain.link/docs/vrf-contracts/#configurations
  address vrfCoordinator = 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625;

  // Sepolia LINK token contract. For other networks, see
  // https://docs.chain.link/docs/vrf-contracts/#configurations
  address link_token_contract = 0x779877A7B0D9E8603169DdbD7836e478b4624789;

  // The gas lane to use, which specifies the maximum gas price to bump to.
  // For a list of available gas lanes on each network,
  // see https://docs.chain.link/docs/vrf-contracts/#configurations
  bytes32 keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c;

  // A reasonable default is 100000, but this value could be different
  // on other networks.
  uint32 callbackGasLimit = 100_000;

  // The default is 3, but you can set this higher.
  uint16 requestConfirmations = 3;

  // For this example, retrieve 2 random values in one request.
  // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS.
  uint32 numWords = 2;

  // Storage parameters
  uint256[] public s_randomWords;
  uint256 public s_requestId;
  uint64 public s_subscriptionId;
  address s_owner;

  constructor() VRFConsumerBaseV2(vrfCoordinator) {
    COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
    LINKTOKEN = LinkTokenInterface(link_token_contract);
    s_owner = msg.sender;
    //Create a new subscription when you deploy the contract.
    createNewSubscription();
  }

  // Assumes the subscription is funded sufficiently.
  function requestRandomWords() external onlyOwner {
    // Will revert if subscription is not set and funded.
    s_requestId =
      COORDINATOR.requestRandomWords(keyHash, s_subscriptionId, requestConfirmations, callbackGasLimit, numWords);
  }

  function fulfillRandomWords(
    uint256,
    /* requestId */
    uint256[] memory randomWords
  ) internal override {
    s_randomWords = randomWords;
  }

  // Create a new subscription when the contract is initially deployed.
  function createNewSubscription() private onlyOwner {
    s_subscriptionId = COORDINATOR.createSubscription();
    // Add this contract as a consumer of its own subscription.
    COORDINATOR.addConsumer(s_subscriptionId, address(this));
  }

  // Assumes this contract owns link.
  // 1000000000000000000 = 1 LINK
  function topUpSubscription(
    uint256 amount
  ) external onlyOwner {
    LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_subscriptionId));
  }

  function addConsumer(
    address consumerAddress
  ) external onlyOwner {
    // Add a consumer contract to the subscription.
    COORDINATOR.addConsumer(s_subscriptionId, consumerAddress);
  }

  function removeConsumer(
    address consumerAddress
  ) external onlyOwner {
    // Remove a consumer contract from the subscription.
    COORDINATOR.removeConsumer(s_subscriptionId, consumerAddress);
  }

  function cancelSubscription(
    address receivingWallet
  ) external onlyOwner {
    // Cancel the subscription and send the remaining LINK to a wallet address.
    COORDINATOR.cancelSubscription(s_subscriptionId, receivingWallet);
    s_subscriptionId = 0;
  }

  // Transfer this contract's funds to an address.
  // 1000000000000000000 = 1 LINK
  function withdraw(
    uint256 amount,
    address to
  ) external onlyOwner {
    LINKTOKEN.transfer(to, amount);
  }

  modifier onlyOwner() {
    require(msg.sender == s_owner);
    _;
  }
}
```

To use this contract, compile and deploy it in Remix.

1. Open the contract in [Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/VRFv2SubscriptionManager.sol).

2. Compile and deploy the contract using the Injected Provider environment. The contract includes all of the configuration variables that you need, but you can edit them if necessary. For a full list of available configuration variables, see the [Supported Networks](/vrf/v2/subscription/supported-networks) page.

   This contract automatically creates a new subscription when you deploy it. Read the `s_subscriptionId` variable to find your subscription ID. You can use this value to find the subscription at [vrf.chain.link](https://vrf.chain.link).

3. In this example, the `topUpSubscription()` function sends LINK from your contract to the subscription. Fund your contract with at least three testnet LINK. Alternatively, you can send LINK directly to the subscription at [vrf.chain.link](https://vrf.chain.link). Any address can provide funding to a subscription balance. If you need testnet LINK, you can get it from [faucets.chain.link](https://faucets.chain.link/sepolia/).

4. Run the `topUpSubscription()` function to send LINK from your contract to your subscription balance. For this example, specify a value of `3000000000000000000`, which is equivalent to three LINK.

5. Run the `requestRandomWords()` function. The request might take several minutes to process. Track the pending request status at [vrf.chain.link](https://vrf.chain.link).

6. You can also add and test consumer contracts using the same programmatic subscription process:
   1. Create and deploy a consumer contract that includes the following components:

      - The `requestRandomWords()` function and the required variables and your subscription ID.
      - The `fulfillRandomWords()` callback function.

      You can use the example from the [Get a Random Number](/vrf/v2/subscription/examples/get-a-random-number/#analyzing-the-contract) guide.

   2. After you deploy the consumer contract, add it to the subscription as an approved consumer using the `addConsumer()` function on your subscription manager contract. Specify the address of your consumer contract.

   3. On the consumer contract, run the `requestRandomWords()` function to request and receive random values. The request might take several minutes to process. Track the pending request status at [vrf.chain.link](https://vrf.chain.link).

      The consumer contract can continue to make requests until your subscription balance runs out. The subscription manager contract must maintain sufficient balance in the subscription so that the consumers can continue to operate.

   4. If you need to remove consumer contracts from the subscription, use the `removeConsumer()` function. Specify the address of the consumer contract to be removed.

7. When you are done with your contracts and the subscription, run the `cancelSubscription()` function to close the subscription and send the remaining LINK to your wallet address. Specify the address of the receiving wallet.

## Funding and requesting simultaneously

You can fund a subscription and request randomness in a single transaction. You must estimate how much the transaction might cost and determine the amount of funding to send to the subscription yourself. See the [Subscription billing](/vrf/v2/subscription/#subscription-limits) page to learn how to estimate request costs.

```sol
// Assumes this contract owns link
// You must estimate LINK cost yourself based on the gas lane and limits.
// 1_000_000_000_000_000_000 = 1 LINK
function fundAndRequestRandomWords(uint256 amount) external onlyOwner {
    LINKTOKEN.transferAndCall(
        address(COORDINATOR),
        amount,
        abi.encode(s_subscriptionId)
    );
    // Will revert if subscription is not set and funded.
    s_requestId = COORDINATOR.requestRandomWords(
        keyHash,
        s_subscriptionId,
        requestConfirmations,
        callbackGasLimit,
        numWords
    );
}
```

Add this function to your contracts if you need to provide funding simultaneously with your requests. The `transferAndCall()` function sends LINK from your contract to the subscription, and the `requestRandomWords()` function requests the random words. Your contract still needs the `fulfillRandomWords()` callback function to receive the random values.