基于时间的 Staking 合约:需要避免循环

Staking contract based on time: need to avoid loop

我们正在以太坊主网上构建一个抵押智能合约。所有的赌注都需要附加一个时间戳,所以我们的逻辑依赖于时间。 逻辑是在月底每个利益相关者都会有信用,并且基于此,合约所有者将根据每个利益相关者的信用金额将奖励分配给每个利益相关者。但是为了获得总的 creditsAmount,我们需要遍历 stakeHolders 列表,这是非常昂贵的。 这是我们的质押合约的一个非常简短的示例:

pragma solidity 0.8.6;
import “@openzeppelin/contracts/utils/structs/EnumerableSet.sol”;

contract Test {
  using EnumerableSet for EnumerableSet.AddressSet;

  struct Stake {
    uint256 lockedToken;
    uint256 creditsEarned; // numberOfDays * lockedToken = 15days * 1000 = 15000
  }
  
  // Rewards = RatioOfCreditsEarnedByStakeholder * MonthlyRewards

  EnumerableSet.AddressSet private stakeholders;
  mapping(address => Stake) private stakeholderToStake;

  function createStake(
   address stakeholder,
   uint256 lockedToken,
   uint256 creditsEarned
  ) public {
   stakeholders.add(stakeholder);
   stakeholderToStake[stakeholder] = Stake({
     lockedToken: lockedToken,
     creditsEarned: creditsEarned
   });
  }
      
function distributeRewards() public {
  uint256 totalCredits = 0;
  for (uint256 i = 0; i < stakeholders.length(); i++) {
    totalCredits += stakeholderToStake[stakeholders.at(i)].creditsEarned;
      }
    }
   }

正如您想象的那样,最后一个循环的成本非常高,但我们目前还没有找到另一种方法来这样做。你对如何避免这种循环有什么想法吗?还是其他像我们一样依赖时间的质押合约?

谢谢

为了扩展我的评论,我将这样做。

pragma solidity 0.8.6;
import “@openzeppelin/contracts/utils/structs/EnumerableSet.sol”;

contract Test {
using EnumerableSet for EnumerableSet.AddressSet;

struct Stake {
      uint256 lockedToken;
      uint256 creditsEarned;
   }
  
  // Rewards = RatioOfCreditsEarnedByStakeholder * MonthlyRewards

  EnumerableSet.AddressSet private stakeholders;
  mapping(address => Stake) private stakeholderToStake;
      
  uint256 private totalCredits;

  function createStake(
     address stakeholder,
     uint256 lockedToken,
     uint256 creditsEarned
  ) public {
      stakeholders.add(stakeholder);
      stakeholderToStake[stakeholder] = Stake({
      lockedToken: lockedToken,
      creditsEarned: creditsEarned
     });
    totalCredits += creditsEarned;
  }
      
  function distributeRewards() public {
  //do whatever you want with totalCredits here
   }