System Architecture of MOLDEX α

GAME
GAME
Published in
12 min readJul 14, 2019

We released MOLDEX α on June 30, 2019. Here, we will summarize the overview of the MOLDEX α system architecture along the following three points. Hopefully it will be helpful for future development around Dapps and blockchains.

  • About the contract of DEX
  • About server side
  • About browser wallet

The structure of MOLDEX α is designed to be aware of processing performance and non-functional requirements (such as availability, operation and maintainability), designability from the user’s perspective, and future UX improvements. In addition, MOLDEX α is configured with full serverless considering the compatibility with blockchains.

As for how to use MOLDEX α, you can refer to the previous article.

Introducing MOLDEX α version

About the contract of DEX

The contract used with MOLDEX α can be confirmed with github or Etherscan. In MOLDEX α, we have defined the trade function (described later) so that anyone can exchange ERC721 and ERC20 (or even exchange with ETH).

Asset contract

When constructing a token exchange mechanism on the DEX contract side, two functions, approve () and transferFrom () defined in ERC20 and ERC721, are used.

  • approve ()
    The approve () function is used to allow the third party (in this case, the DEX contract) to transfer the token from the sender’s balance (in the case of ERC 721, specify tokenId). Tokens are stored in the allowed type mapping data structure.
// ERC20 
function approve(
address _spender,
uint256 _value
)
public
returns (bool)
{
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}

// ERC721
function approve(address _to, uint256 _tokenId) public {
address owner = ownerOf(_tokenId);
require(_to != owner);
require(msg.sender == owner || isApprovedForAll(owner, msg.sender));

tokenApprovals[_tokenId] = _to;
emit Approval(owner, _to, _tokenId);
}
  • transferFrom ()
    The transferFrom () function is used to transfer token by a third party (in this case, a DEX contract). The third party (msg.sender) can only withdraw below the allowed balance (ERC 721 can only extract the specified tokenId).
// ERC20
function transferFrom(
address _from,
address _to,
uint256 _value
)
public
returns (bool)
{
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
require(_to != address(0));

balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}

// ERC721
function transferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
{
require(isApprovedOrOwner(msg.sender, _tokenId));
require(_from != address(0));
require(_to != address(0));

clearApproval(_from, _tokenId);
removeTokenFrom(_from, _tokenId);
addTokenTo(_to, _tokenId);

emit Transfer(_from, _to, _tokenId);
}
  • allowance ()
    The allowance () function is a view function that returns the value of the token assigned to allowed by the approve () function.
    In the case of ERC 721, the getApproved () function is prepared in the same way, and it is a view function that returns the address (ie, approved) that has the right to transfer the token from tokenId.
// ERC20
function allowance(
address _owner,
address _spender
)
public
view
returns (uint256)
{
return allowed[_owner][_spender];
}

// ERC721
function getApproved(uint256 _tokenId) public view returns (address) {
return tokenApprovals[_tokenId];
}

Flow of asset exchange

Taker executes approve () function for Token Contract, and approves to transfer moldcoin of arbitrary quantity (in the website, it is expressed as deposit but it is actually the process of approve).

The Maker passes to the server the data needed to execute the Dex Contract’s trade function. Taker passes the data necessary to execute Dex Contract’s trade function to the server.

On the server side, when the data of Maker and Taker are collected, execute the trade function.In trade function, execute transferFrom () that is permitted for Dex Contract. At this time, the token to be transferred by transferFrom must be approved by the approve () function.

Execute the transferFrom () function to complete the transfer of moldcoin from Taker to Maker, and the transfer of ERC721 asset from Maker to Taker.

moldex-contract-flow

1. Prepare for exchange with the approve function
The Taker side buys ERC721 assets in moldcoin (ERC20). The DEX Contract approves any amount of moldcoin, making _spender a Dex Contract so that it can handle moldcoin. The Maker side sells ERC721. In order to allow DEX Contract to send ERC 721 assets, approve Dex Contract as _spender .

2. Send signed order data
The necessary order data is sent to the server to execute the trade function.
The Maker will hash the following 6 elements in order to generate orderHash and sign it with the secret key.

  • Dex Contract Address
  • ERC 721 Token Contract Address
  • ERC721 Token ID
  • Maker Address
  • ERC20 Token Contract Address
  • ERC20 Amount

Taker will hash the following two elements in order to generate tradeHash and sign it with the secret key.

  • orderHash
  • Taker Address

3. Execution of trade function
The server side mainly performs rawdata verification and signature verification.
rawdata is the order data mentioned above. From the Maker / Taker side, rawdata +orderHash or tradeHash will be sent to the server side. On the server side, the hash function checks if the contents of rawdata are correct. Also, the public key can be uniquely determined from the values of v, r, s and the original data signed with a private key, so we also check if the signature is correct.

In Dex Contract’s trade function, signature is verified using ecrecover (hash, v, r, s). If the return value is not match with order owner's address, the order will be reverted.

4. Execution of transferFrom function
As Dex Contract is msg.sender, transferFrom function is executed twice for moving ERC 20 token and moving ERC 721 token.

Using proxy contract

One of Ethereum’s greatest benefits is that all transactions involved in the transfer of funds, all deployed contracts, and all transactions done for one contract are published and immutable on the blockchain. It means that there is no way to hide or modify the deals that have been made so far, and the ability to verify the validity and state of all transactions at any node on the Ethereum network makes Ethereum a very robust distributed system.

But the biggest drawback is that you can’t change the smart contract source code once it’s deployed. Developers working with centralized applications (Facebook, Airbnb, etc.) are constantly updating to fix bugs and introduce new features. It is impossible to run this traditional development pattern on Ethereum.

You can not upgrade the code of a smart contract that has already been deployed, but you can configure a proxy contract architecture that allows you to use the new deployed contract as if the main logic had been upgraded.

Since this Dex Contract is also an alpha version, it is expected that many revisions will be made and upgraded in the future. At that time, you can benefit from being able to switch to the new contract version by separating and managing the storage and logic parts of the contract.

proxy contract

Initialize

  1. Deploy OwnedUpgradeabilityProxy
  2. Deploy the first version of logic contract
  3. Call the OwnedUpgradeabilityProxy`` upgradeToAndCall function to register the logic contract on the proxy contract side and initialize the proxy contract side as well.

update

  1. Deploy a new logic contract with the same variable name as the previous logic contract
  2. Call the OwnedUpgradeabilityProxy`` upgradeTo function to update the logic contract

Assign an implementation address to a suitably hashed byte string to store the information of the variable in the storage slot defined in the proxy contract side.

//UpgradeabilityProxy.sol
bytes32 private constant implementationPosition = keccak256("org.zeppelinos.proxy.implementation");


function implementation() public view returns (address impl) {
bytes32 position = implementationPosition;
assembly {
impl := sload(position)
}
}

function setImplementation(address newImplementation) internal {
bytes32 position = implementationPosition;
assembly {
sstore(position, newImplementation)
}
}

Use the unstructured storage slots defined in the proxy contract to store the data needed for the upgrade.

In proxy contract, a constant that gives a sufficiently random storage location for storing logic contract address is defined by hashing an arbitrary string.

Because constant state variables do not occupy storage slots, there is no need to worry that the implementationPosition is accidentally overwritten by a proxy contract. Depending on how Solidity lays out its state variables in storage, it is unlikely that this storage slot will be collided with anything else defined in the logic contract.

By using this pattern, no logic contract version needs to know about the storage structure of the proxy, but all future logic contracts need to inherit the storage variables declared by their higher version. Future upgrades of the logic contract will allow you to upgrade existing features and introduce new features and new storage variables.

The implementation provided by the Zeppelin’s labs repository also uses the concept of a proxy contract. The owner of the proxy contract is the only address that can be used to upgrade or transfer ownership of the proxy contract.

The specification of assembly such as sstore and sload refer to the following link.
Reference: Solidity Assembly

The biggest advantage of this proxy contract is that the logic contract side doesn’t have to define it as part of the proxy.

Note
The same goes for constructors such as ownable contract that loses its functionality. Only the initial state determined by the constructor when deploying the logic contract is not stored in the proxy contract side.

Therefore, in the logic contract, you need to create an initialize function etc. and define the owner properly. Alternatively, you need to call and initialize the function that is the constructor when you Update with the upgradeToAndCall function.

Unstructured Storage uses the solidity assembly to store the address of the logic contract, so the logic contract side is better not need to inherit contracts such as upgradeablity. In addition to being able to transfer owner authority, you can also define new variables and put them in storage.

About server-side configuration

MOLDEX α uses a serverless architecture and mainly performs three processes: static file processing, API processing, and batch processing.

moldex-server-side

Static file processing

Static file processing is used as a storage destination for js files and image files, and is built using CloudFront as a CDN and S3 for hosting a static website.

Using CloudFront enables not only caching but also AWS Shield and DDoS protection. Also, S3 alone can not use SSL / TLS protocol with its own domain, but it can be used by using CloudFront.

As mentioned above, CloudFront offers a variety of benefits, so we have adopted a configuration that uses CloudFront, not directly accessing S3.

API Processing

ECS lets you easily deploy, manage, and scale Docker containers that run applications, services, and batch processes. Because of container operation, application availability is maintained even when API changes.

Also, currently there is no need to process many requests at the same time, but it will be possible to easily scale the application in situations where access will be concentrated in the future.

Access to Ethereum is not operated from the front end, but is treated through API to reduce unnecessary processing on the front end.

Batch processing

For example, the transaction history after executing the trade function is always kept up-to-date by referencing Event of Transaction in Ethereum’s blockchain.

Also, approve to Dex Contract will be invalidated if the asset that was being approved is transferred to another address. Therefore, it is necessary to monitor allowance on the Ethereum side at regular intervals.

CI / CD Environment

CI/CD

It becomes a common configuration diagram above, but it was able to carry out development relatively smoothly by running the process of Build → test → deploy from circleCI.

This time, we adopted using Golang for the part of API, and there were many parts that refer the implementation of Geth (go-ethereum).

About browser wallet

Currently, most Dapps on Ethereum use the Metamask, but MOLDEX α has implemented the app’s built-in browser wallet with full scratch instead of using Metamask. The intention is to be conscious of DEX that can be used by users who are not familiar with blockchain.

We think that users who are a little more familiar with blockchains are adding to the extension of chrome as usual, but most users do not use metamask or even extension at present.

We think the ideal of Dapp and other Dapps is to achieve UX that is smooth and easy so that users don’t know it is using blockchains. In order to use one Dapps, there is a way (for most users) that you do not need to install Metamask (in most users), it is possible to incorporate the wallet function into the application. With MOLDEX α, while roughing, by incorporating the browser wallet, the user who has logged in once is designed to be able to use the app with only password.

Private Key Management

In DEX, users are fully responsible for private key management, and the server side has no information about the user’s private key.

moldex-wallet-flow

Users accessing MOLDEX for the first time need to create a new account with create key or import an existing Ethereum wallet.

In MOLDEX α, the user’s private key is managed by session, and the encrypted json key file is managed permanently by the browser’s local storage.

The secret key managed by session is deleted when the user leaves the page (for example, delete the tab), so when you access it again, you will be prompted for a password to unlock the encrypted key file stored in the local storage.

On the other hand, since the encrypted key file is stored in local storage even when the user leaves the page, when the user accesses again, the user just enters password to unlock it and use the application.

Once the wallet is unlocked, the user is free to use the application until the session is terminated. This simplifies the tedious (and slow) Metamask process where pop-ups appear and acknowledge every time.

Also, if you want your browser to be encrypted but you do not want to keep key file information, you can delete the key file information from local storage by doing delete key. In that case, you need to do an import key when accessing again.

wallet-operation-description

When using MOLDEX α, make sure to export the key file and store it on a cloud or in a safe place.

Benefits of DEX

According to DEX overview: About differences and features from centralized exchanges [PART 1] , there are three points about merits of DEX.

  • Privacy is protected
  • High security
  • The possibility of operation is low

Let’s see if such features are actually in MOLDEX α.

With MOLDEX α, anyone can create an account on the application and start trading. At this time, since the server side does not manage user information, completely anonymous transactions are realized.

Also, since the user’s private key is managed by the user, even if the server side is hacked, it is not possible to move the user’s assets (game item or moldcoin).

In addition, even operating side can not manipulate the order illegally on the server, because the order is signed with user’s private key, and the signature is verified on the Dex Contract. Thus, the user can trade on MOLDEX α in trustless (without having to trust the server side).

From the above point of view, it can be said that this MOLDEX α is a useful example that shows the world view of MOLDEX and can specifically understand the advantages of DEX.

The future of MOLDEX

Considering how to trade digital assets freely and quickly at P2P, one way is to use Decentralized Exchange (DEX). However, starting with the collaboration with Ethereum, if you try to convert DEX into a service, the development cost is high, and it is more difficult than you might imagine. Also, the time it takes to generate Ethereum’s blocks and the cost of the gas are one of the major factors that lower UX.

In the future, the MOLDEX α version is aiming to realize the concept of MOLD on Ethereum by adding the following various other functions.

  • Increase asset types of ERC 721
  • Make ETH exchangeable
  • Enable exchange of ERC 1155 assets
  • Make it possible to view the transaction history of sending and receiving
  • Add login sign in function
  • Make a game page

※ MOLDEX α is a test version for moldcoin owners. Please note that there is a possibility that the specifications will be changed significantly in the future.

At the same time, at MOLD, we would like to proceed with building an original chain specializing in games, in order to solve the problems that Etheruem has with regard to games. By pursuing MOLDEX development on Ethereum and R & D on original chains, we will steadily promote projects in the rapidly changing blockchain industry.

Recruitment
MOLD is currently recruiting members of engineers who can grow MOLDEX and original chain development as better services. Please feel free to contact us at Twitter or team@moldproject.org if you are interested.

— — — — — — — — — — — — — — — -
Cosmos Gaming Hub Project(Former MOLD project)
CEO & Co-Founder

Takumi Asano

For all game enthusiasts

--

--

GAME
GAME
Editor for

Cosmos Gaming Hub is a fair and secure distributed gaming platform which supports the development of new games and simplifies the trading of digital assets.