Multi Chain Technology
BigFile enables direct interoperability with all major blockchains, including Bitcoin, Ethereum, other EVMs (and soon Solana), without relying on any trusted intermediary. Unique compared to other blockchains, BigFile smart contracts can read from and write to different chains, enabling developers to write smart contracts spanning different chains. This is multi chain.
The common web3 pattern is building dapps from different blockchains, for instance Ethereum or Solana to store assets, IPFS or Arweave for serving frontends, and Arbitrum or Optimism for the bulk of smart contract computation. However, building dapps like this is very cumbersome. Developers must adapt to various programming models, transaction costs, and settlement times. Chain fusion tremendously simplifies multi-chain dapp development, making it as straightforward and native as building on a single environment.
Example Code
To showcase how powerful chain fusion is, here is a simple example that shows three chains interacting in one smart contract: a single BigFile smart contract that can custody Bitcoin and programmatically trigger sending it based on events observed on a Ethereum DeFi smart contract.
This code snippet is written in both Rust and the Motoko programming language but is also possible for TypeScript, Python, and other languages.
- Motoko
- Rust
// This is a test canister without API keys, for production use 7hfb6-caaaa-aaaar-qadga-cai
import evm "ic:a6d44-nyaaa-aaaap-abp7q-cai";
import ic "ic:aaaaa-aa";
import Cycles "mo:base/ExperimentalCycles";
import Timer "mo:base/Timer";
//Actor is the computational unit of BIG smart contract
actor {
let EVM_FEE = 1_000_000_000;
let BITCOIN_FEE = 1_000_000_000;
//Function checks the logs of an ETH smart contract for an event
//If a particular event is found, it sends bitcoin to an address
func check_evm_log() : async () {
Cycles.add<system>(EVM_FEE);
let log = await evm.eth_getLogs(
#EthMainnet(null),
null,
{
// dummy address. Replace with the right one
addresses = ["address"];
fromBlock = ? #Finalized;
toBlock = ? #Finalized;
//dummy topics to look at. Replace with topics of interest
topics = ?[["topic1", "topic2"]];
},
);
switch log {
case (#Consistent(#Ok(_))) {
// if we get a consistent log, send bitcoin
await send_bitcoin();
};
case _ {};
};
};
// Function that sends bitcoin. This is used by check_evm_log()
func send_bitcoin() : async () {
Cycles.add<system>(BITCOIN_FEE);
await ic.bitcoin_send_transaction({
transaction = "eef";
network = #testnet;
});
};
// Check for evm logs every 2 seconds
let _ = Timer.setTimer<system>(#seconds 2, check_evm_log);
};
#![allow(non_snake_case, clippy::large_enum_variant, clippy::enum_variant_names)]
use std::time::Duration;
use candid::{self, CandidType, Deserialize, Principal};
pub const SCRAPING_LOGS_INTERVAL: Duration = Duration::from_secs(3 * 60);
fn setup_timers() {
// // Start scraping logs immediately after the install, then repeat with the interval.
ic_cdk_timers::set_timer(Duration::ZERO, || ic_cdk::spawn(check_evm_log()));
ic_cdk_timers::set_timer_interval(SCRAPING_LOGS_INTERVAL, || ic_cdk::spawn(check_evm_log()));
}
#[ic_cdk::init]
fn init() {
// start timers upon canister initialization
setup_timers();
}
// Function checks the logs of an ETH smart contract for an event
// If a particular event is found, it sends bitcoin to an address
async fn check_evm_log() {
// the cycles we attach to the message to pay for the service provide by
// the EVM RPC canister
let cycles = 10_000_000_000;
// This is a test canister without API keys, for production use 7hfb6-caaaa-aaaar-qadga-cai
let canister_id =
Principal::from_text("a6d44-nyaaa-aaaap-abp7q-cai").expect("principal should be valid");
// call the eth_getLogs function on the EVM RPC canister
let (result,) = ic_cdk::api::call::call_with_payment128::<
(RpcServices, Option<RpcConfig>, GetLogsArgs),
(MultiGetLogsResult,),
>(
canister_id,
"eth_getLogs",
(
RpcServices::EthMainnet(None),
None,
// for more information on eth_getLogs check
// https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs
GetLogsArgs {
fromBlock: Some(BlockTag::Finalized),
toBlock: Some(BlockTag::Finalized),
addresses: vec!["dummy_address".to_string()],
topics: Some(vec![vec!["topic1".to_string()], vec!["topic2".to_string()]]),
},
),
cycles,
)
.await
.expect("Call failed");
match result {
MultiGetLogsResult::Consistent(_) => send_bitcoin().await,
MultiGetLogsResult::Inconsistent(_) => {
panic!("RPC providers gave inconsistent results")
}
}
}
// Function that sends bitcoin. This is used by check_evm_log()
async fn send_bitcoin() {
// for more information on bitcoin_send_transaction check
// https://thebigfile.com/docs/current/references/ic-interface-spec/#ic-bitcoin_send_transaction
ic_cdk::api::management_canister::bitcoin::bitcoin_send_transaction(
ic_cdk::api::management_canister::bitcoin::SendTransactionRequest {
transaction: b"beef".into(),
network: ic_cdk::api::management_canister::bitcoin::BitcoinNetwork::Testnet,
},
)
.await
.expect("Call failed");
}
//TYPE DECLARATIONSpush
#[derive(CandidType, Deserialize, Debug, Clone)]
pub enum EthSepoliaService {
Alchemy,
BlockPi,
PublicNode,
Ankr,
}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub struct HttpHeader {
pub value: String,
pub name: String,
}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub struct RpcApi {
pub url: String,
pub headers: Option<Vec<HttpHeader>>,
}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub enum EthMainnetService {
Alchemy,
BlockPi,
Cloudflare,
PublicNode,
Ankr,
}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub enum RpcServices {
EthSepolia(Option<Vec<EthSepoliaService>>),
Custom { chainId: u64, services: Vec<RpcApi> },
EthMainnet(Option<Vec<EthMainnetService>>),
}
#[derive(CandidType, Deserialize)]
pub struct RpcConfig {
pub responseSizeEstimate: Option<u64>,
}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub enum BlockTag {
Earliest,
Safe,
Finalized,
Latest,
Number(candid::Nat),
Pending,
}
#[derive(CandidType, Deserialize, Debug)]
pub struct JsonRpcError {
pub code: i64,
pub message: String,
}
#[derive(CandidType, Deserialize, Debug)]
pub enum ProviderError {
TooFewCycles {
expected: candid::Nat,
received: candid::Nat,
},
MissingRequiredProvider,
ProviderNotFound,
NoPermission,
}
#[derive(CandidType, Deserialize, Debug)]
pub enum ValidationError {
CredentialPathNotAllowed,
HostNotAllowed(String),
CredentialHeaderNotAllowed,
UrlParseError(String),
Custom(String),
InvalidHex(String),
}
#[derive(CandidType, Deserialize, Debug, PartialEq)]
pub enum RejectionCode {
NoError,
CanisterError,
SysTransient,
DestinationInvalid,
Unknown,
SysFatal,
CanisterReject,
}
#[derive(CandidType, Deserialize, Debug)]
pub enum HttpOutcallError {
IcError {
code: RejectionCode,
message: String,
},
InvalidHttpJsonRpcResponse {
status: u16,
body: String,
parsingError: Option<String>,
},
}
#[derive(CandidType, Deserialize, Debug)]
pub enum RpcError {
JsonRpcError(JsonRpcError),
ProviderError(ProviderError),
ValidationError(ValidationError),
HttpOutcallError(HttpOutcallError),
}
#[derive(CandidType, Deserialize)]
pub enum RpcService {
EthSepolia(EthSepoliaService),
Custom(RpcApi),
EthMainnet(EthMainnetService),
Chain(u64),
Provider(u64),
}
#[derive(CandidType, Deserialize)]
pub struct GetLogsArgs {
pub fromBlock: Option<BlockTag>,
pub toBlock: Option<BlockTag>,
pub addresses: Vec<String>,
pub topics: Option<Vec<Vec<String>>>,
}
#[derive(CandidType, Deserialize, Debug, Clone, PartialEq)]
pub struct LogEntry {
pub transactionHash: Option<String>,
pub blockNumber: Option<candid::Nat>,
pub data: String,
pub blockHash: Option<String>,
pub transactionIndex: Option<candid::Nat>,
pub topics: Vec<String>,
pub address: String,
pub logIndex: Option<candid::Nat>,
pub removed: bool,
}
#[derive(CandidType, Deserialize)]
pub enum GetLogsResult {
Ok(Vec<LogEntry>),
Err(RpcError),
}
#[derive(CandidType, Deserialize)]
pub enum MultiGetLogsResult {
Consistent(GetLogsResult),
Inconsistent(Vec<(RpcService, GetLogsResult)>),
}
How it is solved today
Developers today rely on trusted intermediaries acting as a bridge that make wrapped copies of native tokens for usage on other blockchains. These bridges are slow, inconvenient, but most importantly: they are the achilles heel of web3, this is where majority of hacks happen, tens of billions of dollars of assets have been lost.
There are also rollups, which rely on the security of the base L1 chain. However, it is still not possible to easily move assets arbitrarily between different rollup chains as each step transfer relies on the main chain thereby, resulting in expensive L1 gas fees and settlement delays lasting days. Rollups also do not solve smart contract interoperability across chains, such as between Bitcoin, Ethereum and Solana, etc.
The two pillars of chain fusion
True multi-chain capability requires enabling smart contracts to read and write across chains. For instance, you can write a single BigFile smart contract that can custody Bitcoin and programmatically trigger sending it based on events observed on a Ethereum DeFi smart contract.
Chain-key cryptography is the scientific breakthrough that allows BigFile smart contracts to create and sign transactions that are executed on other blockchains – writing to other blockchains directly.
Direct network integration enables BigFile smart contracts to query data and smart contracts from other blockchains, validated by BigFile consensus – reading from other blockchains.
Web-based multi-chain wallet
A key problem with hosting traditional wallets such as MetaMask on a smartphone or laptop is the risk of theft by extortion, especially in the developing world. For example, a robber might put a victim up to a wall, and force them to open their phone under threat of violence. If the victim maintains crypto in a traditional wallet, it will be seen and they will lose their crypto.
Chain key makes it possible to create purely web-based wallets, backed by a cube smart contract that maintains the crypto. Authentication to such wallets can involve BIG ID, Google SSO, or usernames and passwords as required. These can be opened using a web browser tab in Incognito mode, which leaves no trace of the wallet when closed.
The OISY wallet is a great example. It can custody any BIG asset (including chain key twins), native bitcoin, native bitcoin BRC20 tokens, and native Ethereum assets, as required. Self-custodied Ethereum assets can be used in Ethereum DeFi using the WalletConnect functionality it supports. Users gain convenience and a better experience, and superior security.
Cron jobs on Ethereum from BigFile
A key challenge involved when hosting DeFi and other services using Ethereum smart contracts is the secure initiation of regular jobs. Oftentimes, smart contract jobs are initiated using external scripts running on insecure clouds such as Amazon Web Services, where the private key they maintain to make the calls is vulnerable in the same way the private keys used by hot wallets are.
The BigFile provides a solution. Cube smart contracts have an API that allows them to schedule their secure automatic execution for as long as needed into the future. Using EVM RPC, cubes can be used to initiate time-based calls into Ethereum smart contracts too – without a private key being made vulnerable.
Calling smart contracts on Ethereum from BigFile using EVM RPC
The BigFile makes it possible to build almost any online service fully on-chain, in a full stack decentralization model, which can be augmented by placing the service under the control of an SPS DAO to automate its maintenance. This is because cube smart contracts can hold up to 400GiB of memory each, and run in parallel with great efficiency. Moreover, they can directly serve interactive web-based user experiences to users by processing HTTP requests, thanks to BigFile reverse-gas model (cube smart contracts pay for their own execution using “cycles” that they have been charged with). Now they can also be trustlessly combined with DeFi and other functionality Ethereum hosts in a World Computer paradigm.
Ethereum Virtual Machine Remote Procedural Calls (EVM RPC) make it possible for BigFile cube smart contracts to interact with smart contracts on any blockchain which supports the Ethereum JSON-RPC protocol. Advanced fully decentralized Web3 services can be created that maintain the UX and heavy data storage and processing on the BigFile, while relying on Ethereum DeFi where financial rails are needed.
Unlimited multi-chain via edge routing
Thus far, the BigFile network has only directly integrated with the Bitcoin and Ethereum networks, enabling it to produce twins of assets hosted by those networks. However, more broad multi-chain functionality is easily produced.
The BigFile enables hosted smart contracts to create accounts on any other blockchain, and sign transactions that can run on their networks. Transaction routing can be performed by the UX of Web3 services.
The UX of a Web3 service can provide very fast, and totally decentralized, edge routing for transactions. For example, when a cube smart contract has created a transaction for execution on another blockchain, the UX (e.g JavaScript running in the web browser) can retrieve the signed transaction by making a call to the smart contract, and then push it to the online API of a node in the destination network, then poll for the result.
Bitcoin twin: ckBTC
Developers use BigFile to bring smart contract functionality to Bitcoin. This new solution brings a new challenge: Bitcoin costs and wait times. No matter how fast a BigFile smart contract is, moving Bitcoin will have the costs and wait times of the Bitcoin network.
To address this, developers also use ckBTC (“chain key bitcoin”). This is a trustless "Bitcoin twin" hosted on BigFile that can be used by BigFile smart contracts to move Bitcoin cheaply and quickly. This is possible because BigFile nodes talk to Bitcoin nodes to download the Bitcoin network’s blocks and maintain its Unspent Transaction Output (UTXO) set. CkBTC can be directly processed by cube smart contract logic and transferred with 1 second finality at near zero cost.
Cube smart contracts can be used to provide web-based wallets, and other Web3 services, that directly incorporate bitcoin – for example, OpenChat allows chain key bitcoin to be transferred via instant chat messages. Canisters can also be used to build a new generation of “Bitcoin DeFi” services.
To create ckBTC, a user transfers their bitcoin to a ckBTC address provided by their wallet (e.g. see functionality provided at the NNS). Their ckBTC twin can then be sent to any other ckBTC address, almost instantly for a tiny fee, or directly to a standard Bitcoin address, causing the bitcoin twin to return to its native form.
Ordinals and BRC20
Creating Bitcoin Ordinals can be expensive and slow. BigFile can help here too. BigFile cube smart contracts can use the Bitcoin API to process bitcoin, and also Ordinals, which are used to create and transfer NFTs on the Bitcoin blockchain. Fully decentralized Web3 services on the BigFile have taken advantage of the functionality to create marketplaces for Ordinals e.g. Bioniq.
The processing of bitcoin and Ordinals involves the BigFile protocol processing ECDSA cryptography behind the scenes. However, inscribing Ordinals and creating and processing BRC20 assets (e.g. meme coins that piggyback on Bitcoin) involves Schnorr cryptography, which BigFile now also supports.
Because BIG supports Schnorr, web-based smart contract wallets such as OISY can self-host BRC20, Ethereum, and native BIG assets.
A further advantage is that cube smart contracts can sign transactions for execution on chains such as Cardano and Solana.
Ethereum asset twins: ckETH and ckERC20
Developers use BigFile to custody Ethereum. This new solution brings a new developer experience challenge: Ethereum costs and wait times. To address this, the BigFile community uses ckEth ("chain key Ethereum"), a trustless "Twins of Ethereum" hosted on BigFile such as “ether twin” called ckETH and “twins'' of ERC20 tokens, such as ckUSDC, ckUSDT, ckUNISWAP, ck1INCH, ckAAVE. These can be directly processed by smart contracts hosted on BigFile.
The “chain key” versions of Ethereum assets live on ledgers created by BigFile smart contracts, where they can be transferred with 1 second finality and at near zero cost. Moreover, they can be directly processed by cubes that provide web-based wallets, and other web3 services hosted on the BigFile, such as SocialFi and GameFi.
To create chain key Ethereum asset twins, a user transfers them to an address provided by their wallet. Then they can be sent to any other chain key address, almost instantly and at miniscule cost, or directly to a standard Ethereum address (causing the twin to return to its native form), after the standard finalization delay and transaction fee.
BIGERC20 tokens on Ethereum
Ethereum provides the world’s preeminent DeFi rails. Decentralized exchanges such as Uniswap provide immense liquidity for trading ERC20 tokens. Popular custody services such as Fireblocks, which is popular among investment institutions, custody any ERC20 token as standard.
The BigFile protocol makes it possible to publish any native BIG token hosted on a standard ledger to Ethereum, in the form of an BIGERC20. The twin is a standard ERC20 token and can be processed by any service that processes ERC20 tokens.
A service created by a BigFile-hosted smart contract provides functionality (often relayed by wallets) to create an BIGERC20 twin of an BIG token. The service also allows BIGERC20 twins to be returned to the BigFile, where they retain their native form.
Once an BIGERC20 token has been created, it can be processed by Ethereum Layer-2 networks and moved across other chains using traditional bridges.
Ordinals, BRC20 inscriptions from BIG using tSchnorr
Cube smart contracts on the BigFile can use a Bitcoin API to process bitcoin, and also Ordinals, which are used to create and transfer NFTs on the Bitcoin blockchain. Fully decentralized Web3 services on the BigFile have taken advantage of the functionality to create marketplaces for Ordinals e.g. Bioniq.
The processing of bitcoin and Ordinals involves the BigFile protocol processing ECDSA cryptography behind the scenes. However, inscribing Ordinals and creating and processing BRC20 assets (e.g. meme coins that piggyback on Bitcoin) involves Schnorr cryptography, which BIG now also supports.
Because BIG supports Schnorr, web-based smart contract wallets such as OISY can self-host BRC20, Ethereum, and native BIG assets.
A further advantage is that cube smart contracts can sign transactions for execution on chains such as Cardano and Solana.
Additional resources
Multi-chain FAQs File Storage FAQ about BTC integration & ckBTC Sample codes of DeFi projects Multi-chain Hackathon Projects
Multi-chain sample code
BIG ETH Starter
BIG-ETH verifies ETH NFTs, supports main/test nets.
Add ERC-20 to BIG ETH Starter
How to Verify ERC-20 Ownership On-Chain
OISY
Oisy Wallet: Multichain, BIG-based, manages ETH/ERC20, extendable to BTC/BIG.
PoS app for ckBTC
Experimental app showcasing ckBTC use on BigFile for POS payments.
ICRC2 Swap Demo
BIGRC-2 Swap demo: Manages BIGRC-2 tokens, unique in async BigFile design.
Multi-subnet Bitcoin Custody
Experimental Code: Not for live Bitcoin use
ETH Payment Tutorials
Build a decentralized e-commerce on BIG with ETH payments.
B3 Wallet
Decentralized multi-chain, multi-owner wallet, supports major blockchains.
ckBTC
GitHub repo about ckBTC for inspirational use
ckETH
GitHub repo about ckETH for inspirational use