// SPDX-License-Identifier: MIT pragma solidity >=0.8.4 <0.9.0; import '../../../interfaces/peripherals/IKeep3rJobs.sol'; import './Keep3rJobFundableCredits.sol'; import './Keep3rJobFundableLiquidity.sol'; abstract contract Keep3rJobMigration is IKeep3rJobMigration, Keep3rJobFundableCredits, Keep3rJobFundableLiquidity { using EnumerableSet for EnumerableSet.AddressSet; uint256 internal constant _MIGRATION_COOLDOWN = 1 minutes; /// @inheritdoc IKeep3rJobMigration mapping(address => address) public override pendingJobMigrations; mapping(address => mapping(address => uint256)) internal _migrationCreatedAt; /// @inheritdoc IKeep3rJobMigration function migrateJob(address _fromJob, address _toJob) external override onlyJobOwner(_fromJob) { if (_fromJob == _toJob) revert JobMigrationImpossible(); pendingJobMigrations[_fromJob] = _toJob; _migrationCreatedAt[_fromJob][_toJob] = block.timestamp; emit JobMigrationRequested(_fromJob, _toJob); } /// @inheritdoc IKeep3rJobMigration function acceptJobMigration(address _fromJob, address _toJob) external override onlyJobOwner(_toJob) { if (disputes[_fromJob] || disputes[_toJob]) revert JobDisputed(); if (pendingJobMigrations[_fromJob] != _toJob) revert JobMigrationUnavailable(); if (block.timestamp < _migrationCreatedAt[_fromJob][_toJob] + _MIGRATION_COOLDOWN) revert JobMigrationLocked(); // force job credits update for both jobs _settleJobAccountance(_fromJob); _settleJobAccountance(_toJob); // migrate tokens while (_jobTokens[_fromJob].length() > 0) { address _tokenToMigrate = _jobTokens[_fromJob].at(0); jobTokenCredits[_toJob][_tokenToMigrate] += jobTokenCredits[_fromJob][_tokenToMigrate]; jobTokenCredits[_fromJob][_tokenToMigrate] = 0; _jobTokens[_fromJob].remove(_tokenToMigrate); _jobTokens[_toJob].add(_tokenToMigrate); } // migrate liquidities while (_jobLiquidities[_fromJob].length() > 0) { address _liquidity = _jobLiquidities[_fromJob].at(0); liquidityAmount[_toJob][_liquidity] += liquidityAmount[_fromJob][_liquidity]; delete liquidityAmount[_fromJob][_liquidity]; _jobLiquidities[_toJob].add(_liquidity); _jobLiquidities[_fromJob].remove(_liquidity); } // migrate job balances _jobPeriodCredits[_toJob] += _jobPeriodCredits[_fromJob]; delete _jobPeriodCredits[_fromJob]; _jobLiquidityCredits[_toJob] += _jobLiquidityCredits[_fromJob]; delete _jobLiquidityCredits[_fromJob]; // stop _fromJob from being a job delete rewardedAt[_fromJob]; _jobs.remove(_fromJob); // delete unused data slots delete jobOwner[_fromJob]; delete jobPendingOwner[_fromJob]; delete _migrationCreatedAt[_fromJob][_toJob]; delete pendingJobMigrations[_fromJob]; emit JobMigrationSuccessful(_fromJob, _toJob); } }