Skip to content

Commit

Permalink
Merge pull request #316 from skalenetwork/enhancement/add-remaining-docs
Browse files Browse the repository at this point in the history
Update TokenManager.sol
  • Loading branch information
cstrangedk authored Nov 9, 2020
2 parents 1c5f306 + c06cf39 commit 8ba7484
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 19 deletions.
116 changes: 107 additions & 9 deletions proxy/contracts/MessageProxyForMainnet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,16 @@ interface ISchains {
returns (bool);
}


/**
* @title Message Proxy for Mainnet
* @dev Runs on Mainnet, contains functions to manage the incoming messages from
* `dstChainID` and outgoing messages to `srcChainID`. Every SKALE chain with
* IMA is therefore connected to MessageProxyForMainnet.
*
* Messages from SKALE chains are signed using BLS threshold signatures from the
* nodes in the chain. Since Ethereum Mainnet has no BLS public key, mainnet
* messages do not need to be signed.
*/
contract MessageProxyForMainnet is Initializable {

// 16 Agents
Expand Down Expand Up @@ -115,6 +124,9 @@ contract MessageProxyForMainnet is Initializable {
mapping(bytes32 => ConnectedChainInfo) public connectedChains;
mapping ( uint256 => OutgoingMessageData ) private _outgoingMessageData;

/**
* @dev Emitted for every outgoing message to `dstChain`.
*/
event OutgoingMessage(
string dstChain,
bytes32 indexed dstChainHash,
Expand All @@ -138,20 +150,39 @@ contract MessageProxyForMainnet is Initializable {
string message
);

/**
* @dev Adds an authorized caller.
*
* Requirements:
*
* - `msg.sender` must be an owner.
*/
function addAuthorizedCaller(address caller) external {
require(msg.sender == owner, "Sender is not an owner");
authorizedCaller[caller] = true;
}

/**
* @dev Removes an authorized caller.
*
* Requirements:
*
* - `msg.sender` must be an owner.
*/
function removeAuthorizedCaller(address caller) external {
require(msg.sender == owner, "Sender is not an owner");
authorizedCaller[caller] = false;
}

// This is called by schain owner.
// On mainnet, SkaleManager will call it every time a SKALE chain is
// created. Therefore, any SKALE chain is always connected to the main chain.
// To connect to other chains, the owner needs to explicitly call this function
/**
* @dev Adds a `newChainID`.
*
* Requirements:
*
* - `msg.sender` must be SKALE Node address.
* - `newChainID` must not be "Mainnet".
* - `newChainID` must not already be added.
*/
function addConnectedChain(
string calldata newChainID
)
Expand All @@ -176,6 +207,14 @@ contract MessageProxyForMainnet is Initializable {
});
}

/**
* @dev Removes connected chain from this contract.
*
* Requirements:
*
* - `msg.sender` must be owner.
* - `newChainID` must be initialized.
*/
function removeConnectedChain(string calldata newChainID) external {
require(authorizedCaller[msg.sender], "Not authorized caller");

Expand All @@ -186,7 +225,14 @@ contract MessageProxyForMainnet is Initializable {
delete connectedChains[keccak256(abi.encodePacked(newChainID))];
}

// This is called by a smart contract that wants to make a cross-chain call
/**
* @dev Posts message from this contract to `dstChainID` MessageProxy contract.
* This is called by a smart contract to make a cross-chain call.
*
* Requirements:
*
* - `dstChainID` must be initialized.
*/
function postOutgoingMessage(
string calldata dstChainID,
address dstContract,
Expand Down Expand Up @@ -214,6 +260,16 @@ contract MessageProxyForMainnet is Initializable {
);
}

/**
* @dev Posts incoming message from `srcChainID`.
*
* Requirements:
*
* - `msg.sender` must be authorized caller.
* - `srcChainID` must be initialized.
* - `startingCounter` must be equal to the chain's incoming message counter.
* - If destination chain is Mainnet, message signature must be valid.
*/
function postIncomingMessages(
string calldata srcChainID,
uint256 startingCounter,
Expand Down Expand Up @@ -260,20 +316,45 @@ contract MessageProxyForMainnet is Initializable {
_popOutgoingMessageData(idxLastToPopNotIncluding);
}

// Test function - will remove in production
/**
* @dev Increments incoming message counter.
*
* Note: Test function. TODO: remove in production.
*
* Requirements:
*
* - `msg.sender` must be owner.
*/
function moveIncomingCounter(string calldata schainName) external {
require(msg.sender == owner, "Sender is not an owner");
connectedChains[keccak256(abi.encodePacked(schainName))].incomingMessageCounter++;
}

// Test function - will remove in production
/**
* @dev Sets the incoming and outgoing message counters to zero.
*
* Note: Test function. TODO: remove in production.
*
* Requirements:
*
* - `msg.sender` must be owner.
*/
function setCountersToZero(string calldata schainName) external {
require(msg.sender == owner, "Sender is not an owner");
connectedChains[keccak256(abi.encodePacked(schainName))].incomingMessageCounter = 0;
connectedChains[keccak256(abi.encodePacked(schainName))].outgoingMessageCounter = 0;
}

// Registration state detection
/**
* @dev Checks whether chain is currently connected.
*
* Note: Mainnet chain does not have a public key, and is implicitly
* connected to MessageProxy.
*
* Requirements:
*
* - `someChainID` must not be Mainnet.
*/
function isConnectedChain(
string calldata someChainID
)
Expand Down Expand Up @@ -321,6 +402,9 @@ contract MessageProxyForMainnet is Initializable {
contractManagerSkaleManager = newContractManager;
}

/**
* @dev Checks whether outgoing message is valid.
*/
function verifyOutgoingMessageData(
uint256 idxMessage,
address sender,
Expand Down Expand Up @@ -365,6 +449,9 @@ contract MessageProxyForMainnet is Initializable {
);
}

/**
* @dev Checks whether message BLS signature is valid.
*/
function _verifyMessageSignature(
uint256[2] memory blsSignature,
bytes32 hash,
Expand All @@ -391,6 +478,9 @@ contract MessageProxyForMainnet is Initializable {
);
}

/**
* @dev Returns hash of message array.
*/
function _hashedArray(Message[] memory messages) private pure returns (bytes32) {
bytes memory data;
for (uint256 i = 0; i < messages.length; i++) {
Expand All @@ -406,6 +496,11 @@ contract MessageProxyForMainnet is Initializable {
return keccak256(data);
}

/**
* @dev Push outgoing message into outgoingMessageData array.
*
* Emits an {OutgoingMessage} event.
*/
function _pushOutgoingMessageData( OutgoingMessageData memory d ) private {
emit OutgoingMessage(
d.dstChain,
Expand All @@ -422,6 +517,9 @@ contract MessageProxyForMainnet is Initializable {
++_idxTail;
}

/**
* @dev Pop outgoing message from outgoingMessageData array.
*/
function _popOutgoingMessageData( uint256 idxLastToPopNotIncluding ) private returns ( uint256 cntDeleted ) {
cntDeleted = 0;
for ( uint256 i = _idxHead; i < idxLastToPopNotIncluding; ++ i ) {
Expand Down
60 changes: 50 additions & 10 deletions proxy/contracts/predeployed/TokenManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ interface ILockAndDataTM {
// This contract runs on schains and accepts messages from main net creates ETH clones.
// When the user exits, it burns them


/**
* @title Token Manager
* @dev Runs on SKALE Chains, accepts messages from mainnet, and instructs
* TokenFactory to create clones. TokenManager mints tokens via
* LockAndDataForSchain*. When a user exits a SKALE chain, TokenFactory
* burns tokens.
*/
contract TokenManager is PermissionsForSchain {


Expand Down Expand Up @@ -107,10 +113,16 @@ contract TokenManager is PermissionsForSchain {
transferToSchain(schainID, to, amount);
}

/**
* @dev Adds ETH cost to perform exit transaction.
*/
function addEthCostWithoutAddress(uint256 amount) external {
addEthCost(amount);
}

/**
* @dev Deducts ETH cost to perform exit transaction.
*/
function removeEthCost() external {
uint256 returnBalance = ILockAndDataTM(getLockAndDataAddress()).removeGasCosts(msg.sender);
require(ILockAndDataTM(getLockAndDataAddress()).sendEth(msg.sender, returnBalance), "Not sent");
Expand Down Expand Up @@ -400,8 +412,17 @@ contract TokenManager is PermissionsForSchain {
);
}

// Receive money from main net and Schain

/**
* @dev Allows MessageProxy to post operational message from mainnet
* or SKALE chains.
*
* Emits an {Error} event upon failure.
*
* Requirements:
*
* - MessageProxy must be the sender.
* - `fromSchainID` must exist in TokenManager addresses.
*/
function postMessage(
address sender,
string calldata fromSchainID,
Expand Down Expand Up @@ -443,13 +464,17 @@ contract TokenManager is PermissionsForSchain {
}
}

// This is called by schain owner.
// Exit to main net
/**
* @dev Performs an exit (post outgoing message) to Mainnet.
*/
function exitToMain(address to, uint256 amount) public {
bytes memory empty = "";
exitToMain(to, amount, empty);
}

/**
* @dev Performs an exit (post outgoing message) to Mainnet.
*/
function exitToMain(address to, uint256 amount, bytes memory data) public receivedEth(amount) {
bytes memory newData;
newData = abi.encodePacked(bytes1(uint8(1)), data);
Expand Down Expand Up @@ -490,22 +515,34 @@ contract TokenManager is PermissionsForSchain {
);
}

/**
* @dev Adds ETH cost for `msg.sender` exit transaction.
*/
function addEthCost(uint256 amount) public {
addEthCost(msg.sender, amount);
}

/**
* @dev Adds ETH cost for user's exit transaction.
*/
function addEthCost(address sender, uint256 amount) public receivedEth(amount) {
ILockAndDataTM(getLockAndDataAddress()).addGasCosts(sender, amount);
}

function getChainID() public view returns ( string memory cID ) { // l_sergiy: added
/**
* @dev Returns chain ID.
*/
function getChainID() public view returns ( string memory cID ) {
if ((keccak256(abi.encodePacked(_chainID))) == (keccak256(abi.encodePacked(""))) ) {
return SkaleFeatures(0x00c033b369416c9ecd8e4a07aafa8b06b4107419e2)
.getConfigVariableString("skaleConfig.sChain.schainID");
}
return _chainID;
}

/**
* @dev Returns MessageProxy address.
*/
function getProxyForSchainAddress() public view returns ( address ow ) { // l_sergiy: added
if (_proxyForSchainAddress == address(0) ) {
return SkaleFeatures(0x00c033b369416c9ecd8e4a07aafa8b06b4107419e2).getConfigVariableAddress(
Expand All @@ -516,14 +553,17 @@ contract TokenManager is PermissionsForSchain {
}

/**
* @dev Convert first byte of data to Operation
* 0x01 - transfer eth
* @dev Converts the first byte of data to an operation.
*
* 0x01 - transfer ETH
* 0x03 - transfer ERC20 token
* 0x05 - transfer ERC721 token
* 0x13 - transfer ERC20 token - raw mode
* 0x15 - transfer ERC721 token - raw mode
* @param data - received data
* @return operation
*
* Requirements:
*
* - Operation must be one of the possible types.
*/
function _fallbackOperationTypeConvert(bytes memory data)
private
Expand Down
Binary file added proxy/docs/IMA-token-positioning.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions proxy/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- SPDX-License-Identifier: (AGPL-3.0-only OR CC-BY-4.0) -->

# SKALE IMA Proxy Documentation

- [IMA Basic Architecture](./basic-architecture.md)
- [IMA Transfer Flows](./transfer-flows.md)
- [ERC20 Transfer Protection](./erc20-transfer-protection.md)

Dapp Development with IMA

- [IMA Documentation for Dapps](https://skale.network/docs/developers/products/interchain-messaging-agent/overview)
21 changes: 21 additions & 0 deletions proxy/docs/basic-architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!-- SPDX-License-Identifier: (AGPL-3.0-only OR CC-BY-4.0) -->

# SKALE IMA Basic Architecture

There are a set of contracts deployed on mainnet, and another set of contracts that are pre-deployed to each IMA enabled SKALE chain. Both sets of contracts are connected together using a SKALE IMA node.js agent.

## Mainnet contracts

- DepositBox
- MessageProxy
- LockAndData...
- ERC Modules

## SKALE chain contracts (pre-deployed)

- MessageProxy
- TokenManager
- TokenFactory
- LockAndData...
- ERC Modules
- ETHERC20
Binary file added proxy/docs/erc20-transfer-to-mainnet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added proxy/docs/erc20-transfer-to-schain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 8ba7484

Please sign in to comment.