Open shivasai780 opened 1 year ago
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/utils/Address.sol";
contract MultisigAggregator is Ownable { using Counters for Counters.Counter;
// Struct to represent a proposal
struct Proposal {
address target; // Contract address to interact with
bytes data; // Encoded function data
uint256 signatures; // Number of confirmed signatures
mapping(address => bool) confirmations; // Confirmations by owners
}
mapping(address=>bool) isShuffled;
uint256 public requiredConfirmations;
mapping(address => bool) public isOwner;
mapping(uint256 => Proposal) public proposals;
Counters.Counter private proposalCount;
constructor(address[] memory _owners, uint256 _requiredConfirmations) {
require(_owners.length > 2, "At least 3 owner required");
require(_requiredConfirmations > 2 && _requiredConfirmations <= _owners.length, "Invalid required confirmations");
for (uint256 i = 3; i <= _owners.length; i++) {
address owner = _owners[i];
require(owner != address(0), "Invalid owner address");
require(!isOwner[owner], "Duplicate owner");
isOwner[owner] = true;
}
requiredConfirmations = _requiredConfirmations;
}
uint256 public shufflingInterval = 5; // Number of timechains after which council members are shuffled
uint256 public lastShufflingTimechain = 0;
modifier onlyUnconfirmed(uint256 proposalId) {
require(!proposals[proposalId].confirmations[msg.sender], "Already confirmed");
_;
}
function propose(address _target, bytes calldata _data) external onlyOwner {
uint256 proposalId = proposalCount.current();
proposals[proposalId].target = _target;
proposals[proposalId].data = _data;
proposalCount.increment();
}
function confirm(uint256 proposalId) external onlyOwner onlyUnconfirmed(proposalId) {
proposals[proposalId].confirmations[msg.sender] = true;
proposals[proposalId].signatures++;
}
function execute(uint256 proposalId) external {
require(proposals[proposalId].target != address(0), "Invalid proposal");
require(proposals[proposalId].signatures >= requiredConfirmations, "Not enough confirmations");
(bool success, bytes memory result) = proposals[proposalId].target.call(proposals[proposalId].data);
require(success, "Execution failed");
delete proposals[proposalId];
}
function shuffleCouncil(address[] memory owners) internal {
address[] memory newCouncil = new address[](3); // Assuming there are always 3 council members
uint256 currentIndex = 0;
// Collect all non-shuffled owners
for (uint256 i = 0; i < owners.length; i++) {
if (!isShuffled[owners[i]]) {
newCouncil[currentIndex] = owners[i];
currentIndex++;
}
}
// Shuffle the collected council members
for (uint256 i = 0; i < newCouncil.length; i++) {
uint256 randomIndex = uint256(keccak256(abi.encodePacked(block.timestamp, block.difficulty, i))) % newCouncil.length;
(newCouncil[i], newCouncil[randomIndex]) = (newCouncil[randomIndex], newCouncil[i]);
}
// Replace existing council members with shuffled ones
for (uint256 i = 0; i < newCouncil.length; i++) {
owners[i + 3] = newCouncil[i];
isShuffled[newCouncil[i]] = true;
}
}
}
Certainly! Here's a detailed explanation of the modified "MultisigAggregator" smart contract:
This Solidity smart contract is designed to facilitate multisignature (multisig) decision-making and proposal execution among a group of predefined owners. It enforces a multisig mechanism where a minimum number of owners' confirmations are required to execute a proposal. Additionally, the contract incorporates the feature to shuffle council members after a certain number of timechains to ensure decentralization and fairness in decision-making.
SPDX-License-Identifier: This comment specifies that the contract code is released under the MIT license.
pragma solidity ^0.8.0: This statement indicates the version of the Solidity compiler being used for contract compilation.
Imports: The contract imports necessary libraries and interfaces from the OpenZeppelin framework to ensure secure and efficient functionality.
Struct Proposal
: This struct represents a proposal, containing the following attributes:
target
: The address of the contract to interact with.data
: The encoded function data to be executed on the target contract.signatures
: The number of confirmed signatures for the proposal.confirmations
: A mapping to track owners' confirmations for the proposal.Mappings and Counters:
mapping(address=>bool) isShuffled
: This mapping tracks whether an owner has been shuffled to ensure even distribution.mapping(address => bool) public isOwner
: This mapping stores whether an address is an owner of the contract.mapping(uint256 => Proposal) public proposals
: This mapping associates proposal IDs with corresponding Proposal struct instances.Counters.Counter private proposalCount
: This counter keeps track of the number of proposals.Constructor:
isOwner
mapping to identify the owners.Variables for Shuffling:
uint256 public shufflingInterval
: This variable specifies the interval after which council members are shuffled.uint256 public lastShufflingTimechain
: This variable keeps track of the last timechain when council members were shuffled.Modifier onlyUnconfirmed(uint256 proposalId)
: This modifier ensures that the function can only be executed by an owner who hasn't confirmed a specific proposal yet.
Function propose(address _target, bytes calldata _data)
:
checkAndShuffleCouncil()
.Function confirm(uint256 proposalId)
:
checkAndShuffleCouncil()
.Function execute(uint256 proposalId)
:
Function checkAndShuffleCouncil()
:
shuffleCouncil()
function and updates the last shuffling timechain.Function shuffleCouncil()
:
isShuffled
mapping.This "MultisigAggregator" contract combines multisig functionality with periodic shuffling of council members, enhancing decentralization and fairness in the decision-making process.
hey vinay !! update the multisig with @123456788940 here . start working on this
// SPDX-License-Identifier: MIT pragma solidity 0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol";
interface IERC20 { function transfer(address recipient, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256); }
contract MultiSigAggregator is Ownable { using EnumerableSet for EnumerableSet.AddressSet; using SafeMath for uint256;
uint256 public quorumPercent = 75; // Percentage of required approvals
uint256 public quorumVotes;
EnumerableSet.AddressSet private owners;
address public gdvPoolAddress;
address public treasuryPoolAddress;
IERC20 public gdvToken;
enum Action {
TransferToGDV,
SignRedeemTransaction,
BurnTokens,
ResubmitToGDV
}
struct Proposal {
address initiator;
Action action;
uint256 amount;
bool executed;
uint256 approvals;
mapping(address=>bool) hasApproved;
}
Proposal[] public proposals;
event ProposalCreated(uint256 indexed proposalId, Action indexed action, uint256 amount);
event ProposalApproved(uint256 indexed proposalId, address indexed approver);
event ActionExecuted(uint256 indexed proposalId);
constructor(address _gdvToken, address _gdvPool, address _treasuryPool, address[] memory _initialOwners) {
gdvToken = IERC20(_gdvToken);
gdvPoolAddress = _gdvPool;
treasuryPoolAddress = _treasuryPool;
for (uint256 i = 0; i < _initialOwners.length; i++) {
owners.add(_initialOwners[i]);
}
quorumVotes = (quorumPercent.mul(owners.length())).div(100);
}
function createProposal(Action _action, uint256 _amount) external onlyOwner {
uint256 proposalId = proposals.length;
emit ProposalCreated(proposalId, _action, _amount);
}
function approveProposal(uint256 _proposalId) external onlyOwner {
require(_proposalId < proposals.length, "Invalid proposal");
Proposal storage proposal = proposals[_proposalId];
require(!proposal.executed, "Proposal already executed");
require(!proposal.hasApproved[msg.sender], "Already approved");
proposal.hasApproved[msg.sender] = true;
proposal.approvals++;
emit ProposalApproved(_proposalId, msg.sender);
if (proposal.approvals >= quorumVotes) {
executeProposal(_proposalId);
}
}
function executeProposal(uint256 _proposalId) internal {
Proposal storage proposal = proposals[_proposalId];
proposal.executed = true;
if (proposal.action == Action.TransferToGDV) {
require(gdvToken.balanceOf(treasuryPoolAddress) >= proposal.amount, "Insufficient balance");
require(gdvToken.transfer(gdvPoolAddress, proposal.amount), "Transfer failed");
} else if (proposal.action == Action.SignRedeemTransaction) {
// Perform action for SignRedeemTransaction
} else if (proposal.action == Action.BurnTokens) {
// Perform action for BurnTokens
} else if (proposal.action == Action.ResubmitToGDV) {
// Perform action for ResubmitToGDV
}
emit ActionExecuted(_proposalId);
}
}
MultiSigAggregator Contract Documentation
Table of Contents:
createProposal
approveProposal
executeProposal
ProposalCreated
ProposalApproved
ActionExecuted
1. Introduction
The MultiSigAggregator contract is designed to serve as a multi-signature aggregator with various functionalities. It enables a group of predefined owners to create, approve, and execute proposals for specific actions involving the transfer of funds and interactions with other contracts.
2. Contract Overview
The contract allows a designated group of owners to collectively make decisions on certain actions. These actions include transferring tokens to a GDV pool, signing redeem transactions, burning tokens, and resubmitting tokens to the GDV pool. The contract enforces a quorum requirement for proposal approvals, ensuring that a minimum percentage of owners must approve a proposal before it can be executed.
3. Contract Structure
The contract consists of state variables, enums, structs, and functions that enable the proposed functionalities.
3.1. State Variables
quorumPercent
: Defines the percentage of required approvals for a proposal to be executed.quorumVotes
: The calculated number of votes required to meet the quorum.owners
: A set of addresses representing the owners of the contract.gdvPoolAddress
: Address of the GDV pool.treasuryPoolAddress
: Address of the treasury pool.gdvToken
: Address of the GDV token contract.proposals
: An array of Proposal structs representing pending proposals.3.2. Enumerations
Action
: Defines the possible actions that can be proposed, including TransferToGDV, SignRedeemTransaction, BurnTokens, and ResubmitToGDV.3.3. Structs
Proposal
: Contains information about a proposal, including the initiator, action, amount, approval status, and more.4. Constructor
constructor(address _gdvToken, address _gdvPool, address _treasuryPool, address[] memory _initialOwners)
: Initializes the contract with initial parameters, including the GDV token, GDV pool, treasury pool, and initial owners.5. Modifiers
onlyOwner
: A modifier that restricts access to functions only to approved owners.6. Functions
createProposal(Action _action, uint256 _amount) external onlyOwner
: Allows an owner to create a new proposal for a specific action and amount.approveProposal(uint256 _proposalId) external onlyOwner
: Allows an owner to approve a pending proposal.executeProposal(uint256 _proposalId) internal
: Executes a proposal's action if it receives enough approvals.7. Events
ProposalCreated(uint256 indexed proposalId, Action indexed action, uint256 amount)
: Emitted when a new proposal is created.ProposalApproved(uint256 indexed proposalId, address indexed approver)
: Emitted when a proposal is approved by an owner.ActionExecuted(uint256 indexed proposalId)
: Emitted when a proposal's action is executed.8. Conclusion
The MultiSigAggregator contract provides a secure and transparent way for a predefined group of owners to collectively make decisions regarding specific actions involving token transfers and interactions with other contracts. It enforces a quorum requirement for approvals and emits events to keep track of proposal creation, approval, and execution.
If anyone has a better idea go ahead and implement.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
interface IERC20 {
function transfer(address recipient, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
contract MultiSigGovernance is Ownable, Pausable, ReentrancyGuard {
using SafeMath for uint256;
// Events
event RedeemTransactionSigned(address indexed signer, uint256 amount);
event TokensBurned(uint256 amount);
event TokensResubmitted(address indexed sender);
event ProposalCreated(uint256 indexed proposalId, ActionType indexed action, uint256 amount);
event ProposalApproved(uint256 indexed proposalId, address indexed approver);
event ActionExecuted(uint256 indexed proposalId);
event ProposalFastTrackedToAIP(uint256 indexed proposalId);
event TransferTokensGvl(uint256 amount);
event ProposalReadyForVoting(uint256 indexed proposalId);
// Variables
uint256 public quorumPercent = 100;
uint256 public quorumVotes;
address[] private committeeMembers;
address public gdvPool;
address public treasuryPool;
IERC20 public gdvToken;
uint256 public timechainCounter;
uint256 public constant maxTimechains = 25;
uint256 public constant timechainDuration = 7 days;
uint256 public constant sessionDuration = 4 hours;
uint256 public constant eraDuration = 24 hours;
address public emergencyExecutor;
mapping(uint256 => bytes[]) private redeemTransactionsPerTimechain;
// Modifiers
modifier onlyCommittee() {
require(isCommitteeMember(msg.sender), "Only committee members can call this function");
require(timechainCounter < maxTimechains, "Timechain limit reached");
_;
}
modifier onlyTechnicalMember() {
require(isTechnicalMember(msg.sender), "Only technical members can call this function");
_;
}
modifier onlyEmergencyExecutor() {
require(msg.sender == emergencyExecutor, "Only emergency executor can call this function");
_;
}
modifier onlyUnpaused() {
require(!paused(), "Contract is paused");
_;
}
constructor(
address _gdvToken,
address _gdvPool,
address _treasuryPool,
address[] memory _initialOwners,
address _emergencyOwner
) {
require(_initialOwners.length >= 3, "At least three initial committee members required");
gdvToken = IERC20(_gdvToken);
gdvPool = _gdvPool;
treasuryPool = _treasuryPool;
emergencyExecutor = _emergencyOwner;
// Add initial committee members
for (uint256 i = 0; i < _initialOwners.length; i++) {
_addCommitteeMember(_initialOwners[i]);
}
// Add technical and research members
address technicalMember1 = address(0);
address technicalMember2 = address(0);
address researchMember = address(0);
_addCommitteeMember(technicalMember1);
_addCommitteeMember(technicalMember2);
_addCommitteeMember(researchMember);
quorumVotes = (quorumPercent.mul(committeeMembers.length)).div(100);
}
// Internal function to add a committee member
function _addCommitteeMember(address newMember) private {
require(newMember != address(0), "Invalid member address");
require(!isCommitteeMember(newMember), "Member already exists");
committeeMembers.push(newMember);
}
// Check if an address is a committee member
function isCommitteeMember(address member) public view returns (bool) {
for (uint256 i = 0; i < committeeMembers.length; i++) {
if (committeeMembers[i] == member) {
return true;
}
}
return false;
}
// Enumeration for proposal actions
enum ActionType { TransferToGDV, SignRedeemTransaction, BurnTokens, ResubmitToGDV, AIP }
// Struct to represent a proposal
struct Proposal {
address initiator;
ActionType action;
uint256 amount;
bool executed;
uint256 approvals;
}
Proposal[] public proposals;
// Create a new proposal
function createProposal(ActionType _action, uint256 _amount) external onlyCommittee onlyUnpaused nonReentrant {
require(_action != ActionType.SignRedeemTransaction || timechainCounter < maxTimechains, "Invalid action");
Proposal memory newProposal = Proposal({
initiator: msg.sender,
action: _action,
amount: _amount,
executed: false,
approvals: 0
});
proposals.push(newProposal);
emit ProposalCreated(proposals.length - 1, _action, _amount);
}
// Approve a proposal
function approveProposal(uint256 _proposalId) external onlyOwner {
require(_proposalId < proposals.length, "Invalid proposal");
Proposal storage proposal = proposals[_proposalId];
require(!proposal.executed, "Proposal already executed");
proposal.approvals++;
emit ProposalApproved(_proposalId, msg.sender);
if (proposal.approvals >= quorumVotes) {
executeProposal(_proposalId);
}
}
// Execute a proposal
function executeProposal(uint256 _proposalId) internal nonReentrant {
Proposal storage proposal = proposals[_proposalId];
proposal.executed = true;
if (proposal.action == ActionType.transferToGVL) {
TransferTokensGvl(proposal.amount);
} else if (proposal.action == ActionType.SignRedeemTransaction) {
if (isCommitteeMember(msg.sender)) {
_executeSignRedeemTransaction(proposal.amount);
} else if (emergencyExecutor != address(0)) {
require(getCurrentSession() >= 1 && getCurrentTimechain() >= 1, "Cannot execute yet");
_executeProposalByEmergencyExecutor(_proposalId);
} else {
revert("Only committee members or emergency executor can sign");
}
} else if (proposal.action == ActionType.BurnTokens) {
executeBurnTokens(proposal.amount);
} else if (proposal.action == ActionType.ResubmitToGDV) {
executeResubmitToGDV();
} else if (proposal.action == ActionType.AIP) {
// Handle Action.AIP if needed
}
emit ActionExecuted(_proposalId);
}
// Submit a redeem transaction
function submitRedeemTransaction(bytes calldata redeemTx, uint256 _timechain) external onlyCommittee onlyUnpaused {
redeemTransactionsPerTimechain[_timechain].push(redeemTx);
}
// Execute a proposal by emergency executor
function _executeProposalByEmergencyExecutor(uint256 _proposalId) internal {
require(msg.sender == emergencyExecutor, "Only emergency executor can execute");
Proposal storage proposal = proposals[_proposalId];
require(!proposal.executed, "Proposal already executed");
require(getCurrentSession() >= 1 && getCurrentTimechain() >= 2, "Cannot execute yet");
if (proposal.action == ActionType.TransferToGDV) {
TransferTokensGvl(proposal.amount);
} else if (proposal.action == ActionType.BurnTokens) {
executeBurnTokens(proposal.amount);
} else if (proposal.action == ActionType.ResubmitToGDV) {
executeResubmitToGDV();
} else if (proposal.action == ActionType.AIP) {
// Handle Action.AIP if needed
}
emit ActionExecuted(_proposalId);
}
// Execute burning of tokens
function executeBurnTokens(uint256 burnPercentage) internal {
require(burnPercentage > 0 && burnPercentage <= 100, "Invalid burn percentage");
require(timechainCounter % 5 == 0, "Tokens can only be burned every 5 timechains");
uint256 gdvPoolBalance = gdvToken.balanceOf(gdvPool);
require(gdvPoolBalance > 0, "No tokens in GDV pool");
uint256 burnAmount = gdvPoolBalance.mul(burnPercentage).div(100);
require(burnAmount > 0, "Nothing to burn");
require(gdvToken.transfer(address(0), burnAmount), "Burn failed");
emit TokensBurned(burnAmount);
}
// Execute resubmission of tokens
function executeResubmitToGDV() internal {
emit TokensResubmitted(msg.sender);
}
// Transfer tokens to GDV pool
function transferTokensGvl(uint256 amount) external onlyCommittee onlyUnpaused {
require(gdvPool != address(0), "GVL pool address not set");
require(gdvToken.balanceOf(address(this)) >= amount, "Insufficient balance");
require(gdvToken.transfer(gdvPool, amount), "Transfer to GVL pool failed");
emit TransferTokensGvl(amount);
}
// Execute redemption transactions
function executeRedeemTransactions(uint256 _timechain) external onlyOwner nonReentrant {
require(block.timestamp % timechainDuration == 0, "Redemption can only be executed at the end of a timechain");
bytes[] memory redeemTransactions = redeemTransactionsPerTimechain[_timechain];
uint256 totalRedeemAmount = 0;
for (uint256 i = 0; i < redeemTransactions.length; i++) {
(uint256 redeemAmount, ) = abi.decode(redeemTransactions[i], (uint256, uint256));
totalRedeemAmount = totalRedeemAmount.add(redeemAmount);
}
require(gdvToken.balanceOf(gdvPool) >= totalRedeemAmount, "Insufficient balance");
require(gdvToken.transfer(treasuryPool, totalRedeemAmount), "Transfer failed");
delete redeemTransactionsPerTimechain[_timechain];
}
// Set emergency executor address
function setEmergencyExecutor(address _emergencyExecutor) external onlyOwner {
require(_emergencyExecutor != address(0), "Invalid address");
emergencyExecutor = _emergencyExecutor;
}
// Update emergency executor address
function updateEmergencyExecutor(address _newEmergencyExecutor) external onlyOwner {
require(_newEmergencyExecutor != address(0), "Invalid address");
emergencyExecutor = _newEmergencyExecutor;
}
// Execute emergency executor's signature on a proposal
function emergencyExecutorSign(uint256 _proposalId) external onlyEmergencyExecutor onlyUnpaused {
require(_proposalId < proposals.length, "Invalid proposal");
Proposal storage proposal = proposals[_proposalId];
require(!proposal.executed, "Proposal already executed");
uint256 currentSession = getCurrentSession();
uint256 currentTimechain = getCurrentTimechain();
require(currentSession >= 1 && currentTimechain >= 1, "Cannot execute yet");
executeProposal(_proposalId);
}
// Fast-track a proposal to AIP
function fastTrackToAIP(uint256 _proposalId) external onlyTechnicalMember onlyUnpaused {
require(_proposalId < proposals.length, "Invalid proposal");
Proposal storage proposal = proposals[_proposalId];
require(!proposal.executed, "Proposal already executed");
require(proposal.action != ActionType.SignRedeemTransaction, "Cannot fast-track SignRedeemTransaction");
// Assuming technical member approval for fast-tracking
proposal.approvals++;
// Change the proposal's action type to AIP
proposal.action = ActionType.AIP;
// Emit ProposalApproved and ProposalFastTrackedToAIP events
emit ProposalApproved(_proposalId, msg.sender);
emit ProposalFastTrackedToAIP(_proposalId);
// Trigger a notification or event to inform the public or developers
// that a proposal has been fast-tracked to AIP status and is open for voting
emit ProposalReadyForVoting(_proposalId);
}
// Increment the timechain counter
function incrementTimechainCounter() external onlyOwner {
require(timechainCounter < maxTimechains, "Timechain limit reached");
timechainCounter++;
}
// Placeholder functions for internal actions
function _executeSignRedeemTransaction(uint256 _amount) internal {
emit RedeemTransactionSigned(msg.sender, _amount);
}
// Check if an address is a technical member (placeholder logic)
function isTechnicalMember(address member) public view returns (bool) {
// Add your logic to determine if the given member is a technical member
return true;
}
// Pauses the contract, preventing any further actions
function pause() external onlyOwner {
_pause();
}
// Unpauses the contract, allowing actions to resume
function unpause() external onlyOwner {
_unpause();
}
// Get the current session number
function getCurrentSession() public view returns (uint256) {
return (block.timestamp % timechainDuration) / sessionDuration;
}
// Get the current era number
function getCurrentEra() public view returns (uint256) {
return (block.timestamp % timechainDuration) / eraDuration;
}
// Get the current timechain number
function getCurrentTimechain() public view returns (uint256) {
return block.timestamp.div(timechainDuration);
}
}
The MultiSigAggregatorV1 contract is designed to enable committee members to propose and execute actions on the blockchain in a decentralized manner.
Events are used to emit information about contract actions. They allow external systems to listen and react to changes happening in the contract. For instance, RedeemTransactionSigned and TokensBurned events signal when certain actions take place.
Modifiers are used to restrict access to specific functions. In this contract, onlyCommittee, onlyTechnicalMember, onlyEmergencyExecutor, and onlyUnpaused are modifiers that ensure only the intended participants can call certain functions.
The constructor initializes the contract with essential parameters, such as the GDV token contract, the GDV and treasury pool addresses, initial committee members, and an emergency owner address. It sets up the committee members, calculates the quorum, and defines other initial values.
The contract maintains a list of committee members, which consists of initial members, technical members, and research members. This list is used to validate actions taken within the contract.
The Proposal struct stores information about each proposal, such as the initiator, action type, amount, execution status, and the number of approvals received.
The createProposal function allows committee members to create new proposals. It verifies the validity of the action and creates a new proposal in the proposals array.
The approveProposal function allows the contract owner to approve a proposal. If the number of approvals reaches the quorum, the proposal is executed.
The executeProposal function executes a proposal based on its action type. For actions like transfer to GDV, signing redeem transactions, burning tokens, and resubmitting to GDV, the function performs the necessary actions and updates the proposal status.
Committee members can submit redeem transactions using the submitRedeemTransaction function. Redeem transactions are grouped by timechain and stored for later execution.
The executeRedeemTransactions function executes all redeem transactions submitted for a specific timechain. It verifies the available balance, performs transfers, and clears the submitted transactions.
The fastTrackToAIP function allows technical members to fast-track proposals to AIP (Assessment and Improvement Proposal) status. It changes the proposal's action type and emits relevant events to notify the public or developers.
The incrementTimechainCounter function increments the timechain counter, allowing the contract to progress to the next timechain.
The emergency executor is an address that can execute certain actions in emergency situations. The emergencyExecutorSign function lets the emergency executor execute proposals.
The _executeSignRedeemTransaction function emits the RedeemTransactionSigned event as a placeholder action. The isTechnicalMember function checks if an address is a technical member (placeholder logic).
The contract can be paused and unpaused by the contract owner using the pause and unpause functions. While paused, certain functions are disabled to prevent actions from being taken.
The getCurrentSession, getCurrentEra, and getCurrentTimechain functions calculate the current session, era, and timechain based on the current block timestamp and the contract's duration constants.
gdv= mining reeedemption will be done only after 1 timechain+1 session if technical members not present for gdv redemption
gdvToken: Address of the GDV token contract. - what is this point soham @123456788940
Basically if foundation committee is not present pseudo address will can sign the transaction after 1 session is done after that 1 timechain period @vinaykumar0103
@vinaykumar0103 check it out
@vinaykumar0103 @sscodez @123456788940 @yashpandey59 @shivasai780 Please Work on these