It’s become quite popular nowadays for groups of individuals to ‘pool’ together funds, in order to participate at an ICO which has a mandatory minimum investment.

The way this usually works is you pick a leader who contacts the ICO, negotiates a bonus and other conditions, and does the KYC process.

Everyone sends ETH to the leader’s personal wallet, while he updates an Excel sheet with each contribution, or uses a centralized platform. Then he sends all the funds to the ICO’s wallet, and after the token sale, when the ICO transfers a bunch of tokens to him in return, he starts to distribute them to the other participants, proportionally to their contribution.


This usually works out, but not always: human errors are possible while doing calculations and needless to say, you are totally trusting a single person to hold a large amount of funds. Some platforms, like PrimaBlock, go a step in the right direction, but they’re still not fully decentralized, as stated by a disclaimer on their website: the pool’s owner has the power to mismanage funds.


What’s great about our solution is that it will keep all the benefits of the existing process, but will reduce the risk of losing funds, by replacing middle man calculation with public code. In simple words, instead of sending funds to a person, you send them to a piece of code: an Ethereum smart contract.

All participants have equal rights. There is no owner or leader. Anyone can join, leave & send the pooled funds to the ICO, subject to the pool limits, specified upon creation. This means you are solely responsible for the decisions to join, leave, send funds & withdraw.

There are currently no fees, other than normal transaction gas fees, though in the near future, our platform will require a small, fixed fee, paid in ECTO.

There’s only 2 pieces of information the contract needs:

  • the ICO wallet address, supplied at creation time, where the pool will send it’s entire ETH balance
  • the ERC20 token contract address, supplied later, together with the withdraw transaction, by each participant

In order to better explain the inner workings, without going into actual code too much, let’s try to tell a short story of how the process unfolds, step by step:

1. Negotiation

Just like before, an individual, contacts the ICO to negotiate prices, bonuses and other conditions. If done through email, it’s a good idea to put other participants in the BCC of the email, so they can also double-check the ICO wallet address (given by the ICO). But this is not mandatory, as any participant can contact the ICO independently and check that the wallet address is correct. Virtually all ICOs are fine with this.

If the ICO asks what your ETH wallet address is, from which you will send the funds, you must give them the newly created pool’s address. This is publicly visible on our platform, after creating a pool, and is needed because it’s the pool who sends the actual funds to the ICO, and in turn, gets assigned a bunch of ERC20 tokens.

2. Creating a trustless pool, as a non-fungible token here

Anyone (doesn’t matter who) creates a non-fungible pool token on our platform, by putting in a title, description, the ICO’s wallet address and optional limits for the pool. If the ICO asks for your ETH address, you must give them this newly created pool’s address, which is easy to copy from our platform.

3. Join or leave the pool at any time

Any interested individual can join the pool by sending ETH to the pool’s address. This is recorded inside the smart contract, using a standard solidity storage pattern:

contract EthManager{
     address[] public participants;
     mapping(address => uint256) contributions;

Likewise, any participant can leave the pool at any time before the funds are transferred to the ICO’s wallet, getting his ETH contribution back.

For both operations, the participant initiates the transaction by simply pressing a button on our platform (we’ve integrated with Metamask for on-chain operations), and only pays for the gas used by the transaction. Alternatively, MyEtherWallet or any other wallet can be used to send funds or leave the pool, by putting in the pool’s address in it.

We like to keep our contracts simple and having a single responsibility. This part of the pool process is handled by a separate base contract, and has only a couple of non-constant methods:

function join() public payable {...}
function leave() public {...}

These methods have several checks in place, to prevent things like:

double join or leave

  • joining or leaving after the pool has sent its funds to the ICO
  • leaving without joining first
  • any other optional pool restrictions, etc…

All required information about a participant is contained within the msg globally available structure (msg.sender address and msg.value ETH amount), thus the methods require no arguments.

4. Pool buys tokens (sends ETH to the ICO wallet)

Any participant in the pool can initiate this transaction, subject to the pool’s public restrictions.

If anyone can send the funds to the ICO, how do we prevent funds from being sent too early? That’s what the optional pool restrictions are for:

  • Min individual contribution.
  • Max individual contribution.
  • Min total contributions.
  • Max total contributions.
  • Min date before buying tokens is allowed.

We are also considering adding a new optional restriction so that only the pool creator can buy tokens. All restrictions are optional. The creator can specify any/all of these upon creation.

The pool’s entire balance is now sent to the ICO wallet, which will, in turn, transfers a proportional amount of tokens to the pool’s address. In case of a private sale, this usually happens later, during the public sale.

This method is implemented in a separate contract:

contract IcoPool is TokenManager{
    address public icoWalletAddress;
    function buy() public {...}

Needless to say, there’s several checks and balances at each step of the process, and we adhere to the Checks-Effects-Interactions pattern recommended in the docs.

5. Time passes, participants withdraw their token share from the pool

Either immediately, or, in case of a private sale, sometime later, the ICO transfers tokens to the pool, so the pool is now the proud owner of a lot of tokens. Each participant can then withdraw ERC20 tokens from the pool, by initiating the transaction himself. We’ve used the recommended withdrawal pattern, about which you can read more on the official docs:

Common Patterns – Solidity 0.4.21 documentation

Edit description
The pool’s smart contract code knows the sender’s contribution ratio, the number of his previously withdrawn tokens and the total withdrawn tokens by everyone in the pool. These 3 pieces of information allows it to compute the amount of tokens the sender is entitled to now, according to the formula:

mapping(address => uint256) withdrawals;
function withdraw(address tokenAddress) public
 ... various checks ...
 maxTokensEver = poolCurrentTokenBalance + totalWithdrawnTokensByAll
 userContributionRatio = userContribution / totalContribution
 allowedToWithdraw = maxTokensEver * userContributionRatio 
                     — anyAlreadyWithdrawnByUser
 ... transfer the tokens ...

The pool then transfers allowedToWithdraw tokens to the participant’s wallet.

This deceptively simple but dare we say beautiful calculation actually takes into account:

  • Any subsequent bonuses given by the ICO to the pool.
  • Different ERC20 token decimals, as it’s the ICO’s token sale code which must scale transfers to the pool, based on any difference in decimals (18 for ETH vs X for their token), though most ERC20 tokens actually have 18 decimals as well).

In actual Solidity code, this calculation is implemented in an equivalent form, to accommodate for the lack of floating point instructions in Solidity, by forcing a common denominator.

6. Pool gives bonuses

This is a fairly common scenario and fully supported the formula at step 5. Each participant can initiate a new withdraw transaction, and the extra tokens from the bonus difference will be transferred to his wallet, just like the initial amount.


Well … that’s it, really. We’ve done extensive testing: unit, positive, negative, bonuses and tried out various attacks. The pool is resilient. The code will be hosted on GitHub soon, for peer review.

For more information or feedback, feel free to reach out to devs on our Telegram channel.

Written by Andrei Dan Singeorzan

Prepared and edited by Andrew Carroll, Journalism MA in DIT. 

If you would like to have your company featured in the Irish Tech News Business Showcase, get in contact with us at [email protected] or on Twitter: @SimonCocking

Pin It on Pinterest

Share This