A Simple decentralized exchange built on the Celo blockchain with Solidity and deployed with Golang
Functionlities:
Create an order book
Get order
Withdraw
Buy
Deposit
The Smart contract
// SPDX-License-Identifier: MITpragma solidity^0.8.0;
contractExchange {
// Define variablesaddress payablepublic owner;
uintpublic orderCount =0;
mapping(uint=> Order) public orders;
mapping(address=>uint) public balances;
// Define struct for orderstruct Order {
uint id;
address payable seller;
address payable buyer;
uint price;
bool completed;
}
// Define events for when an order is created and when an order is completedevent OrderCreated(uintid, address payableseller, address payablebuyer, uintprice, boolcompleted);
event OrderCompleted(uintid, address payableseller, address payablebuyer, uintprice, boolcompleted);
// Constructor functionconstructor() {
owner =payable(msg.sender);
}
// Sell function - create a new orderfunction sell(uint_price) public {
// Increment order count
orderCount++;
// Create new order
orders[orderCount] =Order(orderCount, payable(msg.sender), payable(address(0)), _price, false);
// Emit eventemitOrderCreated(orderCount, payable(msg.sender), payable(address(0)), _price, false);
}
// Buy function - complete an existing orderfunction buy(uint_id) publicpayable {
// Get order from mapping
Order memory _order = orders[_id];
// Make sure order exists and is not completedrequire(_order.id >0&& _order.completed ==false, "Order does not exist or is already completed.");
// Make sure buyer has enough ether to purchase orderrequire(msg.value>= _order.price, "Not enough ether sent to purchase order.");
// Transfer ether to seller
_order.seller.transfer(msg.value);
// Update order to completed
_order.buyer =payable(msg.sender);
_order.completed =true;
orders[_id] = _order;
// Emit eventemitOrderCompleted(_id, _order.seller, payable(msg.sender), _order.price, true);
}
// Deposit function - add ether to user's balancefunction deposit() publicpayable {
// Add ether to user's balance
balances[msg.sender] +=msg.value;
}
// Withdraw function - withdraw ether from user's balancefunction withdraw(uint_amount) public {
// Make sure user has enough ether in their balancerequire(balances[msg.sender] >= _amount, "Not enough ether in balance to withdraw.");
// Subtract ether from user's balance and transfer to user
balances[msg.sender] -= _amount;
payable(msg.sender).transfer(_amount);
}
// Order function - get order detailsfunction getOrder(uint_id) publicviewreturns (uint, address, address, uint, bool) {
// Get order from mapping and return details
Order memory _order = orders[_id];
return (_order.id, _order.seller, _order.buyer, _order.price, _order.completed);
}
}
The Deployment script
package main
import (
"context""crypto/ecdsa""fmt""io/ioutil""log""math/big""github.com/ethereum/go-ethereum/accounts/abi/bind""github.com/ethereum/go-ethereum/common""github.com/ethereum/go-ethereum/core/types""github.com/ethereum/go-ethereum/crypto""github.com/ethereum/go-ethereum/ethclient"
)
// Replace this with your own private key and Celo node URLconstprivateKey="your-private-key"constnodeURL="https://alfajores-forno.celo-testnet.org"funcmain() {
// Connect to the Celo networkclient, err:=ethclient.Dial(nodeURL)
iferr!=nil {
log.Fatalf("Failed to connect to the Celo network: %v", err)
}
deferclient.Close()
// Load the private keykey, err:=crypto.HexToECDSA(privateKey)
iferr!=nil {
log.Fatalf("Failed to load the private key: %v", err)
}
// Load the contract ABIabiBytes, err:=ioutil.ReadFile("Exchange.abi")
iferr!=nil {
log.Fatalf("Failed to read the contract ABI: %v", err)
}
fmt.Println(abiBytes)
// Load the contract bytecodebytecode, err:=ioutil.ReadFile("Exchange.bin")
iferr!=nil {
log.Fatalf("Failed to read the contract bytecode: %v", err)
}
// Get the public address associated with the private keypublicKey:=key.Public().(*ecdsa.PublicKey)
address:=crypto.PubkeyToAddress(*publicKey)
// Get the nonce associated with the addressnonce, err:=client.PendingNonceAt(context.Background(), address)
iferr!=nil {
log.Fatalf("Failed to get the nonce: %v", err)
}
// Get the gas pricegasPrice, err:=client.SuggestGasPrice(context.Background())
iferr!=nil {
log.Fatalf("Failed to get the gas price: %v", err)
}
// Create a new transactiontx:=types.NewContractCreation(nonce, big.NewInt(0), 3000000, gasPrice, common.FromHex(string(bytecode)))
// Sign the transactionsignedTx, err:=types.SignTx(tx, types.NewEIP155Signer(big.NewInt(44787)), key)
iferr!=nil {
log.Fatalf("Failed to sign the transaction: %v", err)
}
// Broadcast the transactionerr=client.SendTransaction(context.Background(), signedTx)
iferr!=nil {
log.Fatalf("Failed to broadcast the transaction: %v", err)
}
// Wait for the transaction receiptreceipt, err:=bind.WaitMined(context.Background(), client, signedTx)
iferr!=nil {
log.Fatalf("Failed to get the transaction receipt: %v", err)
}
// Print the contract addressfmt.Printf("Smart contract deployed at address: %s\n", receipt.ContractAddress.Hex())
}
building-a-decentralized-exchange-on-celo-with-golang's People