Skip to content

Commit

Permalink
refactor: polishing
Browse files Browse the repository at this point in the history
  • Loading branch information
kupermind committed Oct 22, 2024
1 parent 8b52f29 commit b5b734c
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 102 deletions.
171 changes: 71 additions & 100 deletions contracts/contribute/ContributeServiceManager.sol
Original file line number Diff line number Diff line change
@@ -1,87 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IContributors} from "./interfaces/IContributors.sol";
import {IService} from "./interfaces/IService.sol";

// Contributors interface
interface IContributors {
/// @dev Sets service info for the social id.
/// @param socialId Social id.
/// @param serviceId Service Id.
/// @param multisig Service multisig address.
/// @param stakingInstance Staking instance address.
/// @param serviceOwner Service owner.
function setServiceInfoForId(
uint256 socialId,
uint256 serviceId,
address multisig,
address stakingInstance,
address serviceOwner
) external;

/// @dev Gets service info corresponding to a specified social Id.
/// @param socialId Social Id.
/// @return serviceId Corresponding service Id.
/// @return multisig Corresponding service multisig.
/// @return stakingInstance Staking instance address.
/// @return serviceOwner Service owner.
function mapSocialIdServiceInfo(uint256 socialId) external view
returns (uint256 serviceId, address multisig, address stakingInstance, address serviceOwner);
}

// Staking interface
interface IStaking {
/// @dev Gets service staking token.
/// @return Service staking token address.
function stakingToken() external view returns (address);

/// @dev Gets minimum service staking deposit value required for staking.
/// @return Minimum service staking deposit.
function minStakingDeposit() external view returns (uint256);

/// @dev Gets number of required agent instances in the service.
/// @return Number of agent instances.
function numAgentInstances() external view returns (uint256);

/// @dev Gets the service threshold.
/// @return Threshold.
function threshold() external view returns (uint256);

/// @dev Stakes the service.
/// @param serviceId Service Id.
function stake(uint256 serviceId) external;

/// @dev Unstakes the service with collected reward, if available.
/// @param serviceId Service Id.
/// @return reward Staking reward.
function unstake(uint256 serviceId) external returns (uint256);

/// @dev Claims rewards for the service without an additional checkpoint call.
/// @param serviceId Service Id.
/// @return Staking reward.
function claim(uint256 serviceId) external returns (uint256);
}

// Token interface
interface IToken {
/// @dev Transfers the token amount.
/// @param to Address to transfer to.
/// @param amount The amount to transfer.
/// @return True if the function execution is successful.
function transfer(address to, uint256 amount) external returns (bool);

/// @dev Transfers the token amount that was previously approved up until the maximum allowance.
/// @param from Account address to transfer from.
/// @param to Account address to transfer to.
/// @param amount Amount to transfer to.
/// @return True if the function execution is successful.
function transferFrom(address from, address to, uint256 amount) external returns (bool);

/// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
/// @param spender Account address that will be able to transfer tokens on behalf of the caller.
/// @param amount Token amount.
/// @return True if the function execution is successful.
function approve(address spender, uint256 amount) external returns (bool);
import {IStaking} from "./interfaces/IStaking.sol";
import {IToken} from "./interfaces/IToken.sol";

// Multisig interface
interface IMultisig {
/// @dev Returns array of owners.
/// @return Array of Safe owners.
function getOwners() external view returns (address[] memory);
}

/// @dev Zero address.
Expand All @@ -100,6 +29,12 @@ error ServiceAlreadyStaked(uint256 socialId, uint256 serviceId, address multisig
/// @param stakingInstance Staking instance address.
error WrongStakingInstance(address stakingInstance);

/// @dev Wrong provided service setup.
/// @param socialId Social Id.
/// @param serviceId Service Id.
/// @param multisig Multisig address.
error WrongServiceSetup(uint256 socialId, uint256 serviceId, address multisig);

/// @dev Service is not defined for the social Id.
/// @param socialId Social Id.
error ServiceNotDefined(uint256 socialId);
Expand Down Expand Up @@ -142,6 +77,9 @@ contract ContributeServiceManager {
// Safe fallback handler
address public immutable fallbackHandler;

// Nonce
uint256 internal nonce;

/// @dev ContributeServiceManager constructor.
/// @param _contributorsProxy Contributors proxy address.
/// @param _serviceManager Service manager address.
Expand All @@ -162,6 +100,13 @@ contract ContributeServiceManager {
serviceRegistryTokenUtility = IService(serviceManager).serviceRegistryTokenUtility();
}

/// @dev Creates and deploys a service for the contributor.
/// @param token Staking token address.
/// @param minStakingDeposit Min staking deposit value.
/// @param numAgentInstances Number of agent instances in the service.
/// @param threshold Threshold.
/// @return serviceId Minted service Id.
/// @return multisig Service multisig.
function _createAndDeploy(
address token,
uint256 minStakingDeposit,
Expand Down Expand Up @@ -190,9 +135,31 @@ contract ContributeServiceManager {
// Register msg.sender as an agent instance (numAgentInstances wei as a bond wrapper)
IService(serviceManager).registerAgents{value: numAgentInstances}(serviceId, instances, agentIds);

// Prepare Safe multisig data
uint256 localNonce = nonce;
bytes memory data = abi.encodePacked(address(0), fallbackHandler, address(0), address(0), uint256(0),
localNonce, "0x");
// Deploy the service
// TODO: fix the data
multisig = IService(serviceManager).deploy(serviceId, safeMultisig, "0x");
multisig = IService(serviceManager).deploy(serviceId, safeMultisig, data);

// Update the nonce
nonce = localNonce + 1;
}

/// @dev Stakes the already deployed service.
/// @param socialId Social Id.
/// @param serviceId Service Id.
/// @param multisig Corresponding service multisig.
/// @param stakingInstance Staking instance.
function _stake(uint256 socialId, uint256 serviceId, address multisig, address stakingInstance) internal {
// Add the service into its social Id corresponding record
IContributors(contributorsProxy).setServiceInfoForId(socialId, serviceId, multisig, stakingInstance, msg.sender);

// Approve service NFT for the staking instance
IToken(serviceRegistry).approve(stakingInstance, serviceId);

// Stake the service
IStaking(stakingInstance).stake(serviceId);
}

/// @dev Creates and deploys a service for the contributor, and stakes it with a specified staking contract.
Expand Down Expand Up @@ -237,37 +204,38 @@ contract ContributeServiceManager {
emit CreatedAndStaked(socialId, msg.sender, serviceId, multisig, stakingInstance);
}

function _stake(uint256 socialId, uint256 serviceId, address multisig, address stakingInstance) public {
// Add the service into its social Id corresponding record
IContributors(contributorsProxy).setServiceInfoForId(socialId, serviceId, multisig, stakingInstance, msg.sender);

// Stake the service
IStaking(stakingInstance).stake(serviceId);
}

/// @dev Stakes the already deployed service.
function stake(uint256 socialId, uint256 serviceId, address stakingInstance) public {
/// @param socialId Social Id.
/// @param serviceId Service Id.
/// @param stakingInstance Staking instance.
function stake(uint256 socialId, uint256 serviceId, address stakingInstance) external {
// Check for existing service corresponding to the social Id
(uint256 serviceIdCheck, address multisig, , ) = IContributors(contributorsProxy).mapSocialIdServiceInfo(socialId);
if (serviceIdCheck > 0) {
revert ServiceAlreadyStaked(socialId, serviceIdCheck, multisig);
}

// Transfer the service NFT
IToken(serviceRegistry).transferFrom(msg.sender, address(this), serviceId);

// Approve service NFT for the staking instance
IToken(serviceRegistry).approve(stakingInstance, serviceId);

// Get the service multisig
(, multisig, , , , , ) = IService(serviceRegistry).mapServices(serviceId);

// Check that the service multisig owner is msg.sender
uint256 numAgentInstances = IStaking(stakingInstance).numAgentInstances();
address[] memory multisigOwners = IMultisig(multisig).getOwners();
if (multisigOwners.length != numAgentInstances || multisigOwners[0] != msg.sender) {
revert WrongServiceSetup(socialId, serviceId, multisig);
}

// Transfer the service NFT
IToken(serviceRegistry).transferFrom(msg.sender, address(this), serviceId);

// Stake the service
_stake(socialId, serviceId, multisig, stakingInstance);

emit Staked(socialId, msg.sender, serviceId, multisig, stakingInstance);
}

/// @dev Unstakes service Id corresponding to the social Id and clears the contributor record.
/// @param socialId Social Id.
function unstake(uint256 socialId) external {
// Check for existing service corresponding to the social Id
(uint256 serviceId, address multisig, address stakingInstance, address serviceOwner) =
Expand All @@ -285,7 +253,7 @@ contract ContributeServiceManager {
IStaking(stakingInstance).unstake(serviceId);

// Transfer the service back to the original owner
IToken(serviceRegistry).transfer(serviceOwner, serviceId);
IToken(serviceRegistry).transfer(msg.sender, serviceId);

// Zero the service info: the service is out of the contribute records, however multisig activity is still valid
// If the same service is staked back, the multisig activity continues being tracked
Expand All @@ -294,7 +262,10 @@ contract ContributeServiceManager {
emit Unstaked(socialId, msg.sender, serviceId, multisig, stakingInstance);
}

function claim(uint256 socialId) external {
/// @dev Claims rewards for the service.
/// @param socialId Social Id.
/// @return reward Staking reward.
function claim(uint256 socialId) external returns (uint256 reward) {
// Check for existing service corresponding to the social Id
(uint256 serviceId, address multisig, address stakingInstance, address serviceOwner) =
IContributors(contributorsProxy).mapSocialIdServiceInfo(socialId);
Expand All @@ -308,7 +279,7 @@ contract ContributeServiceManager {
}

// Claim staking rewards
IStaking(stakingInstance).claim(serviceId);
reward = IStaking(stakingInstance).claim(serviceId);

emit Claimed(socialId, msg.sender, serviceId, multisig, stakingInstance);
}
Expand Down
5 changes: 3 additions & 2 deletions contracts/contribute/Contributors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ contract Contributors {
event ImplementationUpdated(address indexed implementation);
event OwnerUpdated(address indexed owner);
event ManagerUpdated(address indexed manager);
event SetServiceInfoForId(uint256 indexed socialId, uint256 indexed serviceId, address indexed multisig);
event SetServiceInfoForId(uint256 indexed socialId, uint256 indexed serviceId, address multisig,
address stakingInstance, address indexed serviceOwner);
event SetContributeAgentStatuses(address[] mechMarketplaces, bool[] statuses);
event MultisigActivityChanged(address indexed senderAgent, address[] multisigs, uint256[] activityChanges);

Expand Down Expand Up @@ -163,7 +164,7 @@ contract Contributors {
serviceInfo.stakingInstance = stakingInstance;
serviceInfo.serviceOwner = serviceOwner;

emit SetServiceInfoForId(socialId, serviceId, multisig);
emit SetServiceInfoForId(socialId, serviceId, multisig, stakingInstance, serviceOwner);
}

/// @dev Sets contribute agent statues.
Expand Down
28 changes: 28 additions & 0 deletions contracts/contribute/interfaces/IContributors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

// Contributors interface
interface IContributors {
/// @dev Sets service info for the social id.
/// @param socialId Social id.
/// @param serviceId Service Id.
/// @param multisig Service multisig address.
/// @param stakingInstance Staking instance address.
/// @param serviceOwner Service owner.
function setServiceInfoForId(
uint256 socialId,
uint256 serviceId,
address multisig,
address stakingInstance,
address serviceOwner
) external;

/// @dev Gets service info corresponding to a specified social Id.
/// @param socialId Social Id.
/// @return serviceId Corresponding service Id.
/// @return multisig Corresponding service multisig.
/// @return stakingInstance Staking instance address.
/// @return serviceOwner Service owner.
function mapSocialIdServiceInfo(uint256 socialId) external view
returns (uint256 serviceId, address multisig, address stakingInstance, address serviceOwner);
}
1 change: 1 addition & 0 deletions contracts/contribute/interfaces/IService.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

// Service registry related interface
interface IService {
struct AgentParams {
// Number of agent instances
Expand Down
35 changes: 35 additions & 0 deletions contracts/contribute/interfaces/IStaking.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

// Staking interface
interface IStaking {
/// @dev Gets service staking token.
/// @return Service staking token address.
function stakingToken() external view returns (address);

/// @dev Gets minimum service staking deposit value required for staking.
/// @return Minimum service staking deposit.
function minStakingDeposit() external view returns (uint256);

/// @dev Gets number of required agent instances in the service.
/// @return Number of agent instances.
function numAgentInstances() external view returns (uint256);

/// @dev Gets the service threshold.
/// @return Threshold.
function threshold() external view returns (uint256);

/// @dev Stakes the service.
/// @param serviceId Service Id.
function stake(uint256 serviceId) external;

/// @dev Unstakes the service with collected reward, if available.
/// @param serviceId Service Id.
/// @return reward Staking reward.
function unstake(uint256 serviceId) external returns (uint256);

/// @dev Claims rewards for the service without an additional checkpoint call.
/// @param serviceId Service Id.
/// @return Staking reward.
function claim(uint256 serviceId) external returns (uint256);
}
24 changes: 24 additions & 0 deletions contracts/contribute/interfaces/IToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

// Token interface
interface IToken {
/// @dev Transfers the token amount.
/// @param to Address to transfer to.
/// @param amount The amount to transfer.
/// @return True if the function execution is successful.
function transfer(address to, uint256 amount) external returns (bool);

/// @dev Transfers the token amount that was previously approved up until the maximum allowance.
/// @param from Account address to transfer from.
/// @param to Account address to transfer to.
/// @param amount Amount to transfer to.
/// @return True if the function execution is successful.
function transferFrom(address from, address to, uint256 amount) external returns (bool);

/// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
/// @param spender Account address that will be able to transfer tokens on behalf of the caller.
/// @param amount Token amount.
/// @return True if the function execution is successful.
function approve(address spender, uint256 amount) external returns (bool);
}

0 comments on commit b5b734c

Please sign in to comment.