Exploring the CustomSwapToken Smart Contract: Understanding Decentralized Token Swapping
In this blog post, we'll delve into a Solidity smart contract designed for token swapping – the Swap
contract. This contract facilitates the exchange of Ethereum and various custom ERC-20 tokens in a decentralized manner.
Let's examine the smart contract I created for the UNISWAP Token Marketplace project, which is available on my GitHub.
Link to Smart Contract -> https://github.com/AdityaB1152/token-swap/blob/master/contracts/Swap.sol
Decentralized Token Exchange -> https://github.com/AdityaB1152/token-swap
Understanding the Components
Let's break down the main components of the Smart Contract:
CustomSwapToken Contract
The CustomSwapToken
contract is an ERC-20 token contract that extends the OpenZeppelin ERC-20 implementation. It is used to create custom tokens with specified names and symbols. In the constructor, an initial supply of 10 million tokens is minted and assigned to the contract deployer.
contract CustomSwapToken is ERC20 {
// Constructor to mint tokens to the contract deployer
constructor(string memory name, string memory symbol) ERC20(name, symbol) {
_mint(msg.sender, 10000000 * 10 ** 18);
}
}
Swap Contract
The Swap
contract is the heart of the token-swapping functionality. The main functionality of the Smart contract lies in the Swap contract. It features three types of token swaps: from Ether to a custom token, from a custom token to Ether, and between two custom tokens.
- Token Initialization:
solidityCopy codestring[] public tokens = ["Tether USD", "BNB", "USD Coin", "stETH", "TRON", "Matic Token", "SHIBA INU", "Uniswap"];
mapping(string => ERC20) public tokenInstanceMap;
tokens
: An array of string literals representing the names of different tokens.
tokenInstanceMap
: A mapping that associates each token name with its corresponding ERC20 token instance.
- Ether Value:
solidityCopy codeuint256 ethValue = 1000000000000;
ethValue
: A constant representing the value of 1 Ether in wei. It is set to 1000000000000 wei.
- Contract Initialization:
solidityCopy codeconstructor(){
for(uint i = 0; i < tokens.length; i++){
CustomSwapToken token = new CustomSwapToken(tokens[i], tokens[i]);
tokenInstanceMap[tokens[i]] = token;
}
}
constructor
: The constructor function initializes the contract by creating instances of CustomSwapToken
for each token in the tokens
array. It then populates the tokenInstanceMap
with the token names and their corresponding instances.
- Token Information Functions:
solidityCopy codefunction getBalance(string memory tokenName, address _address) public view returns (uint256) {
return tokenInstanceMap[tokenName].balanceOf(_address);
}
function getTotalSupply(string memory tokenName) public view returns(uint256) {
return tokenInstanceMap[tokenName].totalSupply();
}
function getName(string memory tokenName) public view returns (string memory) {
return tokenInstanceMap[tokenName].name();
}
getBalance
: Returns the balance of a specific token for a given address.
getTotalSupply
: Returns the total supply of a specific token.
getName
: Returns the name of a specific token.
- Ether and Token Information Functions:
solidityCopy codefunction getEthBalance() public view returns (uint256) {
return address(this).balance;
}
function getTokenAddress(string memory tokenName) public view returns (uint256) {
return address(tokenInstanceMap[tokenName]);
}
getEthBalance
: Returns the balance of Ether held by the contract.
getTokenAddress
: Returns the address of the ERC20 token contract for a given token name.
Swapping Ether to Token:
Users can exchange Ether for a custom token using the
swapEthToToken
function. The function calculates the output token amount based on the input Ether value and transfers the tokens to the user.function swapEthToToken(string memory tokenName) public payable returns (uint256) { // Calculate output token amount based on input Ether value uint256 inputValue = msg.value; uint256 outputValue = (inputValue / ethValue) * 10 ** 18; // Transfer tokens to the user require(tokenInstanceMap[tokenName].transfer(msg.sender, outputValue)); // Log transaction history string memory etherToken = "Ether"; _transactionHistory(tokenName, etherToken, inputValue, outputValue); return outputValue; }
Swapping Token to Ether:
Users can convert a custom token to Ether with the
swapTokenToEth
function. The function ensures that the contract has sufficient Ether balance and transfers the calculated Ether amount to the user.
function swapTokenToEth(string memory tokenName, uint256 _amount) public returns (uint256) {
// Calculate exact token amount and Ether to be transferred
uint256 exactAmount = _amount / 10 ** 18;
uint256 ethToBeTransferred = exactAmount * ethValue;
// Check contract's Ether balance
require(address(this).balance >= ethToBeTransferred, "Dex is running low on balance");
// Transfer Ether to the user
payable(msg.sender).transfer(ethToBeTransferred);
// Transfer tokens from the user to the contract
require(tokenInstanceMap[tokenName].transferFrom(msg.sender, address(this), _amount));
// Log transaction history
string memory etherToken = 'Ether';
_transactionHistory(tokenName, etherToken, exactAmount, ethToBeTransferred);
return ethToBeTransferred;
}
Swapping Token to Token:
Users can also exchange one custom token for another with the
swapTokenToToken
function.
function swapTokenToToken(string memory srcTokenName, string memory destTokenName, uint256 _amount) public {
// Transfer source token from user to the contract
require(tokenInstanceMap[srcTokenName].transferFrom(msg.sender, address(this), _amount));
// Transfer destination token from the contract to the user
require(tokenInstanceMap[destTokenName].transfer(msg.sender, _amount));
// Log transaction history
_transactionHistory(srcTokenName, destTokenName, _amount, _amount);
}
- Transaction History:
The History
struct and associated functions maintain a record of each transaction's details, including the involved tokens, input/output values, and the user's address.
struct History { uint256 historyId; string tokenA; string tokenB; uint256 inputValue; uint256 outputValue; address userAddress; } function _transactionHistory(string memory tokenName, string memory etherToken, uint256 inputValue, uint256 outputValue) internal { // Increment history index and record transaction details _historyIndex++; uint256 _historyId = _historyIndex; History storage history = historys[_historyId]; history.historyId = _historyId; history.userAddress = msg.sender; history.tokenA = tokenName; history.tokenB = etherToken; history.inputValue = inputValue; history.outputValue = outputValue; }
Solidity smart contract,
Swap
, demonstrates the basic functionality of a decentralized token swap platform. Users can exchange Ethereum for custom ERC-20 tokens, swap tokens for Ethereum, and even trade one ERC-20 token for another. The transaction history feature enhances transparency by logging all swaps on the blockchain.
Conclusion:
To sum up, the Solidity smart contract described in this blog post provides a simple and effective way to swap Ethereum and custom ERC-20 tokens in a decentralized manner. The contract comprises two main components: the CustomSwapToken contract, which creates custom tokens, and the Swap contract, which enables users to swap tokens. The contract also includes several helpful functions such as token balance and supply information, token swapping functions, and transaction history logging functions. Overall, this contract serves as a solid foundation for building a decentralized token-swapping platform.