EOS - Example Exchange Contract and Benefits of C++

in eos •  7 years ago 

This week I have been focused on the API that smart contract developers will use to write contracts. To help facilitate the design of this API I have given myself an example contract to write. This time the example is a little bit more complex than just a currency contract, but a full up exchange between the native EOS currency and an example CURRENCY contract.

Benefits of C++ API

Developers building on EOS will write their smart contracts in C++ that gets compiled to Web Assembly and then published to the blockchain. This means that we can take advantage of C++'s type and template system to ensure our contracts are safe.

One of the most basic kinds of safety is known as dimensional analysis, aka keeping your units straight. When developing an exchange you are dealing with several numbers with different units: EOS, CURRENCY, and EOS / CURRENCY.

A simple implementation would do something like this:

struct account {
  uint64_t  eos_balance;
  uint64_t  currency_balance;
};

The problem with this simple approach is that the following code could be accidentally written:

void buy( Bid order ) {
   ...
   buyer_account.currency _balance  -=  order.quantity;
   ...
}

At first glance the error isn't obvious, but upon closer inspection bids consume the eos_balance rather than the currency_balance. In this case the market is setup to price CURRENCY in EOS. Another kind of error that could occur is the following:

   auto receive_tokens = order.quantity * order.price;

This particular line of code may be valid if order is a Bid, but the price would need to be inverted if it were an Ask. As you can see without proper dimensional analysis there is no way to be certain you are adding apples to apples and not apples to oranges.

Fortunately, C++ allows us to use templates and operator overloading to define a runtime cost-free validation of our units.

template<typename NumberType, uint64_t CurrencyType = N(eos) >
   struct token {
       token(){}
       explicit token( NumberType v ):quantity(v){};
       NumberType quantity = 0;

       token& operator-=( const token& a ) {
          assert( quantity >= a.quantity, 
                        "integer underflow subtracting token balance" );
          quantity -= a.quantity;
          return *this;
       }

       token& operator+=( const token& a ) {
          assert( quantity + a.quantity >= a.quantity, 
                       "integer overflow adding token balance" );
          quantity += a.quantity;
          return *this;
       }

       inline friend token operator+( const token& a, const token& b ) {
          token result = a;
          result += b;
          return result;
       }

       inline friend token operator-( const token& a, const token& b ) {
          token result = a;
          result -= b;
          return result;
       }

       explicit operator bool()const { return quantity != 0; }
   };

With this definition there is now a clear type distinction in the account:

struct Account {
   eos::Tokens               eos_balance;
   currency::Tokens    currency_balance;
};

struct Bid {
    eos::Tokens quantity;
};

With this in place the following will generate a compile error because there is no -= operator defined for eos::Tokens and currency::Tokens.

void buy( Bid order ) {
   ...
   buyer_account.currency _balance  -=  order.quantity;
   ...
}

Using this technique I was able to use the compiler to identify and fix many unit mismatches in my implementation of an example exchange contract. The really nice thing about all of this is that the final web assembly generated by the C++ compiler is identical to what would have been generated if I had simply used uint64_t for all of my balances.

Another thing you may notice is that the token class also automatically checks for over and underflow exceptions.

Simplified Currency Contract

In the process of writing the exchange contract I first had update the currency contract. In doing so I refactored the currency contract into a header currency.hpp and a source currency.cpp so that the exchange contract could access types defined by the currency contract.

currency.hpp

#include <eoslib/eos.hpp>
#include <eoslib/token.hpp>
#include <eoslib/db.hpp>

/**
 * Make it easy to change the account name the currency is deployed to.
 */
#ifndef TOKEN_NAME
#define TOKEN_NAME currency
#endif

namespace TOKEN_NAME {

   typedef eos::token<uint64_t,N(currency)> Tokens;

   /**
    *  Transfer requires that the sender and receiver be the first two
    *  accounts notified and that the sender has provided authorization.
    */
   struct Transfer {
      AccountName       from;
      AccountName       to;
      Tokens            quantity;
   };

   struct Account {
      Tokens           balance;

      bool  isEmpty()const  { return balance.quantity == 0; }
   };

   /**
    *  Accounts information for owner is stored:
    *
    *  owner/TOKEN_NAME/account/account -> Account
    *
    *  This API is made available for 3rd parties wanting read access to
    *  the users balance. If the account doesn't exist a default constructed
    *  account will be returned.
    */
   inline Account getAccount( AccountName owner ) {
      Account account;
      ///      scope, code, table,      key,       value
      Db::get( owner, N(currency), N(account), N(account), account );
      return account;
   }

} /// namespace TOKEN_NAME

currency.cpp

#include <currency/currency.hpp> /// defines transfer struct (abi)

namespace TOKEN_NAME {

   ///  When storing accounts, check for empty balance and remove account
   void storeAccount( AccountName account, const Account& a ) {
      if( a.isEmpty() ) {
         printi(account);
         ///        scope    table       key
         Db::remove( account, N(account), N(account) );
      } else {
         ///        scope    table       key         value
         Db::store( account, N(account), N(account), a );
      }
   }

   void apply_currency_transfer( const TOKEN_NAME::Transfer& transfer ) {
      requireNotice( transfer.to, transfer.from );
      requireAuth( transfer.from );

      auto from = getAccount( transfer.from );
      auto to   = getAccount( transfer.to );

      from.balance -= transfer.quantity; /// token subtraction has underflow assertion
      to.balance   += transfer.quantity; /// token addition has overflow assertion

      storeAccount( transfer.from, from );
      storeAccount( transfer.to, to );
   }

}  // namespace TOKEN_NAME

Introducing the Exchange Contract

The exchange contract processes the currency::Transfer and the eos::Transfer messages when ever the exchange is the sender or receiver. It also implements three of its own messages: buy, sell, and cancel. The exchange contract defines its public interface in exchange.hpp which is where the message types and database tables are defined.

exchange.hpp

#include <currency/currency.hpp>

namespace exchange {

   struct OrderID {
      AccountName name    = 0;
      uint64_t    number  = 0;
   };

   typedef eos::price<eos::Tokens,currency::Tokens>     Price;

   struct Bid {
      OrderID            buyer;
      Price              price;
      eos::Tokens        quantity;
      Time               expiration;
   };

   struct Ask {
      OrderID            seller;
      Price              price;
      currency::Tokens   quantity;
      Time               expiration;
   };

   struct Account {
      Account( AccountName o = AccountName() ):owner(o){}

      AccountName        owner;
      eos::Tokens        eos_balance;
      currency::Tokens   currency_balance;
      uint32_t           open_orders = 0;

      bool isEmpty()const { return ! ( bool(eos_balance) | bool(currency_balance) | open_orders); }
   };

   Account getAccount( AccountName owner ) {
      Account account(owner);
      Db::get( N(exchange), N(exchange), N(account), owner, account );
      return account;
   }

   TABLE2(Bids,exchange,exchange,bids,Bid,BidsById,OrderID,BidsByPrice,Price);
   TABLE2(Asks,exchange,exchange,bids,Ask,AsksById,OrderID,AsksByPrice,Price);


   struct BuyOrder : public Bid  { uint8_t fill_or_kill = false; };
   struct SellOrder : public Ask { uint8_t fill_or_kill = false; };
}

The exchange contract source code gets a bit long for this post, but you can view it on github. For now I will show the core message handler for a SellOrder to get an idea how it would be implemented:

void apply_exchange_sell( SellOrder order ) {
   Ask& ask = order;
   requireAuth( ask.seller.name );

   assert( ask.quantity > currency::Tokens(0), "invalid quantity" );
   assert( ask.expiration > now(), "order expired" );

   static Ask existing_ask;
   assert( AsksById::get( ask.seller, existing_ask ), "order with this id already exists" );

   auto seller_account = getAccount( ask.seller.name );
   seller_account.currency_balance -= ask.quantity;

   static Bid highest_bid;
   if( !BidsByPrice::back( highest_bid ) ) {
      assert( !order.fill_or_kill, "order not completely filled" );
      Asks::store( ask );
      save( seller_account );
      return;
   }

   auto buyer_account = getAccount( highest_bid.buyer.name );

   while( highest_bid.price >= ask.price ) {
      match( highest_bid, buyer_account, ask, seller_account );

      if( highest_bid.quantity == eos::Tokens(0) ) {
         save( seller_account );
         save( buyer_account );
         Bids::remove( highest_bid );
         if( !BidsByPrice::back( highest_bid ) ) {
            break;
         }
         buyer_account = getAccount( highest_bid.buyer.name );
      } else {
         break; // buyer's bid should be filled
      }
   }

   save( seller_account );
   if( ask.quantity ) {
      assert( !order.fill_or_kill, "order not completely filled" );
      Asks::store( ask );
   }
}

As you can see the code here is relatively concise, readable, safe, and most importantly performant.

Isn't C++ an Unsafe Language?

Those who are into language wars may be familiar with the challenges that C and C++ programers have managing memory. Fortunately, most of those issues go away when building smart contracts because your program "restarts" with a clean slate at the start of every message. Furthermore, there is rarely a need to implement dynamic memory allocation. This entire exchange contract doesn't call new or delete nor malloc or free. The WebAssembly framework will automatically reject any transaction that would address memory wrong.

This means that most of the problems with C++ go away when using it for short-lived message handlers and we are left with its many benefits.

Conclusion

EOS.IO software is progressing nicely and I couldn't be happier with how much fun it is to write smart contracts using this API.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Nice post! Steemit really needs syntax highlighting though :) Any thoughts on using something like AssemblyScript for writing contracts?

Great Suggestion

Can you compare with TurboScript? Looks like AssemblyScript is much more mature than TurboScript. I wonder though why we have two similar projects.

Does it decompile from wasm too?

AFAIK AssemblyScript was born out of dissatisfaction with some of the design choices in TurboScript. Not sure what the exact differences are anymore, looks like TurboScript is moving to binaryen now as well. I would personally go with AssemblyScript in a heartbeat just because I know that the dcode guy makes some great modules.

It doesn't decompile from wasm, and I don't think it ever will. You could maybe use SourceMaps to go back when support for that is added.

money-animated-gif-13.gif

Hallo @dantheman ,

I have some questions about EOS:

  • Is it an operative system or only smart contracts?

  • Which languages do I need to learn in dept to be able to program a serious ride sharing service to take over the world of ride-sharing (I have programmed since I was a child, but as an adult mostly c# with asp.net framework, but also many other languages, mostly as hacks, never understood all the code)

I want to prepare myself to posibily make a ride-sharing app that out-compete uber and conventional taxi services, other then working as an economist (with programming jobs included in the job), I have been working as a taxitemp and a uber driver and know how to make a decentral solution that will solve all (or the crusial) problems of centralized ride/taxi services.

Mostly it is about sharing the 20-50% that uber or taxi company takes between the rider and the driver and getting all ratings on the blockchain. Uber manipulate ratings to their own benefit, and extort drivers... plus their business model is based on massive loans from the corrupt fiat central banks... I could go on with this, but back to the programming part.

Is it c++ that I need to master completely and/or is it realisticly for a semi-pro freelance soft programmer to learn before EOS is ready?

If it is a smart contract platform, then is the website or phone app still hosted on centralized serviecs?? You know it is all about getting that decentralized too, so that no regulation will be able to stop the app/site ??.. I have heard that steemit would run on EOS, but is that also the site itself? Maybe some of these questions shows how little I still know about EOS and other things and hope my questions are not too stupid :)

Thanks for the great work, I really enjoy Steem and also hold a little Bitshares and EOS.

Lasse

@dantheman Please answer this questions.

This is something that concerns me too... Could someone please address this?
@dantheman?

I spent some time learning Wren. Now I'll spend some time learning C++. I've done things in many different languages, but never C or C++. I'm excited for the journey, but also a bit overwhelmed thinking how far I have to go to get to where I'd someday like to be. Thank you for these examples.

Can you give us an idea when a testnet will be up so noobie muggles like myself can start playing around with this stuff?

C was my favorite for a long time, then I moved onto C++ but it still allowed me to do C so I didn't really benefit from C++ as much as I should have since it didn't FORCE me to learn the new things. More recently I've mostly been using C# which is similar in many ways but alien in others. :)

Hey you guys both inspired me. I'm reading your comments thinking, "Damn, I haven't tried programming anything in C or C++ since the early 2000s." I want to be able to make apps and develop ideas in modern ways. I've just been telling myself it's too hard or I'm never going to master it or ever even get close. That's limiting talk and I'm thinking now that I can make programs and learn to code if that's what I really want.

Very good "documentation", thanks @dan

@dan ... hard work there!! I know something about... Thank You!!

Oooo really very interesting post you I am very amazed to see him congratulations on the achievement that you can not all this apart from the results of your hard work in esteem I also want as you want kah you follow me and upvote me and share my post so that your friends can Even though not as good as your post if you want me very grateful to you Congratulations, hopefully sukse always make you up to the front

I don't code but somehow I find these post.... calming and exciting at the same time :-)

  ·  7 years ago (edited)

As I probably wouldn't write my own smart contracts but just use EOS (I wish it lots of success as the things I have read about it sound great) I don't mind if it is C++. Coming from a web development background and seeing the rapid adoption of JavaScript / NodeJS (Go too) for all kinds of things I think it's a bit of a pity that all those developers able to code would have a steep (ok maybe not steep but still) learning curve writing a contract using C++.

@dan Would there be the possibility to define smart contracts in ES6 and then (somehow) convert / compile them to C++?

JavaScript doesn't have declarative syntax like in C++. there is no all let's make this a variable an integer or this variable something else, whereas C++ does so. C++ also has classes and operator overloading whereas Javascript does not.

It seems to me C++ should be the soirce and JS sometimes the target. Although sometimes reading erors related to templates can be like reading Greek.

Good post thanks for sharing

This comment has received a 0.15 % upvote from @booster thanks to: @hamzaoui.

I don't know C++ but your explanation makes a lot of sense. Glad to hear about the progress on EOS.

Hi Dan. I am interested in the EOS project, and I wanted to ask you if you would like me to translate some of your post for the Spanish-speaking community, since I do not see a post on this topic and I think that in my community most people do not know EOS.

I am not a professional translator, but I would try to do my best.
I hope you have a good Friday!

Smart contracts is definitely the way forward into the future. EOS has great potential and can possibly one of the greatest in it's space. I'll be keeping an eye out.
@incomepal

I don’t know how to code and most of this is like reading a foreign language but I’m happy with your conclusion that EOS is progressing nicely :). Thanks for the post.

cool :) i can see this as an asp or php thanks!

I wish eos a great long life ahead
Keep it up

Thanks for the review!

Cool!!

Thanks for taking the time to explain everything well detailed and clear. @dan

meep

EOS's huge ICO caused a big market hype jump for them and the Buzz is over, not sure if it will rise again in my opinion. Tezos ICO same thing, now all ICO will think about 200m plus and it won't happen everytime.

Great post. Smart contracts on the up!

Last paragraph caught my attention, since no new or delete is called, using c++ is safe but there is nothing preventing from anyone writing contract to do so?How do you enforce?or are you saying if they use web assembly framework will some how detect it? but still it is run time only? may be this is best practice to writing "EOS contracts"

  ·  7 years ago (edited)

Before I start, I've not looked in-depth at how EOS smart contracts will be implemented. Consider this a thinking out loud comment.

Furthermore, there is rarely a need to implement dynamic memory allocation.

What about developers that are intentionally trying to cause harm? You mention that it restarts with a clean slate each time, but what does that mean?

@dan
Given that (as you mention) c++ is inherently unsafe, what protection is there against obfuscated contracts that cause harm to unsuspecting users?

The constitution. Contact has limited working memory and with abort it it runs out.

hey @dan!!
i've posted my first blog .............plzzz check

To The Moon EOS!!

Great read, hopefully great future is ahead of EOS.

Hey dan, I just have massive success but votes are so low, please have a look,thx

If only I knew how to code, reading this article would be much easier!

EOS, the next Ethereum ? :)

Thanks for sharing

Nice post dan👍🏼 Eos is looking good

Do not forget my vote

Recibe el mio. Saludos

How would you regulate the contract between each user? Is there any legal foundation?

thanks great information

Nice
Incredible friend best regards from [email protected]

  ·  7 years ago (edited)

Way more interested in what happens to steem, you could build a lot of apllications around a working social network like that

Can you teach me how you do this please

SUCH POST!

A very useful post .., thank you @dan have given me the science, hopefully your post can be useful for stemian all over the world

It's Great.

Thanks for the info. This helps people understand what EOS brings to the table

Thanks for sharing

Hi, im here 3 weeks on steemit and i just want to say thank you for making this world interesting, better and developing into something new and revolutionary. Maybe you are not even aware of it and maybe it seems not a big deal to you but this a beginning of something amazing.

Thats one of my favourite features of EOS, the integration of built in features and other coding languages.
This will make it alot more accesible for folks to start coding for and integrating into their products.

Well done @dan , keep it up.

  ·  7 years ago (edited)

@yoza.ossan - yes, the roadmap says: "Adding support for additional langauges to be compiled to WASM: C++, Rust, etc." ... i wonder if Python and JavaScript will be included ?

Great post there about EOS.IO software @dan. It's shows that its really getting better and more advanced and seems to hold a great future in the currencies world

I think the change to web assembly was a great decision which will have a big impact on EOS adoption in the enterprise world. We will be virtually able to use soon any programming language.

Thanks for the very hard work. Retweet.

I was just on the beginning of learning c and after it c++ is going to be amazing i think

This stuff is pretty much above my head. I am just following numerous different Cryptos because this is the wave of the future. I like the STEEM platform and the its possibilities. When I get more funds, I will think about investing into EOS.
Thanks for sharing

Hmmm you are making my day

Congratulations @dan!
Your post was mentioned in my hit parade in the following category:

  • Pending payout - Ranked 1 with $ 928,14

4 weeks on steemit and i'm amazed about the things you've created and what your vision for the future is.What a man really special,wish you the best of luck for your future projects.

Thank you dan!!

If it weren't for templates and operator overloading, C++ would be so sad lol.

Is it gonna have an app?...an interface to communicate like Steemit?...The name seems enticing each time i see it even though am just getting familiar with cryptos....

EOS is a platform to run Apps on, like Facebook runs Servers that run Facebooks backend (receiving and sending data)

What database do you think Facebook uses?

Facebook uses a series of database technologies :) It has one of the biggest MySQL installations, and also Hive, Cassandra, etc...

The app is very useful and always good information and share. I am very happy with your post I am from indonesia.best regard community steemit Indonesia

Awesome article Dan. Thanks for keeping us in the loop on the current updates and works of EOS. In light of recent price action this is most reassuring as us pro-EOS supporters are often told that it is an 'unproven' tech. Please keep us posted as you make further progress.

I don't even know C++. Just higher level languages so far (python, php, javascript). But I'm really glad this is out there. Thank you.

nice post

i dont know what can i do here , but i am trying for my work.

you expect people to code contracts in C++? I don't think there are enough C++ dev who know how to write secure programs.

excellent

This is a great post, I as a newcomer in steemit this post should I learn more from my teacher @dan. And I will continue to follow you @and.
I'm @rizal will always be a spirit in the steemit community

What is witness vote, how does one become a part of it and what is the benefit please ,any one that knows please kindly answer me please, thank you so very much in advance.
목격자 표결은 무엇이며, 어떻게 그것의 일부가되며 혜택은 무엇입니까, 제발 친절하게 대답 해주십시오. 제발, 제발 대단히 감사드립니다.
什么是见证投票,如何成为它的一部分,什么是好处,请知道任何一个请客气请回答我,非常感谢你提前。

Nice post

  ·  7 years ago (edited)

It would great to have l-values returned in favor of output arguments. So if I'm reading this right:

instead of

Db::get( N(exchange), N(exchange), N(account), owner, account );

use:

account = Db::get( N(exchange), N(exchange), N(account), owner );

I like the elegance of C++ but I am reluctant to the potential security troubles without proper memory management. If I remember well, ETC/ETH split happened because of a trivial bug, a recursive call or something. If C++ will be language of choice for EOS, I think it will need some strong memory management rules, built at the blockchain level. If there's bare metal C++ written, then the attack surface is big. I don't know how exactly Web Assembly will deal with this, I admit, but without taking that into account, it seems like a playground for nasty stuff waiting to explode.

We assembly keeps everything safe and attack surfaces minimal.

WOW! such a informative post. I loved it

Wow, thanks for sharing with us, keep up the good work, bro!
Upvoted and reestem'D

Gr8t

This is a great post, however this I don't comprehend @dan or someone please explain to me why this post is in negative?

He declines payout on a lot of his posts. Probably because he created Steem and doesn't think it would be fair to the rest of us Steemians if he took a lot of the rewards.

You are right @kendewitt just confirmed lol. He got a lot a dough Steempower and all. Must be the boss 4 sure.

Right. But he doesn't work on Steem anymore. He left it for the rest of the team to work on and is developing EOS now.

@dan Analysis of Steem's Economy - A Social Scientist's First Impressions - Part 3/4 in the series.

https://steemit.com/steemit/@cyberspace/analysis-of-steem-s-economy-a-social-scientist-s-first-impressions-part-3-4

That's great. I'll test it.

its really useful software wtih much fun thanks to introduce @dan

nice post!, one of my favorite programming languange :)

Great info @dan, thank for shared !, allow me for resteem this post

@syahhiran

thank you for sharing

Nice, but just now i receive massages in two telegram communities about EOS starts sell ethers on stocks. Fake info or no?

nice post..!!

Very well written article. C for life. But got a question, how are transactions related to memory addresses? and how does the WebAssembly framework knows/can relate a transaction to a particular memory address?

Awesome @dan - This man knows his stuff and is a legend in his own right in crypto - Very grateful for the play be play illustrating the coding used to write the contracts

Thanks for your update ,respect 🙂

I understand not but it all sounds and looks very interesting.
Maybe EOS will be the new Bitcoin, now that Ethereum is planing major changes that will affect mining.

i wonder why you decline your payouts from your post......... you can always give them to small minnows like me.... hahaha

yep ,it is very beneficial for develpor/programmers , its very helpful. thanks for this post.
UPVOTED.....

I didntt even realize there was a C++ to WebAssembly compiler, that opens a huge scope for C++ :)

Is it beta for safe for production? And does it support C++ 11?

@dan how would someone offer a token smart contract which offers both ability to reward dividends to holders and the ability of holders to reinvest the dividends back into the token simulating DRIP functionality?

I know C++ so these examples interest me.

Does the IMF uses this for there SDR

@dan,
First, I would like to say great post you have written here.

Second, I feel you know this language ;) C and C++ is the core of most modern programming languages. Seems you have the idea and experience about this.

Third, thanks for reminding me I was learn this language while I was at the university!

Fourth, EOS seems to be a good shot! I will do a small research and go for it!

Finally,
Thank you very much for this amazing article! I become a fan of yours and awaiting to read the next post as well.

Cheers~

That is amazing ....
Your post is impotant for people to join API....
That is the good sharing...
Thanks for sharing @dan ....
I am @viqral will support your post.
Please upvote mine @dan
Beucause i need your upvote mine..
Thanks @dan

Hi, just wondering all the eos i buy over the next year , will i be able to simply transfer it into an eos wallet when it all goes live?

Wonderful post. It is of great benefit. Thanks

please

Hello sir @dan, can I possibly disturb your privacy and have a word with you? Can I contact you on steemit.chat or you prefer it here?

Good one..

  ·  7 years ago (edited)

I Am Getting Into EOS today ... So it sounds like EOS would make Stratis obsolete because EOS does the same but more (???) Yet, nobody really knows why things actually take off, but we are taught to be know it alls... I think that now is a great time to diversify your crypto holdings ... Getting Steem, ANS, Sia, IOTA, BAT, etc ... I just joined Steemit.com, I plan on posting a lot of Fun Art Content That I Make as well as Creative Crypto Content : Lets follow each other and enjoy this exciting ride (!!!) ~ mum

Many of theese altcoins have not proven themselves.

Hi @dan,
I know you're a busy man. I have a question, are you a fan of the NFL?
And would you be interested in making NFL football picks, just one week?
I'm writing sports for @thedailysteemit and I thought the readers would enjoy a post with your picks. I'm attempting to recruit Steemit Celebrities for this. Thanks for your consideration.

@dan My introduction

FYI: My article on EOS and the potential for disrupting Steem and every other 1st generation blockchain on the basis of 1) their code and design structure, 2) transaction capacity and 3) migration of the masses into blockchain space. Would appreciate your feedback on this
https://steemit.com/steemit/@cyberspace/the-new-eos-platform-will-disrupt-steem-bitcoin-ethereum-and-all-1st-generation-blockchains-and-cryptocoins-guaranteed