0

Similar question, in need of something simpler

Specs:

  • Each time a user interacts with my contract, I want to deposit 100 USDC into Spirals
  • tokens should be locked for at least 30 days
  • deposited tokens will always be associated to the contract (not the user)

I am thinking to do this using a Batch struct that keeps track of the timestamp the batch will be unlocked and its amount.

Question: Is there a better way to do this? Ideally without using loops.

Current pseudocode solution:

struct Batch {
  uint256 withdrawableTimestamp;
  uint256 amount;
}

contract Depositor {
  
  Batch[] public batches;

  function triggerDeposit() external{
    // deposit 100 USDC
    SpiralsImpactVault(0x123).deposit(10 * 10 ** 18);

    // Add a new batch specifying the unlock date and the amount
    batches.push(Batch(block.timestamp + 30 days, 10 * 10 ** 18));
  }

  function withdraw() external onlyOwner {
    // withdraw all that is withdrawable
    uint256 withdrawableAmount = withdrawable();
    SpiralsImpactVault(0x123).withdraw(withdrawableAmount);

    // update the batches array by popping the first elements, 
    // until `block.timestamp >= batches[i].withdrawableTimestamp`.
    // this is the expensive bit.
    ...
  }
  
  function withdrawable() public view returns (uint256) {
    uint256 withdrawableAmount = 0;
    
    // loop in the array, summing all batches with a past timestamp
    for (uint256 i=0; i < batches.length; ++i) {
      if (block.timestamp >= batches[i].withdrawableTimestamp) {
        withdrawableAmount += batches[i].amount;
      } else {
        break;
      }
    }

    return withdrawableAmount ;
  }
}

1 Answer 1

0

Rather than having one batches array for all the users, I would create a mapping batches (user address => timestamp), so when a user wants to withdraw it would have to iterate only his deposits.

Also (not sure if this is what you had in mind) but for popping make sure to switch deleted items' places with the last element and pop the last element in the array. It will destroy the order but will save space and future iterations.

2
  • deposited tokens will always be associated to the contract (not the user), this is why 1 array of batches would be enough (the only "user" is the contract). Also switching before popping isn't a very good piece of advice. As the elements are pushed in an orderly fashion, I only need to loop the array until I find a date greater than today (then I am sure that all the following batches are still locked). If I change the positions, this assumption won't be true anymore. Commented Feb 9, 2023 at 11:57
  • If that is your goal I agree with the first part, but you should be careful with pushing elements to an array. What will happen is that at some point you will have an arbitrarily large array (since you won't really delete any elements) which causes extremely high gas costs and at some point transaction reversion.
    – Nal Luksic
    Commented Feb 9, 2023 at 12:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.