Skip to main content


Contract: JBController​‌

Allows a project to migrate from this controller to another.

Only a project's owner or a designated operator can migrate it.


function migrate(uint256 _projectId, IJBMigratable _to)
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER) { ... }
  • Arguments:
    • _projectId is the ID of the project that will be migrated from this controller.
    • _to is the IJBMigratable controller to which the project is migrating.
  • Through the requirePermission modifier, the function is only accessible by the project's owner, or from an operator that has been given the JBOperations.MIGRATE_CONTROLLER permission by the project owner for the provided _projectId.
  • The function can be overriden by inheriting contracts.
  • The function doesn't return anything.


  1. Keep a reference to the directory.

    // Keep a reference to the directory.
    IJBDirectory _directory = directory;

    Internal references:

  2. Make sure this controller is the project's current controller.

    // This controller must be the project's current controller.
    if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();

    External references:

  3. Get a reference to the current funding cycle for the project.

    // Get a reference to the project's current funding cycle.
    JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);

    Internal references:

    External references:

  4. Make sure the project's current funding cycle is configured to allow controller migrations.

    // Migration must be allowed.
    if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();

    Library references:

  5. Distribute any outstanding reserved tokens. There are reserved tokens to be distributed if the tracker does not equal the token's total supply.

    // All reserved tokens must be minted before migrating.
    if (
    _processedTokenTrackerOf[_projectId] < 0 ||
    uint256(_processedTokenTrackerOf[_projectId]) != tokenStore.totalSupplyOf(_projectId)
    ) _distributeReservedTokensOf(_projectId, '');

    Internal references:

    External references:

  6. Let the new controller know that a migration to it is happening.

    // Make sure the new controller is prepped for the migration.
    _to.prepForMigrationOf(_projectId, address(this));

    External references:

  7. Set the new controller of the project.

    // Set the new controller.
    _directory.setControllerOf(_projectId, _to);

    External references:

  8. Emit a Migrate event with the relevant parameters.

    emit Migrate(_projectId, _to, msg.sender);

    Event references: