DistributedCollective / Homecoming-Sale

2 stars 2 forks source link

pre deposit contract for the homecoming sale #1

Open ororopickpocket opened 3 years ago

ororopickpocket commented 3 years ago

for the auctions some investor will be able to pre-deposit their funds into a smart contract before the auction starts. the funds will be different BTC-tokens on Ethereum: WBTC, renBTC, tBTC,...

the investors should be able to withdraw their funds any time before the sale starts. therefore, the smart contract will need to remember the investor addresses and how much they invested.

after the sale started, an admin wallet will be able to invest the funds on the auction contract on the investor's behalf. so, it needs to iterate over the array of investors and call the respective function on the auction contract (i think that's bid). because we can't iterate over an unlimited number of addresses, we need to set some maximum per transaction and remember how far we got on the last function.

here's a pseudocode template with some more description:

contract HomecomingPreDeposit{
  address[] investors;
  mapping(address => uint) investments;
  uint lastProcessed;

  function deposit(){
    // only before the sale started
    //transfer the tokens from the sender to this contract
    //update the investor array and investments mapping 
  }

  function withdraw(){
    //only before the sale started
    //check if the sender has made an investment
    //remove the investor from the list and set the investment to 0
    //transfer the tokens to the sender
  }

  function setAuctionContract(){
    //only authorized wallet
  }

  function moveToAuction(){
    //only after sale started
    //can be called by anybody if the auction contract was set
    //iterate over max amount of investors starting from lastProcessed
    //bid per investor
    //update the lastProcessed variable
  }
}
anon-xxs commented 3 years ago

here one issue: in withdraw(), how to remove the investor from the list?

for(uint256 i = 0; i < investors.length; i++) {
    if (investors[i] == msg.sender) {
        delete investors[i];
        // or
        investors[i] = address(0);
    }
}

it's pretty gas-consuming.

And if do so, even though we remove the investor from the list, it still leaves a gap in the array and makes the length of the array untouched. This means, and then in the moveToAuction(), iterate will be pretty gas-consuming as well, and iterate many invalid addresses(address(0))

So here some options from me:

  1. Use the EnumerableMap.AddressToUintMap from OpenZeppelin to replace investors and investments
  2. Use the EnumerableSet.AddressSet of OpenZeppelin to replace investors
  3. Use some variables to store the id of the investors:
    uint256[] investorIds;
    // or
    mapping(address => uint) investorIds;
    // or
    struct investorInfo {
    uint256 id;
    uint256 investment;
    }
anon-xxs commented 3 years ago

Can u explain what these mean: only authorized wallet, the setAuctionContract() only could be called by owner? lastProcessed, what does it store/record?

ororopickpocket commented 3 years ago

Good thinking, Wukong! Your questions are 3 days old, so I'm not sure if you already made a decision by yourself? I could not find you code anywhere. Could you push to this repo?

only authorized wallet, the setAuctionContract() only could be called by owner?

yes, can be the owner.

lastProcessed, what does it store/record?

the last index which was processed on the previous call. As you realized yourself, we can get problems if the investor array is getting too long, because we have to spend gas not just on the iteration, but also on the auction contract call per investor. This is why we might need to process the investors in batches. If we store the last index which was processed, we can pick it up from there on the next function call.