Skip to content

Instantly share code, notes, and snippets.

@MarkNwilliam
Created November 30, 2022 07:25
Show Gist options
  • Save MarkNwilliam/544dda41ae8534969d58e6fbf0dab013 to your computer and use it in GitHub Desktop.
Save MarkNwilliam/544dda41ae8534969d58e6fbf0dab013 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.7+commit.e28d00a7.js&optimize=false&runs=200&gist=
{
"language": "Solidity",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"": ["ast"],
"*": ["abi", "metadata", "devdoc", "userdoc", "storageLayout", "evm.legacyAssembly", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "evm.gasEstimates", "evm.assembly"]
}
},
"evmVersion": "byzantium"
}
}
pragma solidity ^0.8.0;
contract YeeExchange {
// The asset structure
struct Asset {
address creator;
bytes6 id; // 6 bytes string
string link
int price;
int quantity;
}
// The transaction structure
struct Transaction {
bytes6 source; // 6 bytes string
bytes6 target; // 6 bytes string
int quantity;
int price;
uint256 timestamp;
int8 state; // 0:PENDING / 1:VALIDATED / 2:REJECTED
}
// Counts
int transaction_count;
int asset_count;
// Lists
mapping (int => Transaction) transactions;
mapping (int => Asset) assets;
// private functions
// compare 6 bytes string
function stringsEqual(bytes6 a, bytes6 b) internal pure returns (bool) {
// @todo unroll this loop
for (uint i = 0; i < 6; i ++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
// Events
event AssetJoined(address indexed asset_address, int index, bytes6 id, string link, int quantity, int price, uint256 timestamp);
event TransactionExecuted(address indexed source_address, int source_asset_index, int target_asset_index, bytes6 source,
bytes6 target, int quantity, int price, uint256 timestamp, int8 state);
event AssetUpdated(address indexed asset_address, int index, bytes6 id, string link, int quantity, int price, uint256 timestamp);
// Gets an asset index in the mapping by id
function getAssetIndex(bytes6 _id) public view returns (int index) {
for (int i = 1; i <= asset_count; i++) {
if(stringsEqual(assets[i].id, _id) == true)
return i;
}
return -1;
}
// Gets assets count
function getAssetsCount() public view returns (int uid) {
return asset_count;
}
// Gets transactions count
function getTransactionsCount() public view returns (int uid) {
return transaction_count;
}
// Registers an asset into the assets list
function register(bytes6 _id, string _link, int _quantity, int _price) public payable returns (bool success) {
int asset_index = getAssetIndex(_id);
if(asset_index == -1){
asset_count = asset_count + 1;
Asset memory _asset = Asset(msg.sender, _id,_link, _price, _quantity);
assets[asset_count] = _asset;
emit AssetJoined(msg.sender,asset_count, _id,_link, _quantity, _price, now);
} else {
assets[asset_index].quantity = _quantity;
assets[asset_index].price = _price;
emit AssetUpdated(msg.sender, asset_index, _id,_link, _quantity, _price, now);
}
return true;
}
// Gets an asset by index in the list
function getAssetByIndex(int i) public view returns (bytes6 id, string link int price, int quantity) {
if(i >= 1 && i <= asset_count)
return (assets[i].id,assets[i].link, assets[i].price, assets[i].quantity);
else
return ("NONEAA",-1,-1);
}
// Gets an asset by id (string)
function getAsset(bytes6 _id) public view returns (bytes6 id, string link, int price, int quantity) {
for (int i = 1; i <= asset_count; i++) {
if(stringsEqual(assets[i].id, _id) == true)
return (assets[i].id, assets[i].price, assets[i].quantity);
}
return ("NONEAA",-1,-1);
}
// executes a transaction where source buys from target a certain quantity
function transact(bytes6 source, bytes6 target, int quantity) public payable returns (bool success) {
int si = getAssetIndex(source);
int ti = getAssetIndex(target);
if(si == -1 || ti == -1) {
return false;
}
else {
transaction_count = transaction_count + 1;
Transaction memory _t = Transaction(assets[si].id, assets[ti].id, quantity, assets[ti].price, now, 0);
transactions[transaction_count] = _t;
if((assets[ti].quantity - quantity) >= 0) { // validate transaction
assets[ti].quantity -= quantity;
transactions[transaction_count].state = 1;
emit TransactionExecuted(msg.sender,si,ti, transactions[transaction_count].source, transactions[transaction_count].target, transactions[transaction_count].quantity, transactions[transaction_count].price, transactions[transaction_count].timestamp, transactions[transaction_count].state);
emit AssetUpdated(assets[ti].creator, ti, assets[ti].id, assets[ti].quantity, assets[ti].price, now);
}
else if(assets[ti].quantity > 0) { // validate partial transaction
transactions[transaction_count].state = 1;
transactions[transaction_count].quantity = assets[ti].quantity;
emit TransactionExecuted(msg.sender, si, ti, transactions[transaction_count].source, transactions[transaction_count].target, transactions[transaction_count].quantity, transactions[transaction_count].price, transactions[transaction_count].timestamp, transactions[transaction_count].state);
// create the rejected transaction
transaction_count = transaction_count + 1;
Transaction memory _t1 = Transaction(assets[si].id, assets[ti].id, quantity - assets[ti].quantity, assets[ti].price, now, 0);
transactions[transaction_count] = _t1;
assets[ti].quantity = 0;
transactions[transaction_count].state = 2;
emit TransactionExecuted(msg.sender, si, ti, transactions[transaction_count].source, transactions[transaction_count].target, transactions[transaction_count].quantity, transactions[transaction_count].price, transactions[transaction_count].timestamp, transactions[transaction_count].state);
emit AssetUpdated(assets[ti].creator, ti, assets[ti].id, assets[ti].quantity, assets[ti].price, now);
}
else {
transactions[transaction_count].state = 2;
emit TransactionExecuted(msg.sender, si, ti, transactions[transaction_count].source, transactions[transaction_count].target, transactions[transaction_count].quantity, transactions[transaction_count].price, transactions[transaction_count].timestamp, transactions[transaction_count].state);
}
}
return true;
}
// Get transaction by index
function getTransactionByIndex(int i) public view
returns (bytes6 source, bytes6 target, int quantity, int price, uint256 timestamp, int8 state ) {
if(i >= 1 && i <= transaction_count)
return (transactions[i].source, transactions[i].target,
transactions[i].quantity, transactions[i].price, transactions[i].timestamp, transactions[i].state);
else
return ("NONEAA", "NONEAA",-1,-1, 0, 2);
}
// Get the next transaction index involving an asset
function getNextTransactionIdInvolvingAsset(bytes6 id, int start) public view returns (int) {
if(start < 1 || start > transaction_count)
return -1;
for (int i = start; i <= transaction_count; i++) {
if(stringsEqual(transactions[i].source, id) == true || stringsEqual(transactions[i].target, id))
return i;
}
return -1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment