👋Welcome

Hello, I hope you're well. We've already developed these packages to help you get better. Yes, because I've developed with a lot of blockchain networks and I've done the same things in many, many different ways and that's why MultipleChain was born.

What is it?

Shortly: A project to standardize the general characteristics of blockchain networks both across blockchain networks and across languages.

As you know, there are hundreds of different blockchain networks. Although they all have different infrastructures (although some of them are the same, namely EVM), they all basically have the same features. For example: native coins, contracts, tokens, transactions, and signature processes.

But in each of them, you need to do these basic operations or get data. You need to write different code, use different libraries, and read a lot of documentation. You don't need any of this if you don't want to go deep into a single network! Because now you have MultipleChain.

MultipleChain is a collection of packages that aims to standardize the most basic elements across disparate blockchain networks. And not just between blockchains. It also aims to do this between programming languages. The first packages have been developed for the Bitcoin, Ethereum (EVM), Solana, and Tron blockchains, and the JavaScript and PHP programming languages!

Examples

Now let's make transfers on the Ethereum and Solana blockchain networks with Ethers and Solana Web3.js packages

Ethereum (Ethers)

You need to write a code roughly like the one below, but I haven't tested it and it might be missing!

import { Contract, Wallet, JsonRpcProvider, TransactionRequest } from 'ethers'

const privateKey = '...'
const contractAbi = [/* ... */]
const contractAddress = '0x...'
const provider = new JsonRpcProvider('rpc url')
const signer = new Wallet(privateKey, provider)

const sender = signer.address
const receiver = '0x...'
const hexAmount = '0x1'

const getGasPrice = async (): Promise<string> => {
    return (await provider.send('eth_gasPrice', [])).toString()
}

const getNonce = async (address: string): Promise<number> => {
    return await provider.getTransactionCount(address)
}

// Coin transfer
const coinTransfer = async () => {
    const txData: TransactionRequest = {
        data: '0x',
        chainId: 1,
        to: receiver,
        from: sender,
        value: hexAmount,
    }

    const [gasPrice, nonce, gasLimit] = await Promise.all([
        getGasPrice(),
        getNonce(sender),
        provider.estimateGas(txData)
    ])

    txData.nonce = nonce
    txData.gasPrice = gasPrice
    txData.gasLimit = gasLimit

    const signedData = await signer.signTransaction(txData)

    return await provider.send('eth_sendRawTransaction', [signedData])
}

// Token transfer
const tokenTransfer = async () => {
    const token = new Contract(contractAddress, contractAbi, signer)

    const [gasPrice, nonce, data, gasLimit] = await Promise.all([
        getGasPrice(),
        getNonce(sender),
        token.interface.encodeFunctionData('transfer', [receiver, hexAmount]),
        token.transfer.estimateGas(receiver, hexAmount, { from: sender })
    ])

    const txData = {
        data,
        nonce,
        gasPrice,
        gasLimit,
        chainId: 1,
        from: sender,
        value: '0x0',
        to: contractAddress
    }

    const signedData = await signer.signTransaction(txData)

    return await provider.send('eth_sendRawTransaction', [signedData])
}

Solana (Web3.js)

You need to write a code roughly like the one below, but I haven't tested it and it might be missing!

import bs58 from 'bs58'
import { PublicKey, SystemProgram, Transaction, VersionedTransaction, Connection, Keypair } from '@solana/web3.js'
import { getAssociatedTokenAddressSync, createAssociatedTokenAccountInstruction, createTransferInstruction } from '@solana/spl-token'

const amount = 1
const sender = 'sender public key'
const receiver = 'receiver public key'
const privateKey = 'sender private key'
const contractAddress = 'contract address'

const provider = new Connection('https://api.devnet.solana.com', 'confirmed')

const fromLamports = (amount: number, decimals: number = 9): number => {
    return amount / Math.pow(10, decimals);
}

const toLamports = (amount: number, decimals: number = 9): number => {
    return amount * Math.pow(10, decimals);
}

const getRawTransaction = (encodedTransaction: string): Transaction | VersionedTransaction => {
    let recoveredTransaction: Transaction | VersionedTransaction
    try {
        recoveredTransaction = Transaction.from(Buffer.from(encodedTransaction, 'base64'))
    } catch (error) {
        recoveredTransaction = VersionedTransaction.deserialize(
            Buffer.from(encodedTransaction, 'base64')
        )
    }
    return recoveredTransaction
}

const signTransaction = async (transaction: Transaction) => {
    transaction.recentBlockhash = (
        await provider.getLatestBlockhash('finalized')
    ).blockhash

    const serialized = transaction.serialize({
        requireAllSignatures: false,
        verifySignatures: true
    })

    
    const feePayer = Keypair.fromSecretKey(bs58.decode(privateKey))
    const rawTx = getRawTransaction(serialized.toString('base64'))

    if (transaction instanceof VersionedTransaction) {
        transaction.sign([feePayer])
    } else {
        transaction.partialSign(feePayer)
    }

    return transaction.serialize()
}

// Coin transfer
const coinTransfer = async () => {
    const lamports = toLamports(amount)
    const senderPubKey = new PublicKey(sender)
    const receiverPubKey = new PublicKey(receiver)
    
    const transaction = new Transaction().add(
        SystemProgram.transfer({
            fromPubkey: senderPubKey,
            toPubkey: receiverPubKey,
            lamports
        })
    )
    
    transaction.feePayer = senderPubKey

    const signedTx = await signTransaction(transaction)

    return await provider.sendRawTransaction(signedTx)
}    

// Token transfer
const tokenTransfer = async () => {
    const transaction = new Transaction()
    const ownerPubKey = new PublicKey(sender)
    const spenderPubKey = new PublicKey(receiver)
    const receiverPubKey = new PublicKey(receiver)
    const transferAmount = toLamports(amount, 12)
    const contractPubKey = new PublicKey(contractAddress)

    const ownerAccount = getAssociatedTokenAddressSync(
        contractPubKey,
        ownerPubKey,
        false
    )

    const receiverAccount = getAssociatedTokenAddressSync(
        contractPubKey,
        receiverPubKey,
        false
    )

    if ((await provider.getAccountInfo(receiverAccount)) === null) {
        transaction.add(
            createAssociatedTokenAccountInstruction(
                spenderPubKey,
                receiverAccount,
                receiverPubKey,
                contractPubKey
            )
        )
    }

    transaction.add(
        createTransferInstruction(
            ownerAccount,
            receiverAccount,
            spenderPubKey,
            transferAmount
        )
    )

    transaction.feePayer = spenderPubKey

    const signedTx = await signTransaction(transaction)

    return await provider.sendRawTransaction(signedTx)
}

The examples above are just examples of native coin and token transfers on two networks. There is a lot of code and complexity in both, isn't there? Especially when you get into the "everything is account" aspect in Solana, you will get even more confused.

There is still the matter of getting the data of the transactions in a readable format. So actually, when you expand the scope, things get more complicated for each blockchain network.

So, would you like to see how you can easily do the same thing in MultipleChain for both Solana and Ethereum?

MultipleChain

Yes, the same transfer operations in the examples given above for Ethereum and Solana are as follows in MultipleChain. This is exactly what we are aiming for. If developers don't need to go deep into a network and just want to perform basic operations, they should be able to do it in the simplest way.

import * as EVM from '@multiplechain/evm-chains'
import * as Solana from '@multiplechain/solana'

// Ethereum
const ethereumProcess = async () => {
    // Provider have to be initialized
    new EVM.Provider(EVM.networks.ethereum)

    const amount = 0.1
    const sender = '0x'
    const receiver = '0x'
    const privateKey = '0x'
    const tokenContract = '0x'
    const coin = new EVM.assets.Coin();
    const token = new EVM.assets.Token(tokenContract);

    const coinTx = await coin.transfer(sender, receiver, amount)
    const tokenTx = await token.transfer(sender, receiver, amount)

    return {
        coinTxId: await (await coinTx.sign(privateKey)).send(),
        tokenTxId: await (await tokenTx.sign(privateKey)).send()
    }
}


// Solana
const solanaProcess = async () => {
    // Provider have to be initialized
    new Solana.Provider({ testnet: true })

    const amount = 0.1
    const sender = '...'
    const receiver = '...'
    const privateKey = '...'
    const coin = new Solana.assets.Coin();
    const token = new Solana.assets.Token('...');

    const coinTx = await coin.transfer(sender, receiver, amount)
    const tokenTx = await token.transfer(sender, receiver, amount)

    return {
        coinTxId: await (await coinTx.sign(privateKey)).send(),
        tokenTxId: await (await tokenTx.sign(privateKey)).send()
    }
}

Last updated