Skip to content

Commit

Permalink
upd Nil.sol to 2024.09.03 release
Browse files Browse the repository at this point in the history
  • Loading branch information
Gezort authored Sep 4, 2024
2 parents e74b6bc + b148909 commit ab5c206
Show file tree
Hide file tree
Showing 2 changed files with 197 additions and 32 deletions.
122 changes: 90 additions & 32 deletions Nil.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ library Nil {
address private constant ASYNC_CALL = address(0xfd);
address public constant VERIFY_SIGNATURE = address(0xfe);
address public constant IS_INTERNAL_MESSAGE = address(0xff);
address private constant MINT_CURRENCY = address(0xd0);
address public constant MINT_CURRENCY = address(0xd0);
address private constant GET_CURRENCY_BALANCE = address(0xd1);
address private constant SEND_CURRENCY_SYNC = address(0xd2);
address private constant GET_MESSAGE_TOKENS = address(0xd3);
address private constant GET_GAS_PRICE = address(0xd4);
address private constant GET_POSEIDON_HASH = address(0xd5);

address payable public constant MINTER_ADDRESS = payable(address(0x0001222222222222222222222222222222222222));
address private constant AWAIT_CALL = address(0xd6);
address private constant CONFIG_PARAM = address(0xd7);
address private constant SEND_REQUEST = address(0xd8);

// The following constants specify from where and how the gas should be taken during async call.
// Forwarding values are calculated in the following order: FORWARD_VALUE, FORWARD_PERCENTAGE, FORWARD_REMAINING.
Expand Down Expand Up @@ -41,9 +42,17 @@ library Nil {
address bounceTo,
uint value,
bytes memory callData
) internal returns(bool) {
) internal {
Token[] memory tokens;
return asyncCall(dst, address(0), bounceTo, 0, FORWARD_REMAINING, false, value, tokens, callData);
asyncCall(dst, address(0), bounceTo, 0, FORWARD_REMAINING, false, value, tokens, callData);
}

// awaitCall makes an asynchronous call to `dst` contract and waits for the result.
function awaitCall(
address dst,
bytes memory callData
) internal returns(bytes memory, bool) {
return __Precompile__(AWAIT_CALL).precompileAwaitCall(dst, callData);
}

// asyncCall makes an asynchronous call to `dst` contract.
Expand All @@ -56,9 +65,9 @@ library Nil {
bool deploy,
uint value,
bytes memory callData
) internal returns(bool) {
) internal {
Token[] memory tokens;
return asyncCall(dst, refundTo, bounceTo, feeCredit, forwardKind, deploy, value, tokens, callData);
asyncCall(dst, refundTo, bounceTo, feeCredit, forwardKind, deploy, value, tokens, callData);
}

// asyncCall makes an asynchronous call to `dst` contract.
Expand All @@ -72,10 +81,9 @@ library Nil {
uint value,
Token[] memory tokens,
bytes memory callData
) internal returns(bool) {
bool success = Precompile(ASYNC_CALL).precompileAsyncCall{value: value}(deploy, forwardKind, dst, refundTo,
) internal {
__Precompile__(ASYNC_CALL).precompileAsyncCall{value: value}(deploy, forwardKind, dst, refundTo,
bounceTo, feeCredit, tokens, callData);
return success;
}

// asyncCall makes an asynchronous call to `dst` contract.
Expand All @@ -88,10 +96,9 @@ library Nil {
uint value,
Token[] memory tokens,
bytes memory callData
) internal returns(bool) {
bool success = Precompile(ASYNC_CALL).precompileAsyncCall{value: value}(deploy, FORWARD_NONE, dst, refundTo,
) internal {
__Precompile__(ASYNC_CALL).precompileAsyncCall{value: value}(deploy, FORWARD_NONE, dst, refundTo,
bounceTo, feeCredit, tokens, callData);
return success;
}

function syncCall(
Expand All @@ -102,12 +109,21 @@ library Nil {
bytes memory callData
) internal returns(bool, bytes memory) {
if (tokens.length > 0) {
Precompile(SEND_CURRENCY_SYNC).precompileSendTokens(dst, tokens);
__Precompile__(SEND_CURRENCY_SYNC).precompileSendTokens(dst, tokens);
}
(bool success, bytes memory returnData) = dst.call{gas: gas, value: value}(callData);
return (success, returnData);
}

function sendRequest(
address dst,
uint256 value,
bytes memory context,
bytes memory callData
) internal {
__Precompile__(SEND_REQUEST).precompileSendRequest{value: value}(dst, context, callData);
}

// Send raw internal message using a special precompiled contract
function sendMessage(uint g, bytes memory message) internal {
uint message_size = message.length;
Expand Down Expand Up @@ -145,20 +161,14 @@ library Nil {
return result;
}

// mintCurrency mints a token with a given id and amount. Can be called only by the special minter contract.
// Returns `true` if the minting was successful.
function mintToken(uint256 id, uint256 amount) internal returns(bool) {
return Precompile(MINT_CURRENCY).precompileMintCurrency(id, amount);
}

// getCurrencyBalance returns the balance of a token with a given id for a given address.
function tokensBalance(address addr, uint256 id) internal returns(uint256) {
return Precompile(GET_CURRENCY_BALANCE).precompileGetCurrencyBalance(id, addr);
function currencyBalance(address addr, uint256 id) internal view returns(uint256) {
return __Precompile__(GET_CURRENCY_BALANCE).precompileGetCurrencyBalance(id, addr);
}

// msgTokens returns tokens from the current message.
function msgTokens() internal returns(Token[] memory) {
return Precompile(GET_MESSAGE_TOKENS).precompileGetMessageTokens();
return __Precompile__(GET_MESSAGE_TOKENS).precompileGetMessageTokens();
}

// getShardId returns shard id for a given address.
Expand All @@ -173,7 +183,7 @@ library Nil {
// the message will be processed; and `price_growth_factor` is the maximum value by which gas can grow per block.
// TODO: add `getEstimatedGasPrice` method, which implements the above formula.
function getGasPrice(address addr) internal returns(uint256) {
return Precompile(GET_GAS_PRICE).precompileGetGasPrice(getShardId(addr));
return __Precompile__(GET_GAS_PRICE).precompileGetGasPrice(getShardId(addr));
}

function createAddress(uint shardId, bytes memory code, uint256 salt) internal returns(address) {
Expand All @@ -193,7 +203,48 @@ library Nil {
}

function getPoseidonHash(bytes memory data) internal returns(uint256) {
return Precompile(GET_POSEIDON_HASH).precompileGetPoseidonHash(data);
return __Precompile__(GET_POSEIDON_HASH).precompileGetPoseidonHash(data);
}

function setConfigParam(string memory name, bytes memory data) internal {
__Precompile__(CONFIG_PARAM).precompileConfigParam(true, name, data);
}

function getConfigParam(string memory name) internal returns(bytes memory) {
return __Precompile__(CONFIG_PARAM).precompileConfigParam(false, name, bytes(""));
}

struct ValidatorInfo {
uint8[33] PublicKey;
address WithdrawalAddress;
}

struct ParamValidators {
ValidatorInfo[] list;
}

struct ParamGasPrice {
uint256 gasPriceScale;
}

function setValidators(ParamValidators memory validators) internal {
bytes memory data = abi.encode(validators);
setConfigParam("curr_validators", data);
}

function getValidators() internal returns(ParamValidators memory) {
bytes memory data = getConfigParam("curr_validators");
return abi.decode(data, (ParamValidators));
}

function setParamGasPrice(ParamGasPrice memory param) internal {
bytes memory data = abi.encode(param);
setConfigParam("gas_price", data);
}

function getParamGasPrice() internal returns(ParamGasPrice memory) {
bytes memory data = getConfigParam("gas_price");
return abi.decode(data, (ParamGasPrice));
}
}

Expand Down Expand Up @@ -221,18 +272,25 @@ contract NilBase {
}
}

// Precompile is a contract that provides stubs for precompiled contract calls.
// NOTE: Function should always return value, otherwise Solidity will check contract existence by EXTCODESIZE opcode
contract Precompile {
function precompileMintCurrency(uint256 id, uint256 amount) public returns(bool) {}
function precompileGetCurrencyBalance(uint256 id, address addr) public returns(uint256) {}
abstract contract NilBounceable is NilBase {
function bounce(string calldata err) virtual payable external;
}

// WARNING: User should never use this contract directly.
contract __Precompile__ {
function precompileMintCurrency(uint256 amount) public returns(bool) {}
function precompileGetCurrencyBalance(uint256 id, address addr) public view returns(uint256) {}
function precompileAsyncCall(bool, uint8, address, address, address, uint, Nil.Token[] memory, bytes memory) public payable returns(bool) {}
function precompileAwaitCall(address, bytes memory) public payable returns(bytes memory, bool) {}
function precompileSendRequest(address, bytes memory, bytes memory) public payable returns(bool) {}
function precompileSendTokens(address, Nil.Token[] memory) public returns(bool) {}
function precompileGetMessageTokens() public returns(Nil.Token[] memory) {}
function precompileGetGasPrice(uint id) public returns(uint256) {}
function precompileGetPoseidonHash(bytes memory data) public returns(uint256) {}
function precompileConfigParam(bool isSet, string calldata name, bytes calldata data) public returns(bytes memory) {}
}

abstract contract NilBounceable is NilBase {
function bounce(string calldata err) virtual payable external;
contract NilConfigAbi {
function curr_validators(Nil.ParamValidators memory) public {}
function gas_price(Nil.ParamGasPrice memory) public {}
}
107 changes: 107 additions & 0 deletions NilCurrencyBase.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./Nil.sol";

/**
* @title NilCurrencyBase
* @dev Abstract contract that provides functionality for currency processing.
* Methods with "Internal" suffix are internal, which means that they can be called only from the derived contract
* itself. But there are default wrapper methods that provide the account owner access to internal methods.
* They are virtual, so the main contract can disable them by overriding them. Then only logic of the contract can use
* internal methods.
*/
abstract contract NilCurrencyBase is NilBase {
uint totalSupply;
string tokenName;

/**
* @dev Returns the total supply of the currency.
* @return The total supply of the currency.
*/
function getCurrencyTotalSupply() public view returns(uint) {
return totalSupply;
}

/**
* @dev Returns the balance of the currency owned by this contract.
* @return The balance of the currency owned by this contract.
*/
function getOwnCurrencyBalance() public view returns(uint256) {
return Nil.currencyBalance(address(this), getCurrencyId());
}

/**
* @dev Returns the unique identifier of the currency owned by this contract.
* @return The unique identifier of the currency owned by this contract.
*/
function getCurrencyId() public view returns(uint256) {
return uint256(uint160(address(this)));
}

/**
* @dev Returns the name of the currency.
* @return The name of the currency.
*/
function getCurrencyName() public view returns(string memory) {
return tokenName;
}

/**
* @dev Set the name of the currency.
* @param name The name of the currency.
*/
function setCurrencyName(string memory name) onlyExternal virtual public {
tokenName = name;
}

/**
* @dev Mints a specified amount of currency using external call.
* It is wrapper over `mintCurrencyInternal` method to provide access to the owner of the account.
* @param amount The amount of currency to mint.
*/
function mintCurrency(uint256 amount) onlyExternal virtual public {
mintCurrencyInternal(amount);
}

/**
* @dev Sends a specified amount of arbitrary currency to a given address.
* It is wrapper over `sendCurrencyInternal` method to provide access to the owner of the account.
* @param amount The amount of currency to mint.
*/
function sendCurrency(address to, uint256 currencyId, uint256 amount) onlyExternal virtual public {
sendCurrencyInternal(to, currencyId, amount);
}

/**
* @dev Mints a specified amount of currency and increases the total supply.
* All minting should be carried out using this method.
* @param amount The amount of currency to mint.
*/
function mintCurrencyInternal(uint256 amount) internal {
bool success = __Precompile__(Nil.MINT_CURRENCY).precompileMintCurrency(amount);
require(success, "Mint failed");
totalSupply += amount;
}

/**
* @dev Sends a specified amount of arbitrary currency to a given address.
* @param to The address to send the currency to.
* @param currencyId ID of the currency to send.
* @param amount The amount of currency to send.
*/
function sendCurrencyInternal(address to, uint256 currencyId, uint256 amount) internal {
Nil.Token[] memory tokens_ = new Nil.Token[](1);
tokens_[0] = Nil.Token(currencyId, amount);
Nil.asyncCall(to, address(0), address(0), 0, Nil.FORWARD_REMAINING, false, 0, tokens_, "");
}

/**
* @dev Returns the balance of the currency for a given address.
* @param account The address to check the balance for.
* @return The balance of the currency for the given address.
*/
function getCurrencyBalanceOf(address account) public view returns(uint256) {
return Nil.currencyBalance(account, getCurrencyId());
}
}

0 comments on commit ab5c206

Please sign in to comment.