Skip to content
Global documentation search

Source Chain Smart Contracts

A source chain smart contract is a contract living on a source chain such as Ethereum that is supported by the Creditcoin Oracle. Source chain contracts have two main responsibilities:

  1. Support any source chain logic required by their Universal DApp.
  2. Emit events that contain the data their DApp needs to verify and process on Creditcoin

Let’s focus on these one by one.

Most logic and data for Universal DApps should live in contracts on Creditcoin rather than the source chain. Keep source chain logic minimal—typically just enough to handle asset movements (e.g., burning tokens, locking assets) and emit events.

Best practices:

  • Minimize source chain logic to reduce gas costs and complexity
  • Keep business logic on Creditcoin
    • So that data and liquidity from many chains can be used in one place
    • And to benefit from lower tx + storage costs
  • Use source chain contracts primarily for emitting events that trigger cross-chain actions

This is the way by which the source chain will communicate with Creditcoin. When a source chain contract emits an event, it becomes part of the transaction’s receipt logs, which can be cryptographically verified on Creditcoin. Imagine that you want a simple DApp which burns ERC20 tokens on Ethereum and mints corresponding ERC20 tokens on Creditcoin. Then you would want your source chain smart contract to emit an event such as TokensBurnedForBridging.

Event design considerations:

  • Use indexed parameters for efficient filtering (up to 3 indexed parameters)
  • Include all data the DApp needs in the event parameters
  • Keep event signatures consistent to simplify parsing in USC contracts

The following example shows a simple ERC20 contract that supports a token bridge DApp. When tokens are “burned” (transferred to a burn address), a custom TokensBurnedForBridging event is emitted, which can be verified on Creditcoin to trigger token minting.

Key features:

  • Emits a custom TokensBurnedForBridging event for easy filtering by offchain workers
  • Uses a burn address (0x...01) to represent token burning
  • The TokensBurnedForBridging event includes all necessary data (from, value)
  • Workers can easily filter for this specific event signature and then generate proofs to submit to the USC contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract TestERC20 is ERC20 {
address public constant BURN_ADDRESS = address(1); // 0x...01
/// @notice Emitted when tokens are burned (sent to the burn address).
/// @param from The address burning their tokens
/// @param value The amount of tokens burned
event TokensBurnedForBridging(address indexed from, uint256 value);
constructor() ERC20("Burn Test", "TEST") {
// Mint sender initial supply
_mint(msg.sender, 1_000_000 ether);
}
/// @notice "Burn" by transferring tokens to the 0x...01 sink address.
/// @dev This does NOT reduce totalSupply; it only makes tokens inaccessible.
/// @param amount The amount of tokens to burn
/// @return success Whether the transfer succeeded
function burn(uint256 amount) external returns (bool) {
_transfer(msg.sender, BURN_ADDRESS, amount);
emit TokensBurnedForBridging(msg.sender, amount);
return true;
}
}

Universal Smart Contracts

Check out this tutorial for an example of how to use the Creditcoin stack to set up a decentralized trustless bridge.