From 368844ad2a28ec07848e3c0169cf2b83b579a2e8 Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Mon, 23 Nov 2020 20:46:35 -0500 Subject: Add native asset precompiled contracts for apricot release --- contracts/arc20.sol | 150 +++++++++++++++++++++++++++++++++++++++++++++ contracts/nativeAssets.sol | 20 ++++++ 2 files changed, 170 insertions(+) create mode 100644 contracts/arc20.sol create mode 100644 contracts/nativeAssets.sol (limited to 'contracts') diff --git a/contracts/arc20.sol b/contracts/arc20.sol new file mode 100644 index 0000000..a7fc997 --- /dev/null +++ b/contracts/arc20.sol @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +import {NativeAssets} from "./NativeAssets.sol"; + +contract ARC20 { + + mapping (address => uint256) private _balances; + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _assetID; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + uint8 private _decimals; + + constructor(string memory name_, string memory symbol_, uint8 decimals_, uint256 assetID_) public { + _name = name_; + _symbol = symbol_; + _decimals = decimals_; + _assetID = assetID_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to represent the token. + */ + function decimals() public view returns (uint8) { + return _decimals; + } + + /** + * @dev Returns the total supply of `assetID` currently held by + * this contract. + */ + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + /** + * @dev Returns the balance of `account` held in this contract. + */ + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + // Withdrawal/Deposit functionality + + /** + * @dev Acknowledges the receipt of some amount of an Avalanche Native Token + * into the contract implementing this interface. + */ + function deposit() public { + uint256 updatedBalance = NativeAssets.assetBalance(address(this), _assetID); + uint256 depositAmount = updatedBalance - _totalSupply; + assert(depositAmount >= 0); + + _balances[msg.sender] += depositAmount; + _totalSupply = updatedBalance; + emit Deposit(msg.sender, depositAmount); + } + + /** + * @dev Emitted when `value` tokens are deposited from `depositor` + */ + event Deposit(address indexed depositor, uint256 value); + + /** + * @dev Withdraws `value` of the underlying asset to the contract + * caller. + */ + function withdraw(uint256 value) public { + require(_balances[msg.sender] >= value, "Insufficient funds for withdrawal"); + + _balances[msg.sender] -= value; + _totalSupply -= value; + + NativeAssets.assetCall(msg.sender, _assetID, value, ""); + emit Withdrawal(msg.sender, value); + } + + /** + * @dev Emitted when `value` tokens are withdrawn to `withdrawer` + */ + event Withdrawal(address indexed withdrawer, uint256 value); + + /** + * @dev Returns the `assetID` of the underlying asset this contract handles. + */ + function assetID() external view returns (uint256) { + return _assetID; + } + + event Transfer(address indexed from, address indexed to, uint256 value); + + function transfer(address to, uint256 value) public returns (bool success) { + require(_balances[msg.sender] >= value, "insufficient balance for transfer"); + + _balances[msg.sender] -= value; // deduct from sender's balance + _balances[to] += value; // add to recipient's balance + emit Transfer(msg.sender, to, value); + return true; + } + + event Approval(address indexed owner, address indexed spender, uint256 value); + + function approve(address spender, uint256 value) + public + returns (bool success) + { + _allowances[msg.sender][spender] = value; + emit Approval(msg.sender, spender, value); + return true; + } + + function transferFrom(address from, address to, uint256 value) + public + returns (bool success) + { + require(value <= _balances[from], "From address has insufficient balance to transfer"); + require(value <= _allowances[from][msg.sender], "Insufficient allowance granted to sender"); + + _balances[from] -= value; + _balances[to] += value; + _allowances[from][msg.sender] -= value; + emit Transfer(from, to, value); + return true; + } + + function allowance(address owner, address spender) public view returns (uint256) { + return _allowances[owner][spender]; + } +} diff --git a/contracts/nativeAssets.sol b/contracts/nativeAssets.sol new file mode 100644 index 0000000..0656271 --- /dev/null +++ b/contracts/nativeAssets.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +library NativeAssets { + address constant balanceAddr = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF; + address constant transferAddr = 0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE; + + function assetBalance(address addr, uint256 assetID) public returns (uint256) { + (bool success, bytes memory data) = balanceAddr.call(abi.encodePacked(addr, assetID)); + require(success, "assetBalance failed"); + return abi.decode(data, (uint256)); + } + + function assetCall(address addr, uint256 assetID, uint256 assetAmount, bytes memory callData) public returns (bytes memory) { + (bool success, bytes memory data) = transferAddr.call(abi.encodePacked(addr, assetID, assetAmount, callData)); + require(success, "assetCall failed"); + return data; + } +} -- cgit v1.2.3