Skip to content

Commit

Permalink
update contracts to 2024.10.15 release
Browse files Browse the repository at this point in the history
  • Loading branch information
Zerg1996 committed Oct 15, 2024
1 parent 285e121 commit b37f959
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 63 deletions.
43 changes: 37 additions & 6 deletions Nil.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// CurrencyId is a type that represents a unique currency identifier.
type CurrencyId is address;

using {
currencyIdEqual as ==,
currencyIdNotEqual as !=
} for CurrencyId global;

function currencyIdEqual(CurrencyId a, CurrencyId b) pure returns (bool) {
return CurrencyId.unwrap(a) == CurrencyId.unwrap(b);
}

function currencyIdNotEqual(CurrencyId a, CurrencyId b) pure returns (bool) {
return CurrencyId.unwrap(a) != CurrencyId.unwrap(b);
}

library Nil {
uint private constant SEND_MESSAGE = 0xfc;
address private constant ASYNC_CALL = address(0xfd);
Expand All @@ -15,6 +31,7 @@ library Nil {
address private constant AWAIT_CALL = address(0xd6);
address private constant CONFIG_PARAM = address(0xd7);
address private constant SEND_REQUEST = address(0xd8);
address public constant IS_RESPONSE_MESSAGE = address(0xd9);

// 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 All @@ -33,7 +50,7 @@ library Nil {

// Token is a struct that represents a token with an id and amount.
struct Token {
uint256 id;
CurrencyId id;
uint256 amount;
}

Expand Down Expand Up @@ -167,7 +184,7 @@ library Nil {
}

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

Expand Down Expand Up @@ -255,13 +272,26 @@ library Nil {

// NilBase is a base contract that provides modifiers for checking the type of message (internal or external).
contract NilBase {
// onlyInternal checks that method was invoked from internal message.
/**
* @dev Modifier to check that the method was invoked from a response message.
*/
modifier onlyResponse() {
(bool success,/* bytes memory returnData*/) = Nil.IS_RESPONSE_MESSAGE.staticcall(bytes(""));
require(success, "IS_RESPONSE_MESSAGE call failed");
_;
}

/**
* @dev Modifier to check that the method was invoked from an internal message.
*/
modifier onlyInternal() {
require(isInternalMessage(), "Trying to call internal function with external message");
_;
}

// onlyExternal checks that method was invoked from external message.
/**
* @dev Modifier to check that the method was invoked from an external message.
*/
modifier onlyExternal() {
require(!isInternalMessage(), "Trying to call external function with internal message");
_;
Expand All @@ -285,7 +315,7 @@ abstract contract NilBounceable is NilBase {
contract __Precompile__ {
// if mint flag is set to false, currency will be burned instead
function precompileManageCurrency(uint256 amount, bool mint) public returns(bool) {}
function precompileGetCurrencyBalance(uint256 id, address addr) public view returns(uint256) {}
function precompileGetCurrencyBalance(CurrencyId 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, uint, bytes memory) public payable returns(bytes memory, bool) {}
function precompileSendRequest(address, Nil.Token[] memory, uint, bytes memory, bytes memory) public payable returns(bool) {}
Expand All @@ -299,4 +329,5 @@ contract __Precompile__ {
contract NilConfigAbi {
function curr_validators(Nil.ParamValidators memory) public {}
function gas_price(Nil.ParamGasPrice memory) public {}
}
}

155 changes: 98 additions & 57 deletions NilCurrencyBase.sol
Original file line number Diff line number Diff line change
@@ -1,88 +1,129 @@
// SPDX-License-Identifier: GPL-3.0
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

pragma solidity ^0.8.9;

import "./NilCurrencyBase.sol";
import "./Nil.sol";

/**
* @title Wallet
* @dev Basic Wallet contract which provides functional for calling another contracts and sending tokens.
* It also supports multi-currency functionality providing methods for minting and sending currency.
* NilCurrencyBase class implements functional for managing own currency(where `currencyId = address(this)`).
* @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.
*/
contract Wallet is NilCurrencyBase {
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;
}

bytes pubkey;
/**
* @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 Fallback function to receive Ether.
* @dev Returns the unique identifier of the currency owned by this contract.
* @return The unique identifier of the currency owned by this contract.
*/
receive() external payable {}
function getCurrencyId() public view returns(CurrencyId) {
return CurrencyId.wrap(address(this));
}

/**
* @dev Function to handle bounce messages.
* @param err The error message.
* @dev Returns the name of the currency.
* @return The name of the currency.
*/
function bounce(string calldata err) external payable {}
function getCurrencyName() public view returns(string memory) {
return tokenName;
}

/**
* @dev Constructor to initialize the wallet with a public key.
* @param _pubkey The public key to initialize the wallet with.
* @dev Set the name of the currency.
* @param name The name of the currency.
*/
constructor(bytes memory _pubkey) payable {
pubkey = _pubkey;
function setCurrencyName(string memory name) onlyExternal virtual public {
tokenName = name;
}

/**
* @dev Sends raw message.
* @param message The raw message to send.
* @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 send(bytes calldata message) onlyExternal public {
Nil.sendMessage(message);
function mintCurrency(uint256 amount) onlyExternal virtual public {
mintCurrencyInternal(amount);
}

/**
* @dev Makes an asynchronous call.
* @param dst The destination address.
* @param refundTo The address where to send refund message.
* @param bounceTo The address where to send bounce message.
* @param feeCredit The amount of tokens available to pay all fees during message processing.
* @param deploy Whether to deploy the contract.
* @param tokens The multi-currency tokens to send.
* @param value The value to send.
* @param callData The call data of the called method.
* @dev Burns a specified amount of currency using external call.
* It is wrapper over `burnCurrencyInternal` method to provide access to the owner of the account.
* @param amount The amount of currency to burn.
*/
function asyncCall(
address dst,
address refundTo,
address bounceTo,
uint feeCredit,
bool deploy,
Nil.Token[] memory tokens,
uint value,
bytes calldata callData) onlyExternal public {
Nil.asyncCallWithTokens(dst, refundTo, bounceTo, feeCredit, Nil.FORWARD_NONE, deploy, value, tokens, callData);
function burnCurrency(uint256 amount) onlyExternal virtual public {
burnCurrencyInternal(amount);
}

/**
* @dev Makes a synchronous call, which is just a regular EVM call, without using messages.
* @param dst The destination address.
* @param feeCredit The amount of tokens available to pay all fees during message processing.
* @param value The value to send.
* @param call_data The call data of the called method.
* @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 syncCall(address dst, uint feeCredit, uint value, bytes memory call_data) onlyExternal public {
(bool success,) = dst.call{value: value, gas: feeCredit}(call_data);
require(success, "Call failed");
function sendCurrency(address to, CurrencyId currencyId, uint256 amount) onlyExternal virtual public {
sendCurrencyInternal(to, currencyId, amount);
}

/**
* @dev Verifies an external message.
* @param hash The hash of the data.
* @param signature The signature to verify.
* @return True if the signature is valid, false otherwise.
* @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 verifyExternal(uint256 hash, bytes calldata signature) external view returns (bool) {
return Nil.validateSignature(pubkey, hash, signature);
function mintCurrencyInternal(uint256 amount) internal {
bool success = __Precompile__(Nil.MANAGE_CURRENCY).precompileManageCurrency(amount, true);
require(success, "Mint failed");
totalSupply += amount;
}
}

/**
* @dev Burns a specified amount of currency and decreases the total supply.
* All burning should be carried out using this method.
* @param amount The amount of currency to mint.
*/
function burnCurrencyInternal(uint256 amount) internal {
require(totalSupply >= amount, "Burn failed: not enough tokens");
bool success = __Precompile__(Nil.MANAGE_CURRENCY).precompileManageCurrency(amount, false);
require(success, "Burn 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, CurrencyId currencyId, uint256 amount) internal {
Nil.Token[] memory tokens_ = new Nil.Token[](1);
tokens_[0] = Nil.Token(currencyId, amount);
Nil.asyncCallWithTokens(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 b37f959

Please sign in to comment.