Skip to content

Commit

Permalink
feat: contribute contracts stack
Browse files Browse the repository at this point in the history
  • Loading branch information
kupermind committed Oct 22, 2024
1 parent 1281c6f commit c534fc0
Show file tree
Hide file tree
Showing 5 changed files with 386 additions and 1 deletion.
73 changes: 73 additions & 0 deletions contracts/contribute/ContributeActivityChecker.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface IContributors {
function mapMutisigActivities(address multisig) external view returns (uint256);
}

/// @dev Zero address.
error ZeroAddress();

/// @dev Zero value.
error ZeroValue();

/// @title ContributeActivityChecker - Smart contract for performing contributors service staking activity check
/// @author Aleksandr Kuperman - <[email protected]>
/// @author Andrey Lebedev - <[email protected]>
/// @author Tatiana Priemova - <[email protected]>
/// @author David Vilela - <[email protected]>
contract ContributeActivityChecker {
// Liveness ratio in the format of 1e18
uint256 public immutable livenessRatio;
// Contributors proxy contract address
address public immutable contributorsProxy;

/// @dev StakingNativeToken initialization.
/// @param _contributorsProxy Contributors proxy contract address.
/// @param _livenessRatio Liveness ratio in the format of 1e18.
constructor(address _contributorsProxy, uint256 _livenessRatio) {
// Check the zero address
if (_contributorsProxy == address(0)) {
revert ZeroAddress();
}

// Check for zero value
if (_livenessRatio == 0) {
revert ZeroValue();
}

contributorsProxy = _contributorsProxy;
livenessRatio = _livenessRatio;
}

/// @dev Gets service multisig nonces.
/// @param multisig Service multisig address.
/// @return nonces Set of a single service multisig nonce.
function getMultisigNonces(address multisig) external view virtual returns (uint256[] memory nonces) {
nonces = new uint256[](1);
// The nonces are equal to the social off-chain activity corresponding multisig activity
nonces[0] = IContributors(contributorsProxy).mapMutisigActivities(multisig);
}

/// @dev Checks if the service multisig liveness ratio passes the defined liveness threshold.
/// @notice The formula for calculating the ratio is the following:
/// currentNonce - service multisig nonce at time now (block.timestamp);
/// lastNonce - service multisig nonce at the previous checkpoint or staking time (tsStart);
/// ratio = (currentNonce - lastNonce) / (block.timestamp - tsStart).
/// @param curNonces Current service multisig set of a single nonce.
/// @param lastNonces Last service multisig set of a single nonce.
/// @param ts Time difference between current and last timestamps.
/// @return ratioPass True, if the liveness ratio passes the check.
function isRatioPass(
uint256[] memory curNonces,
uint256[] memory lastNonces,
uint256 ts
) external view virtual returns (bool ratioPass) {
// If the checkpoint was called in the exact same block, the ratio is zero
// If the current nonce is not greater than the last nonce, the ratio is zero
if (ts > 0 && curNonces[0] > lastNonces[0]) {
uint256 ratio = ((curNonces[0] - lastNonces[0]) * 1e18) / ts;
ratioPass = (ratio >= livenessRatio);
}
}
}
51 changes: 51 additions & 0 deletions contracts/contribute/ContributeServiceManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/// @dev Zero address.
error ZeroAddress();

/// @dev Zero value.
error ZeroValue();

/// @dev Only contribute is allowed to have access.
error OnlyContribute(address sender, address contribute);

/// @title ContributeServiceManager - Smart contract for managing services for contributors
/// @author Aleksandr Kuperman - <[email protected]>
/// @author Andrey Lebedev - <[email protected]>
/// @author Tatiana Priemova - <[email protected]>
/// @author David Vilela - <[email protected]>
contract ContributeServiceManager {
// Contributors proxy contract address
address public immutable contributorsProxy;

/// @dev StakingNativeToken initialization.
/// @param _contributorsProxy Contributors proxy contract address.
constructor(address _contributorsProxy) {
// Check the zero address
if (_contributorsProxy == address(0)) {
revert ZeroAddress();
}

contributorsProxy = _contributorsProxy;
}

function register(uint256 id, address stakingInstance) external {
// if (mapSocialHashMultisigs[handleHash] != address(0))
// revert();
//
// createSerivce();
// deploy();
//
// stake(stakingInstance);
// mapUserImplemnetations[multisig] = stakingInstance;
}

function stake(uint256 serviceId, address stakingInstance) public {

}

function unstake() external {

}
}
191 changes: 191 additions & 0 deletions contracts/contribute/Contributors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/// @dev Only `owner` has a privilege, but the `sender` was provided.
/// @param sender Sender address.
/// @param owner Required sender address as an owner.
error OwnerOnly(address sender, address owner);

/// @dev The contract is already initialized.
error AlreadyInitialized();

/// @dev Zero address.
error ZeroAddress();

/// @dev Only manager is allowed to have access.
error OnlyManager(address sender, address manager);

/// @dev Wrong length of two arrays.
/// @param numValues1 Number of values in a first array.
/// @param numValues2 Number of values in a second array.
error WrongArrayLength(uint256 numValues1, uint256 numValues2);

/// @dev Account is unauthorized.
/// @param account Account address.
error UnauthorizedAccount(address account);

/// @title Contributors - Smart contract for managing contributors
/// @author Aleksandr Kuperman - <[email protected]>
/// @author Andrey Lebedev - <[email protected]>
/// @author Tatiana Priemova - <[email protected]>
/// @author David Vilela - <[email protected]>
contract ContributeActivityChecker {
event ImplementationUpdated(address indexed implementation);
event OwnerUpdated(address indexed owner);
event ManagerUpdated(address indexed manager);
event SetMultisigForId(uint256 indexed id, address indexed multisig);
event SetContributeAgentStatuses(address[] mechMarketplaces, bool[] statuses);
event MultisigActivityChanged(address indexed senderAgent, address[] multisigs, uint256[] activityChanges);

// Version number
string public constant VERSION = "1.0.0";
// Code position in storage is keccak256("CONTRIBUTORS_PROXY") = "0x8f33b4c48c4f3159dc130f2111086160da6c94439c147bd337ecee0aa81518c7"
bytes32 public constant CONTRIBUTORS_PROXY = 0x8f33b4c48c4f3159dc130f2111086160da6c94439c147bd337ecee0aa81518c7;

// Contract owner
address public owner;
// Service manager contract address
address public manager;

// Mapping of social id => service multisig address
mapping(uint256 => address) public mapSocialHashMultisigs;
// Mapping of service multisig address => activity
mapping(address => uint256) public mapMutisigActivities;
// Mapping of whitelisted contributor agents
mapping(address => bool) public mapContributeAgents;

/// @dev Contributors initializer.
/// @param _manager Manager address.
function initialize(address _manager) external{
// Check for already initialized
if (owner != address(0)) {
revert AlreadyInitialized();
}

// Check for zero address
if (_manager == address(0)) {
revert ZeroAddress();
}

owner = msg.sender;
manager = _manager;
}

/// @dev Changes the contributors implementation contract address.
/// @param newImplementation New implementation contract address.
function changeImplementation(address newImplementation) external {
// Check for the ownership
if (msg.sender != owner) {
revert OwnerOnly(msg.sender, owner);
}

// Check for zero address
if (newImplementation == address(0)) {
revert ZeroAddress();
}

// Store the contributors implementation address
assembly {
sstore(CONTRIBUTORS_PROXY, newImplementation)
}

emit ImplementationUpdated(newImplementation);
}

/// @dev Changes contract owner address.
/// @param newOwner Address of a new owner.
function changeOwner(address newOwner) external {
// Check for the ownership
if (msg.sender != owner) {
revert OwnerOnly(msg.sender, owner);
}

// Check for the zero address
if (newOwner == address(0)) {
revert ZeroAddress();
}

owner = newOwner;
emit OwnerUpdated(newOwner);
}

/// @dev Changes contract manager address.
/// @param newManager Address of a new manager.
function changeManager(address newManager) external {
// Check for the ownership
if (msg.sender != owner) {
revert OwnerOnly(msg.sender, owner);
}

// Check for the zero address
if (newManager == address(0)) {
revert ZeroAddress();
}

manager = newManager;
emit ManagerUpdated(newManager);
}

/// @dev Sets service multisig for the social id.
/// @param id Social id.
/// @param multisig Service multisig address.
function setMultisigForId(uint256 id, address multisig) external {
// Check for manager
if (msg.sender != manager) {
revert OnlyManager(msg.sender, manager);
}

// Set (or remove) multisig for the corresponding social id
mapSocialHashMultisigs[id] = multisig;

emit SetMultisigForId(id, multisig);
}

/// @dev Sets contribute agent statues.
/// @param contributeAgents Contribute agent addresses.
/// @param statuses Corresponding whitelisting statues.
function setMechMarketplaceStatuses(address[] memory contributeAgents, bool[] memory statuses) external {
// Check for the ownership
if (msg.sender != owner) {
revert OwnerOnly(msg.sender, owner);
}

// Check for array lengths
if (contributeAgents.length != statuses.length) {
revert WrongArrayLength(contributeAgents.length, statuses.length);
}

// Traverse all the mech marketplaces and statuses
for (uint256 i = 0; i < contributeAgents.length; ++i) {
if (contributeAgents[i] == address(0)) {
revert ZeroAddress();
}

mapContributeAgents[contributeAgents[i]] = statuses[i];
}

emit SetContributeAgentStatuses(contributeAgents, statuses);
}

/// @dev Increases multisig activity by the contribute agent.
/// @param multisigs Multisig addresses.
/// @param activityChanges Corresponding activity changes
function increaseActivity(address[] memory multisigs, uint256[] memory activityChanges) external {
// Check for whitelisted contribute agent
if (!mapContributeAgents[msg.sender]) {
revert UnauthorizedAccount(msg.sender);
}

// Check for array lengths
if (multisigs.length != activityChanges.length) {
revert WrongArrayLength(multisigs.length, activityChanges.length);
}

// Increase / decrease multisig activity
for (uint256 i = 0; i < multisigs.length; ++i) {
mapMutisigActivities[multisigs[i]] += activityChanges[i];
}

emit MultisigActivityChanged(msg.sender, multisigs, activityChanges);
}
}
70 changes: 70 additions & 0 deletions contracts/contribute/ContributorsProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/// @dev Zero implementation address.
error ZeroImplementationAddress();

/// @dev Zero contributors data.
error ZeroContributorsData();

/// @dev Proxy initialization failed.
error InitializationFailed();

/*
* This is a Contributors proxy contract.
* Proxy implementation is created based on the Universal Upgradeable Proxy Standard (UUPS) EIP-1822.
* The implementation address must be located in a unique storage slot of the proxy contract.
* The upgrade logic must be located in the implementation contract.
* Special contributors implementation address slot is produced by hashing the "CONTRIBUTORS_PROXY"
* string in order to make the slot unique.
* The fallback() implementation for all the delegatecall-s is inspired by the Gnosis Safe set of contracts.
*/

/// @title ContributorsProxy - Smart contract for contributors proxy
/// @author Aleksandr Kuperman - <[email protected]>
/// @author Andrey Lebedev - <[email protected]>
/// @author Tatiana Priemova - <[email protected]>
/// @author David Vilela - <[email protected]>
contract ContributorsProxy {
// Code position in storage is keccak256("CONTRIBUTORS_PROXY") = "0x8f33b4c48c4f3159dc130f2111086160da6c94439c147bd337ecee0aa81518c7"
bytes32 public constant CONTRIBUTORS_PROXY = 0x8f33b4c48c4f3159dc130f2111086160da6c94439c147bd337ecee0aa81518c7;

/// @dev ContributorsProxy constructor.
/// @param implementation Contributors implementation address.
/// @param contributorsData Contributors initialization data.
constructor(address implementation, bytes memory contributorsData) {
// Check for the zero address, since the delegatecall works even with the zero one
if (implementation == address(0)) {
revert ZeroImplementationAddress();
}

// Check for the zero data
if (contributorsData.length == 0) {
revert ZeroContributorsData();
}

// Store the contributors implementation address
assembly {
sstore(CONTRIBUTORS_PROXY, implementation)
}
// Initialize proxy tokenomics storage
(bool success, ) = implementation.delegatecall(contributorsData);
if (!success) {
revert InitializationFailed();
}
}

/// @dev Delegatecall to all the incoming data.
fallback() external {
assembly {
let implementation := sload(CONTRIBUTORS_PROXY)
calldatacopy(0, 0, calldatasize())
let success := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
if eq(success, 0) {
revert(0, returndatasize())
}
return(0, returndatasize())
}
}
}
Loading

0 comments on commit c534fc0

Please sign in to comment.