Transaction Hash:
Block:
9118198 at Dec-17-2019 01:02:43 AM +UTC
Transaction Fee:
0.0005949735 ETH
$1.23
Gas Used:
108,177 Gas / 5.5 Gwei
Emitted Events:
| 91 |
ERC20Proxy.Transfer( _from=0x0000000000000000000000000000000000000000, _to=0xc271b6CF4A9C8e30c2f42E32E59902E9d0Db5C1A, _value=1200000000 )
|
| 92 |
0x631e223441dada8a86193e67efc4c13e03070c32.0xed5574191550f9863d8d776ecd6b661f161177759ee9d2c39b0e73513782f23a( 0xed5574191550f9863d8d776ecd6b661f161177759ee9d2c39b0e73513782f23a, 00000000000000000000000000000000000000000000000000000000000003e8, d7d4633584d5f490db3596215ae036d0284c77886b2f34631e091a81e88ae320, 0000000000000000000000000ee9a2fa8937ae24c1e4eb5ca52b4454a293ca4b, 0000000000000000000000000000000000000000000000000000000047868c00, 0000000000000000000000000000000000000000000000000000000000000001 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x0E1518eC...4092095a0 | |||||
| 0x631e2234...E03070C32 | |||||
|
0x7B0b579B...2a7A44A24
Miner
| 18.496246137125061427 Eth | 18.496841110625061427 Eth | 0.0005949735 | ||
| 0x7f2F51A5...17c3a6eb9 |
0.785590102743536632 Eth
Nonce: 10246
|
0.784995129243536632 Eth
Nonce: 10247
| 0.0005949735 |
Execution Trace
0x631e223441dada8a86193e67efc4c13e03070c32.8fb72ec5( )
-
Null: 0x000...001.cfaa5875( ) -
0x0e1518ec6058d93fcefd6c971b609a34092095a0.CALL( ) -
0x0e1518ec6058d93fcefd6c971b609a34092095a0.f7ea7a3d( ) -
0x0e1518ec6058d93fcefd6c971b609a34092095a0.CALL( ) -
ERC20Proxy.emitTransfer( _from=0x0000000000000000000000000000000000000000, _to=0xc271b6CF4A9C8e30c2f42E32E59902E9d0Db5C1A, _value=1200000000 )
-
0x0e1518ec6058d93fcefd6c971b609a34092095a0.CALL( ) -
0x0e1518ec6058d93fcefd6c971b609a34092095a0.21e5383a( )
pragma solidity ^0.4.21;
contract LockRequestable {
uint256 public lockRequestCount;
function LockRequestable() public {
lockRequestCount = 0;
}
function generateLockId() internal returns (bytes32 lockId) {
return keccak256(block.blockhash(block.number - 1), address(this), ++lockRequestCount);
}
}
contract CustodianUpgradeable is LockRequestable {
struct CustodianChangeRequest {
address proposedNew;
}
address public custodian;
mapping(bytes32 => CustodianChangeRequest) public custodianChangeReqs;
function CustodianUpgradeable(
address _custodian
)
LockRequestable()
public
{
custodian = _custodian;
}
modifier onlyCustodian {
require(msg.sender == custodian);
_;
}
function requestCustodianChange(address _proposedCustodian) public returns (bytes32 lockId) {
require(_proposedCustodian != address(0));
lockId = generateLockId();
custodianChangeReqs[lockId] = CustodianChangeRequest({
proposedNew : _proposedCustodian
});
emit CustodianChangeRequested(lockId, msg.sender, _proposedCustodian);
}
function confirmCustodianChange(bytes32 _lockId) public onlyCustodian {
custodian = getCustodianChangeReq(_lockId);
delete custodianChangeReqs[_lockId];
emit CustodianChangeConfirmed(_lockId, custodian);
}
function getCustodianChangeReq(bytes32 _lockId) private view returns (address _proposedNew) {
CustodianChangeRequest storage changeRequest = custodianChangeReqs[_lockId];
require(changeRequest.proposedNew != 0);
return changeRequest.proposedNew;
}
event CustodianChangeRequested(
bytes32 _lockId,
address _msgSender,
address _proposedCustodian
);
event CustodianChangeConfirmed(bytes32 _lockId, address _newCustodian);
}
contract ERC20ImplUpgradeable is CustodianUpgradeable {
struct ImplChangeRequest {
address proposedNew;
}
ERC20Impl public erc20Impl;
mapping(bytes32 => ImplChangeRequest) public implChangeReqs;
function ERC20ImplUpgradeable(address _custodian) CustodianUpgradeable(_custodian) public {
erc20Impl = ERC20Impl(0x0);
}
modifier onlyImpl {
require(msg.sender == address(erc20Impl));
_;
}
function requestImplChange(address _proposedImpl) public returns (bytes32 lockId) {
require(_proposedImpl != address(0));
lockId = generateLockId();
implChangeReqs[lockId] = ImplChangeRequest({
proposedNew : _proposedImpl
});
emit ImplChangeRequested(lockId, msg.sender, _proposedImpl);
}
function confirmImplChange(bytes32 _lockId) public onlyCustodian {
erc20Impl = getImplChangeReq(_lockId);
delete implChangeReqs[_lockId];
emit ImplChangeConfirmed(_lockId, address(erc20Impl));
}
function getImplChangeReq(bytes32 _lockId) private view returns (ERC20Impl _proposedNew) {
ImplChangeRequest storage changeRequest = implChangeReqs[_lockId];
require(changeRequest.proposedNew != address(0));
return ERC20Impl(changeRequest.proposedNew);
}
event ImplChangeRequested(
bytes32 _lockId,
address _msgSender,
address _proposedImpl
);
event ImplChangeConfirmed(bytes32 _lockId, address _newImpl);
}
contract NianLunServiceUpgradeable is CustodianUpgradeable {
struct NianLunServiceChangeRequest {
address proposedNew;
}
NianLunService public nianLunService;
mapping(bytes32 => NianLunServiceChangeRequest) public nianLunServiceChangeReqs;
function NianLunServiceUpgradeable(address _custodian) CustodianUpgradeable(_custodian) public {
nianLunService = NianLunService(0x0);
}
modifier onlyNianLunService {
require(msg.sender == address(nianLunService));
_;
}
function requestNianLunServiceChange(address _proposedNianLunService) public returns (bytes32 lockId) {
require(_proposedNianLunService != address(0));
lockId = generateLockId();
nianLunServiceChangeReqs[lockId] = NianLunServiceChangeRequest({
proposedNew : _proposedNianLunService
});
emit NianLunServiceChangeRequested(lockId, msg.sender, _proposedNianLunService);
}
function confirmNianLunServiceChange(bytes32 _lockId) public onlyCustodian {
nianLunService = getNianLunServiceChangeReq(_lockId);
delete nianLunServiceChangeReqs[_lockId];
emit NianLunServiceChangeConfirmed(_lockId, address(nianLunService));
}
function getNianLunServiceChangeReq(bytes32 _lockId) private view returns (NianLunService _proposedNew) {
NianLunServiceChangeRequest storage changeRequest = nianLunServiceChangeReqs[_lockId];
require(changeRequest.proposedNew != address(0));
return NianLunService(changeRequest.proposedNew);
}
event NianLunServiceChangeRequested(
bytes32 _lockId,
address _msgSender,
address _proposedNianLunService
);
event NianLunServiceChangeConfirmed(bytes32 _lockId, address _newNianLunService);
}
contract ERC20Interface {
// METHODS
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#totalsupply
function totalSupply() public view returns (uint256);
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#balanceof
function balanceOf(address _owner) public view returns (uint256 balance);
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer
function transfer(address _to, uint256 _value) public returns (bool success);
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transferfrom
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approve
function approve(address _spender, uint256 _value) public returns (bool success);
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#allowance
function allowance(address _owner, address _spender) public view returns (uint256 remaining);
// EVENTS
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer-1
event Transfer(address indexed _from, address indexed _to, uint256 _value);
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approval
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
contract ERC20Proxy is ERC20Interface, ERC20ImplUpgradeable, NianLunServiceUpgradeable {
string public name;
string public symbol;
uint8 public decimals;
function ERC20Proxy(
string _name,
string _symbol,
uint8 _decimals,
address _custodian
)
ERC20ImplUpgradeable(_custodian) NianLunServiceUpgradeable(_custodian)
public
{
name = _name;
symbol = _symbol;
decimals = _decimals;
}
modifier onlyPermitted() {
require(
msg.sender == address(nianLunService) ||
msg.sender == address(erc20Impl)
);
_;
}
function totalSupply() public view returns (uint256) {
return erc20Impl.totalSupply();
}
function balanceOf(address _owner) public view returns (uint256 balance) {
return erc20Impl.balanceOf(_owner);
}
function emitTransfer(address _from, address _to, uint256 _value) public onlyPermitted {
emit Transfer(_from, _to, _value);
}
function transfer(address _to, uint256 _value) public returns (bool success) {
return erc20Impl.transferWithSender(msg.sender, _to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
return erc20Impl.transferFromWithSender(msg.sender, _from, _to, _value);
}
function emitApproval(address _owner, address _spender, uint256 _value) public onlyImpl {
emit Approval(_owner, _spender, _value);
}
function approve(address _spender, uint256 _value) public returns (bool success) {
return erc20Impl.approveWithSender(msg.sender, _spender, _value);
}
function increaseApproval(address _spender, uint256 _addedValue) public returns (bool success) {
return erc20Impl.increaseApprovalWithSender(msg.sender, _spender, _addedValue);
}
function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool success) {
return erc20Impl.decreaseApprovalWithSender(msg.sender, _spender, _subtractedValue);
}
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return erc20Impl.allowance(_owner, _spender);
}
}
contract ERC20Impl {
ERC20Proxy public erc20Proxy;
ERC20Store public erc20Store;
function ERC20Impl(
address _erc20Proxy,
address _erc20Store
)
public
{
erc20Proxy = ERC20Proxy(_erc20Proxy);
erc20Store = ERC20Store(_erc20Store);
}
modifier onlyProxy {
require(msg.sender == address(erc20Proxy));
_;
}
modifier onlyPayloadSize(uint size) {
assert(msg.data.length == size + 4);
_;
}
function approveWithSender(
address _sender,
address _spender,
uint256 _value
)
public
onlyProxy
returns (bool success)
{
require(_spender != address(0));
// disallow unspendable approvals
erc20Store.setAllowance(_sender, _spender, _value);
erc20Proxy.emitApproval(_sender, _spender, _value);
return true;
}
function increaseApprovalWithSender(
address _sender,
address _spender,
uint256 _addedValue
)
public
onlyProxy
returns (bool success)
{
require(_spender != address(0));
// disallow unspendable approvals
uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
uint256 newAllowance = currentAllowance + _addedValue;
require(newAllowance >= currentAllowance);
erc20Store.setAllowance(_sender, _spender, newAllowance);
erc20Proxy.emitApproval(_sender, _spender, newAllowance);
return true;
}
function decreaseApprovalWithSender(
address _sender,
address _spender,
uint256 _subtractedValue
)
public
onlyProxy
returns (bool success)
{
require(_spender != address(0));
// disallow unspendable approvals
uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
uint256 newAllowance = currentAllowance - _subtractedValue;
require(newAllowance <= currentAllowance);
erc20Store.setAllowance(_sender, _spender, newAllowance);
erc20Proxy.emitApproval(_sender, _spender, newAllowance);
return true;
}
function transferFromWithSender(
address _sender,
address _from,
address _to,
uint256 _value
)
public
onlyProxy onlyPayloadSize(4 * 32)
returns (bool success)
{
require(_to != address(0));
uint256 balanceOfFrom = erc20Store.balances(_from);
require(_value <= balanceOfFrom);
uint256 senderAllowance = erc20Store.allowed(_from, _sender);
require(_value <= senderAllowance);
erc20Store.setBalance(_from, balanceOfFrom - _value);
erc20Store.addBalance(_to, _value);
erc20Store.setAllowance(_from, _sender, senderAllowance - _value);
erc20Proxy.emitTransfer(_from, _to, _value);
return true;
}
function transferWithSender(
address _sender,
address _to,
uint256 _value
)
public onlyProxy onlyPayloadSize(3 * 32)
returns (bool success)
{
require(_to != address(0));
uint256 balanceOfSender = erc20Store.balances(_sender);
require(_value <= balanceOfSender);
erc20Store.setBalance(_sender, balanceOfSender - _value);
erc20Store.addBalance(_to, _value);
erc20Proxy.emitTransfer(_sender, _to, _value);
return true;
}
function totalSupply() public view returns (uint256) {
return erc20Store.totalSupply();
}
function balanceOf(address _owner) public view returns (uint256 balance) {
return erc20Store.balances(_owner);
}
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return erc20Store.allowed(_owner, _spender);
}
}
contract ERC20Store is ERC20ImplUpgradeable, NianLunServiceUpgradeable {
uint256 public totalSupply;
uint256 public createDate;
address public foundation;
address public team;
address public partner;
address public transit;
mapping(address => uint256) public balances;
mapping(address => mapping(address => uint256)) public allowed;
mapping(address => uint256) public availableMap;
function ERC20Store(address _custodian, address _foundation, address _team, address _partner, address _transit)
ERC20ImplUpgradeable(_custodian) NianLunServiceUpgradeable(_custodian)
public
{
createDate = now;
foundation = _foundation;
partner = _partner;
team = _team;
transit = _transit;
availableMap[foundation] = 15120000000000000;
availableMap[partner] = 3360000000000000;
availableMap[team] = 2520000000000000;
}
modifier onlyPermitted
{
require(
msg.sender == address(nianLunService) ||
msg.sender == address(erc20Impl)
);
_;
}
function setTotalSupply(uint256 _newTotalSupply)
public onlyPermitted
{
totalSupply = _newTotalSupply;
}
function setAllowance(address _owner, address _spender, uint256 _value)
public onlyImpl
{
allowed[_owner][_spender] = _value;
}
function setBalance(address _owner, uint256 _newBalance)
public onlyPermitted
{
balances[_owner] = _newBalance;
}
function addBalance(address _owner, uint256 _balanceIncrease)
public onlyPermitted
{
balances[_owner] = balances[_owner] + _balanceIncrease;
}
function reduceAvailable(address _owner, uint256 _value)
public onlyNianLunService
{
availableMap[_owner] = availableMap[_owner] - _value;
}
}
contract NianLunService is LockRequestable, CustodianUpgradeable {
struct PendingService {
address sender;
uint256 value;
bool isPrint;
}
ERC20Proxy public erc20Proxy;
ERC20Store public erc20Store;
mapping(address => bool) public primaryBank;
mapping(bytes32 => PendingService) public pendingServiceMap;
function NianLunService(address _erc20Proxy, address _erc20Store, address _custodian)
CustodianUpgradeable(_custodian)
public
{
erc20Proxy = ERC20Proxy(_erc20Proxy);
erc20Store = ERC20Store(_erc20Store);
}
modifier onlyPrimary
{
require(primaryBank[address(msg.sender)]);
_;
}
modifier onlyPayloadSize(uint size) {
assert(msg.data.length == size + 4);
_;
}
function addPrimary(address _newPrimary)
public onlyCustodian
{
primaryBank[_newPrimary] = true;
emit PrimaryChanged(_newPrimary, true);
}
function removePrimary(address _removePrimary)
public onlyCustodian
{
delete primaryBank[_removePrimary];
emit PrimaryChanged(_removePrimary, false);
}
function authTransfer(address _from, address _to, uint256 _value)
public onlyPrimary onlyPayloadSize(3 * 32)
returns (bool success)
{
require(_to != address(0));
uint256 balanceOfFrom = erc20Store.balances(_from);
require(_value <= balanceOfFrom);
erc20Store.setBalance(_from, balanceOfFrom - _value);
erc20Store.addBalance(_to, _value);
erc20Proxy.emitTransfer(_from, _to, _value);
return true;
}
function batchPublishService(address[] _senders, uint256[] _values, bool[] _isPrints)
public onlyPrimary
returns (bool success)
{
require(_senders.length == _values.length);
require(_isPrints.length == _values.length);
uint256 numPublish = _senders.length;
for (uint256 i = 0; i < numPublish; i++) {
publishService(_senders[i], _values[i], _isPrints[i]);
}
return true;
}
function publishService(address _sender, uint256 _value, bool _isPrint)
public onlyPrimary onlyPayloadSize(3 * 32)
{
require(_sender != address(0));
bytes32 lockId = generateLockId();
pendingServiceMap[lockId] = PendingService({
sender : _sender,
value : _value,
isPrint : _isPrint
});
if (_isPrint) {
// print value to transit;
erc20Store.setTotalSupply(erc20Store.totalSupply() + _value);
erc20Proxy.emitTransfer(address(0), erc20Store.transit(), _value);
} else {
// transfer value from sender to transit
uint256 balanceOfSender = erc20Store.balances(_sender);
if (_value > balanceOfSender) {
delete pendingServiceMap[lockId];
emit ServicePublished(lockId, _sender, _value, false);
return;
}
erc20Store.setBalance(_sender, balanceOfSender - _value);
erc20Proxy.emitTransfer(_sender, erc20Store.transit(), _value);
}
erc20Store.addBalance(erc20Store.transit(), _value);
emit ServicePublished(lockId, _sender, _value, true);
}
function batchConfirmService(bytes32[] _lockIds, uint256[] _values, address[] _tos)
public onlyPrimary
returns (bool result)
{
require(_lockIds.length == _values.length);
require(_lockIds.length == _tos.length);
uint256 numConfirms = _lockIds.length;
for (uint256 i = 0; i < numConfirms; i++) {
confirmService(_lockIds[i], _values[i], _tos[i]);
}
return true;
}
function confirmService(bytes32 _lockId, uint256 _value, address _to)
public onlyPrimary
{
PendingService storage service = pendingServiceMap[_lockId];
address _sender = service.sender;
uint256 _availableValue = service.value;
bool _isPrint = service.isPrint;
if (_value > _availableValue) {
emit ServiceConfirmed(_lockId, _sender, _to, _value, false);
return;
}
uint256 _restValue = _availableValue - _value;
if (_restValue == 0) {
delete pendingServiceMap[_lockId];
} else {
service.value = _restValue;
}
if (_isPrint) {
releaseFoundation(_value);
}
uint256 balanceOfTransit = erc20Store.balances(erc20Store.transit());
erc20Store.setBalance(erc20Store.transit(), balanceOfTransit - _value);
erc20Store.addBalance(_to, _value);
erc20Proxy.emitTransfer(erc20Store.transit(), _to, _value);
emit ServiceConfirmed(_lockId, _sender, _to, _value, true);
}
function releaseFoundation(uint256 _value)
private
{
uint256 foundationAvailable = erc20Store.availableMap(erc20Store.foundation());
if (foundationAvailable <= 0) {
return;
}
if (foundationAvailable < _value) {
_value = foundationAvailable;
}
erc20Store.addBalance(erc20Store.foundation(), _value);
erc20Store.setTotalSupply(erc20Store.totalSupply() + _value);
erc20Store.reduceAvailable(erc20Store.foundation(), _value);
erc20Proxy.emitTransfer(address(0), erc20Store.foundation(), _value);
}
function batchCancelService(bytes32[] _lockIds)
public onlyPrimary
returns (bool result)
{
uint256 numCancels = _lockIds.length;
for (uint256 i = 0; i < numCancels; i++) {
cancelService(_lockIds[i]);
}
return true;
}
function cancelService(bytes32 _lockId)
public onlyPrimary
{
PendingService storage service = pendingServiceMap[_lockId];
address _sender = service.sender;
uint256 _value = service.value;
bool _isPrint = service.isPrint;
delete pendingServiceMap[_lockId];
if (_isPrint) {
// burn
erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);
erc20Proxy.emitTransfer(erc20Store.transit(), address(0), _value);
} else {
// send back
erc20Store.addBalance(_sender, _value);
erc20Proxy.emitTransfer(erc20Store.transit(), _sender, _value);
}
uint256 balanceOfTransit = erc20Store.balances(erc20Store.transit());
erc20Store.setBalance(erc20Store.transit(), balanceOfTransit - _value);
emit ServiceCanceled(_lockId, _sender, _value);
}
function queryService(bytes32 _lockId)
public view
returns (address _sender, uint256 _value, bool _isPrint)
{
PendingService storage service = pendingServiceMap[_lockId];
_sender = service.sender;
_value = service.value;
_isPrint = service.isPrint;
}
function releaseTeam()
public
returns (bool success)
{
uint256 teamAvailable = erc20Store.availableMap(erc20Store.team());
if (teamAvailable > 0 && now > erc20Store.createDate() + 3 * 1 years) {
erc20Store.addBalance(erc20Store.team(), teamAvailable);
erc20Store.setTotalSupply(erc20Store.totalSupply() + teamAvailable);
erc20Store.reduceAvailable(erc20Store.team(), teamAvailable);
erc20Proxy.emitTransfer(address(0), erc20Store.team(), teamAvailable);
return true;
}
return false;
}
function releasePartner()
public
returns (bool success)
{
uint256 partnerAvailable = erc20Store.availableMap(erc20Store.partner());
if (partnerAvailable > 0) {
erc20Store.addBalance(erc20Store.partner(), partnerAvailable);
erc20Store.setTotalSupply(erc20Store.totalSupply() + partnerAvailable);
erc20Store.reduceAvailable(erc20Store.partner(), partnerAvailable);
erc20Proxy.emitTransfer(address(0), erc20Store.partner(), partnerAvailable);
return true;
}
return false;
}
event ServicePublished(bytes32 _lockId, address _sender, uint256 _value, bool _result);
event ServiceConfirmed(bytes32 _lockId, address _sender, address _to, uint256 _value, bool _result);
event ServiceCanceled(bytes32 _lockId, address _sender, uint256 _value);
event PrimaryChanged(address _primary, bool opt);
}