Skip to content

Commit

Permalink
[WIP] Add SuperToken example
Browse files Browse the repository at this point in the history
  • Loading branch information
rookmate committed Dec 16, 2024
1 parent ec4d245 commit 7fe21bb
Show file tree
Hide file tree
Showing 5 changed files with 398 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/superToken/ISuperToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

interface ISuperToken {
function burn(address user_, uint256 amount_) external;

function mint(address receiver_, uint256 amount_) external;

function balanceOf(address account) external;

function totalSupply() external view returns (uint256);

function transfer(address to, uint256 value) external returns (bool);

function approve(address spender, uint256 value) external returns (bool);

function transferFrom(
address from,
address to,
uint256 value
) external returns (bool);

function allowance(
address owner,
address spender
) external view returns (uint256);
}
83 changes: 83 additions & 0 deletions src/superToken/SuperToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "solady/tokens/ERC20.sol";

/**
* @title SuperToken
* @notice An ERC20 contract which enables bridging a token to its sibling chains.
* @dev Implements a custom ERC20 token with minting and burning capabilities restricted to a socket address
*/
contract SuperToken is ERC20 {
string private _name;
string private _symbol;
uint8 private _decimals;
address public _SOCKET;

// Custom Errors
error NotSOCKET();

modifier onlySOCKET() {
if (msg.sender != _SOCKET) revert NotSOCKET();
_;
}

/**
* @notice Initialize the token with name, symbol, and decimals
* @param name_ The name of the token
* @param symbol_ The symbol of the token
* @param decimals_ The number of decimals for the token
* @dev Sets the token parameters and sets the initial socket address to the contract deployer
*/
constructor(string memory name_, string memory symbol_, uint8 decimals_) {
_name = name_;
_symbol = symbol_;
_decimals = decimals_;
_SOCKET = msg.sender;
}

/**
* @notice Mint tokens to a specified address
* @dev Can only be called by the SOCKET address
* @param to_ The address to mint tokens to
* @param amount_ The amount of tokens to mint
* @custom:modifier onlySOCKET Ensures only the SOCKET can call this function
*/
function mint(address to_, uint256 amount_) external onlySOCKET {
_mint(to_, amount_);
}

/**
* @notice Burn tokens from the caller's balance
* @dev Can only be called by the SOCKET address
* @param amount_ The amount of tokens to burn
* @custom:modifier onlySOCKET Ensures only the SOCKET can call this function
*/
function burn(uint256 amount_) external onlySOCKET {
_burn(msg.sender, amount_);
}

/**
* @notice Returns the name of the token
* @return The token's name
*/
function name() public view override returns (string memory) {
return _name;
}

/**
* @notice Returns the symbol of the token
* @return The token's symbol
*/
function symbol() public view override returns (string memory) {
return _symbol;
}

/**
* @notice Returns the number of decimals for the token
* @return The token's decimal places
*/
function decimals() public view override returns (uint8) {
return _decimals;
}
}
127 changes: 127 additions & 0 deletions src/superToken/SuperTokenAppGateway.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

import "socket-protocol/contracts/base/AppGatewayBase.sol";
import "solady/auth/Ownable.sol";
import {ISuperToken} from "./ISuperToken.sol";

/**
* @title SuperTokenApp
* @notice A cross-chain application for bridging tokens
* @dev Extends AppGatewayBase and Ownable to provide a chain abstracted token bridging functionality
*/
contract SuperTokenApp is AppGatewayBase, Ownable {
/**
* @notice Counter to track unique transaction IDs
* @dev Incremented with each bridging operation
*/
uint256 public idCounter;

/**
* @notice Emitted when a token bridging operation is initiated
* @param asyncId Unique identifier for the asynchronous cross-chain transaction
*/
event Bridged(bytes32 asyncId);

/**
* @notice Represents a user's token bridging order
* @dev Contains details of the token transfer across different chains
*/
struct UserOrder {
/// @notice Source token contract address
address srcToken;
/// @notice Destination token contract address
address dstToken;
/// @notice User initiating the bridge transaction
address user;
/// @notice Amount of tokens to be bridged from source chain
uint256 srcAmount;
/// @notice Deadline for the bridge transaction
uint256 deadline;
}

/**
* @notice Constructor to initialize the SuperTokenApp
* @param _addressResolver Address of the cross-chain address resolver
* @param deployerContract_ Address of the contract deployer
* @param feesData_ Struct containing fee-related data for bridging
* @dev Sets up the contract, initializes ownership, and configures gateways
*/
constructor(
address _addressResolver,
address deployerContract_,
FeesData memory feesData_
) AppGatewayBase(_addressResolver) Ownable() {
_initializeOwner(msg.sender);
addressResolver.setContractsToGateways(deployerContract_);
_setFeesData(feesData_);
}

/**
* @notice Validates user's token balance for a cross-chain transaction
* @param data Encoded user order and async transaction ID
* @param returnData Balance data returned from the source chain
* @dev Checks if user has sufficient balance to complete the bridge transaction
* @custom:modifier onlyPromises Ensures the function can only be called by the promises system
*/
function checkBalance(
bytes memory data,
bytes memory returnData
) external onlyPromises {
(UserOrder memory order, bytes32 asyncId) = abi.decode(
data,
(UserOrder, bytes32)
);

uint256 balance = abi.decode(returnData, (uint256));
if (balance < order.srcAmount) {
_revertTx(asyncId);
return;
}
}

/**
* @notice Initiates a cross-chain token bridge transaction
* @param _order Encoded user order details
* @return asyncId Unique identifier for the asynchronous cross-chain transaction
* @dev Handles token bridging logic across different chains
*/
function bridge(
bytes memory _order
) external async returns (bytes32 asyncId) {
UserOrder memory order = abi.decode(_order, (UserOrder));
asyncId = _getCurrentAsyncId();
/* TODO:
1. Check user balance on src chain
2. Check if it was a already deployed contract
if original contract,
transferFrom user to Vault
mint to user on dst chain
if supertoken,
burn from user
transferFrom Vault to user
*/

emit Bridged(asyncId);
}

/**
* @notice Allows the owner to withdraw fee tokens from a specific chain
* @param chainSlug_ Unique identifier of the blockchain
* @param token_ Address of the token to withdraw
* @param amount_ Amount of tokens to withdraw
* @param receiver_ Address receiving the withdrawn tokens
* @dev Restricted to contract owner
* @custom:modifier onlyOwner Ensures only the contract owner can withdraw fees
*/
function withdrawFeeTokens(
uint32 chainSlug_,
address token_,
uint256 amount_,
address receiver_
) external onlyOwner {
_withdrawFeeTokens(chainSlug_, token_, amount_, receiver_);
}

// TODO: Add rescue tokens from Vault in chainSlug
}
68 changes: 68 additions & 0 deletions src/superToken/SuperTokenDeployer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

import "socket-protocol/contracts/base/AppDeployerBase.sol";
import "solady/auth/Ownable.sol";
import "./SuperToken.sol";

/**
* @title SuperTokenDeployer
* @notice A contract for deploying SuperToken across multiple chains
* @dev Extends AppDeployerBase and Ownable to provide cross-chain token deployment functionality
*/
contract SuperTokenDeployer is AppDeployerBase, Ownable {
/**
* @notice Unique identifier for the SuperToken contract
* @dev Used to track and manage the SuperToken contract across different chains
*/
bytes32 public superToken = _createContractId("superToken");

/**
* @notice Constructor to initialize the SuperTokenDeployer
* @param addressResolver_ Address of the address resolver contract
* @param owner_ Address of the contract owner
* @param name_ Name of the token to be deployed
* @param symbol_ Symbol of the token to be deployed
* @param decimals_ Number of decimals for the token
* @param feesData_ Struct containing fee-related data for deployment
* @dev Sets up the contract with token creation code and initializes ownership
*/
constructor(
address addressResolver_,
address owner_,
string memory name_,
string memory symbol_,
uint8 decimals_,
FeesData memory feesData_
) AppDeployerBase(addressResolver_) Ownable() {
_initializeOwner(owner_);

creationCodeWithArgs[superToken] = abi.encodePacked(
type(SuperToken).creationCode,
abi.encode(name_, symbol_, decimals_)
);

_setFeesData(feesData_);
}

/**
* @notice Deploys the SuperToken contract on a specified chain
* @param chainSlug The unique identifier of the target blockchain
* @dev Triggers the deployment of the SuperToken contract
* @custom:modifier Accessible to contract owner or authorized deployers
*/
function deployContracts(uint32 chainSlug) external async {
// TODO: Add logic to process if token is already deployed on a chain
_deploy(superToken, chainSlug);
}

/**
* @notice Initialization function for post-deployment setup
* @param chainSlug The unique identifier of the blockchain
* @dev Overrides the initialize function from AppDeployerBase
* @notice This function is automatically called after all contracts are deployed
* @dev Currently implemented as a no-op, can be extended for additional initialization logic
* @custom:note Automatically triggered via AppDeployerBase.allPayloadsExecuted or AppGateway.queueAndDeploy
*/
function initialize(uint32 chainSlug) public override async {}
}
Loading

0 comments on commit 7fe21bb

Please sign in to comment.