Developing an ICO using Laravel

by Nikola Gjorgievski

10 min read

Are you interested in issuing your own Token and making an ICO (Initial Coin Offering)? Search no more! I’ve put together a tutorial that will help you understand the technology better and take part in the crypto movement.

First, I will explain the technologies we are going to use. Then, I will walk you through the steps of setting up your account on MyEtherWallet, issuing your first token on the Ethereum network, and creating an ICO using Laravel.

DISCLAIMER: You take full responsibility for how you use this tutorial and what you do with your ETH. I strongly recommend that you consult with a blockchain expert if you're reading this for commercial purposes.

Prerequisites

Before we start I'd like to go through the related terminology, so you have a clear understanding of it.

  1. Cryptocurrency
  2. Wallet
  3. Blockchain
  4. ICO

Cryptocurrency

Cryptocurrency is a digital currency. It solves the problem of inflation by not allowing us to issue new money when we feel like it.

Cryptocurrencies are global. Despite the different laws and regulations of the countries, cryptocurrencies enable us to trade equally, around the globe.

The main goal of cryptocurrency is the separation of money and state.

Cryptocurrencies have their drawbacks, too. Since they are anonymous, they can easily be used for illegal purposes. And their free usage beyond country borders makes tax regulations tough.

Wallet

A wallet is your personal account that allows you to store and transact with your cryptocurrencies. It's protected with a private key that unlocks the account. Pay close attention to how you store this key because losing it would mean losing access to your funds forever.

What are the characteristics of cryptocurrency transactions?

  • They are anonymous. When you want to make a transaction, you generate a public address using your private key. You can generate as many as you want and this enables you to keep your anonymity.
  • The transactions are irreversible. If you make a mistake and send money to a wrong address, you can't change it. Your money is lost and some lucky person can enjoy it.
  • The transactions are fast and global. You can send money anywhere in the world and it takes a few seconds to complete the transaction.

Blockchain

There were many attempts in the past to create a cryptocurrency. They all failed because in a decentralized network, anyone can make false transactions. Unlike banks, there is no centralized server that keeps track of which transactions are correct or false.

The first person who solved this problem is the founder of Bitcoin. He invented the blockchain.

How does the blockchain work?

When a transaction is confirmed, it is added to a block. When the block is full, it is added to the blockchain. After that, the transactions are sealed and it's impossible to change them. That means, if someone wants to add a false transaction in a previous block, they can't do it.

The only option for bad guys is to add the false transaction in the current block. This problem is solved with miners.

Any node in the network can be a miner. The miner's job is to take the new transaction and produce a hash. Every cryptocurrency has its own hash algorithm and rules, but the main purpose of the hash process is that it should take a lot of time and resources to complete. That means, if a bad guy wants to confirm a false transaction, they will have to spend a lot of time hashing it. By the time they finish, they are behind the current ledger and the other nodes can identify that the transaction is fake.

The only possible way to confirm a false transaction, is if someone has control of over 51% of the nodes in the network. But because the network is free and anyone can be a miner, it's close to impossible to have that power.

ICO

ICO stands for Initial Coin Offering. That means that a new cryptocurrency is publicly launched and anyone can invest to get a share of its market. After the launch period, if exchange offices accept the ICO, it becomes a currency.

To launch a new cryptocurrency you will need a whole network of users and miners. Luckily, there are networks that allow us to use their network of miners, so we can focus only on attracting the users.

In this case, we will use Ethereum. Ethereum can process complex contracts and programs and our ICO will be a contract which will live on the Ethereum network.

Developing your ICO

Creating an ICO Contract

The token will be a standard ERC20 token with its main functions. We will use the Ropsten test network to test this without spending real ethereum. We will need:

  • Ethereum address
  • Some ethereum
  • Solidity contract

Creating the token is out of the scope of this article. Follow this tutorial to create your token in less than 20 minutes.

Collecting payments

Now we are ready to launch our ICO and we need a way to collect payments. By this time, I assume that you have already set up your Laravel project.

  • Install this coinbase library for PHP;
  • Go to Coinbase and create an account;
  • Create a new post route in your project, which we will use to receive a notification when a user makes a payment;
  • Go to Settings -> API Access and create a new API key. In the Notification URL, enter the route which we created in the previous step to receive the payments.

To initialize the coinbase client, use this code:

Client::create(
    Configuration::apiKey(
        config('services.coinbase.apiKey'),
        config('services.coinbase.apiSecretKey')
    )
);

The accounts can be found with:

foreach ($client->getAccounts() as $account) {
    switch ($account->getCurrency()) {
        case 'BTC':
            //$account is BTC Account
            break;
        case 'ETH':
            //$account is ETH Account
            break;
        case 'LTC':
            //$account is LTC Account
            break;
    }
}

To receive a payment, we must generate a new address for the user. For example to generate a Bitcoin address use:

$address = new Address();
$client->createAccountAddress($btcAccount, $address);
return $address->getAddress();

We should store the relationship between user and address. That will help us to identify the user later on when we receive a payment on the given address.

Once a user makes a payment to that address, we will receive a request on our webhook url. The request will contain the payment address, amount and currency among other data. We can use the payment address to identify which user made the payment.

Optionally, if our token depends on USD, we should account for the exchange rate between USD and the other cryptocurrencies. For example, to get the exchange rates for Bitcoin we can use:

$client->getExchangeRates('BTC');

Withdrawals

When a user wants to withdraw their tokens (transfer them to their account), we issue a transaction from our Ethereum address (which holds all tokens) to the user's address. In order to make transactions using our smart contract, we must have an API endpoint. We will use infura.io, so go there and create an account.

To issue a transaction on the blockchain we must sign our transactions using our private key. Bad news: the existing PHP libraries don't have this step implemented, so we need to find an alternative. One option is to use a Node.js script to make the transaction. Lets do that.

First, make sure you have node installed on your server. Then, create a new folder and run:

npm init -y
npm install web3 ethereumjs-tx big-integer dotenv

We will also need the contract ABI which we generated on the remix page. To find the contract ABI, select your token and click Details.

ABI step 1

In the window that opens, find the ABI section and click the ?copy button.

ABI step 2

Create a new file abi.json with the copied content and put it in the same folder as the script.

Now, we need to require the dependencies.

const Web3 = require('web3');
const Tx = require('ethereumjs-tx');
const bigInt = require("big-integer");

We can direct 'dotenv' to our .env file, so all our variables, such as Infura API key, address private key, contract address etc., will be stored there.

Change the path parameter to your .env path.

require('dotenv').config({path: '../../.env'});

The script will accept two parameters "ToAddress" and "Amount" and it will return 2 outputs: "status" and "message". The status can be true or false depending on whether the script succeeded or failed. The message will contain the transaction hash (which can be used to check the transaction status), or an error message.

var args = process.argv.slice(2);
if (args.length<2) {
    console.log(0); //status
    console.log('Address and amount are required.'); // message
    process.exit();
}

We will need the following constants:

const network = process.env.WITHDRAWAL_TOKEN_NETWORK; //mainnet or test network
const infuraApiKey = process.env.INFURA_API_KEY;
const privateKey = process.env.PRIVATE_KEY_TOKEN_HOLDER_ACCOUNT;
const contractAddress = process.env.CONTRACT_ADDRESS;
const abi = require('./abi.json');

const target = args[0]; //input parameter
const amount = args[1]; //input parameter

const web3 = new Web3();

web3.setProvider(new web3.providers.HttpProvider('https://' + network + '.infura.io/' + infuraApiKey));

// Get account from private key.
const account = web3.eth.accounts.privateKeyToAccount(privateKey.indexOf('0x') === 0 ? privateKey : '0x' + privateKey);
const contract = new web3.eth.Contract(abi, contractAddress);

Let's define a transaction parameter:

const parameter = {
    from: account.address,
    to: contractAddress
};

Add the parameter data which contains the transaction method and amount.

contract.methods.decimals().call()
    .then((decimals) => {
        parameter.data = contract.methods.transfer(target, bigInt(amount * (10 ** decimals)).toString()).encodeABI();
        return web3.eth.estimateGas(parameter);
    })

Then, add the parameter gasLimit.

Gas is a measure of computational effort. The Ethereum network needs Gas to process every operation and the Gas is paid by the sender of the transaction. Make sure to always have some Ethereum on your account before sending tokens.

gasLimit is basically the maximum amount of Ethereum you’re willing to spend per transaction.

    .then((gasLimit) => {
        // Changes may occur at the moment of estimateGas and the moment of sending transaction, so let's give it a margin.
        parameter.gasLimit = web3.utils.toHex(gasLimit + 10000);
        return web3.eth.getGasPrice();
    })

Then, add the parameter gasPrice. The is the current Gas Price on the Ethereum network.

    .then((gasPrice) => {
        parameter.gasPrice = web3.utils.toHex(gasPrice);
        return web3.eth.getTransactionCount(account.address);
    })

Then, add the parameter nonce. This is the transaction count.

Finally, sign the transaction and send it:

    .then((count) => {
        parameter.nonce = count;
        const transaction = new Tx(parameter);
        transaction.sign(Buffer.from(account.privateKey.replace('0x', ''), 'hex'));
        web3.eth.sendSignedTransaction('0x' + transaction.serialize().toString('hex'))
            .once('transactionHash', (hash) => {
                console.log(1); //status
                console.info(hash); //message
                process.exit();
            })
            .on('error', function(e) {
                console.log(0); // status
                console.log(e); //message
            });
    })
    .catch(function(e) {
        console.log(0); //status
        console.log(e); // message
    });

To call the script from your PHP code, use:

exec('node sendTokens.js ' . $address . ' ' . $amount, $output);

Final Considerations:

Before issuing your ICO on the main net, make sure to have your code audited by a blockchain specialist.

I'd love to hear about your experience on the topic. Share it in the comments below together with any questions/feedback you might have.

FAQs

Q: How to securely store and manage the private keys used in transactions?
Use secure storage solutions like hardware security modules (HSMs), encrypt private keys before storing, and implement access controls and audit logs to manage and protect private keys for transactions.
Q: Are there legal considerations or requirements when launching an ICO?
Yes, launching an ICO involves legal considerations including compliance with securities laws, anti-money laundering (AML) regulations, Know Your Customer (KYC) policies, and potential registration requirements depending on the jurisdiction.
Q: How to handle the scalability of an ICO as the number of participants increases?
Optimize the ICO platform's architecture for high traffic, use scalable cloud services, implement efficient transaction handling methods, and consider layering solutions or sidechains to manage the increasing number of participants efficiently.
Nikola Gjorgievski
Nikola Gjorgievski
Software Engineer

Hikola is a Senior Software Engineer, working remotely with global teams on exciting projects. His contributions make a meaningful impact and bring much value to the team. He writes clean and quality code, using coding standards and design principles. His implementations are dynamic, modular, and easily customizable for different use cases.

Expertise
  • JavaScript
  • Laravel
  • MySQL
  • Node.js
  • ReactJS
  • AWS
  • PHP
  • Vue.js
  • AngularJS
  • +4

Ready to start?

Get in touch or schedule a call.