evm_client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +26 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.travis.yml +32 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/LICENSE.txt +21 -0
- data/PREREQUISITES.md +75 -0
- data/README.md +665 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/install_parity +22 -0
- data/bin/setup +7 -0
- data/contracts/AccountingLib.sol +112 -0
- data/contracts/AuditorInterface.sol +4 -0
- data/contracts/AuditorRegistry.sol +14 -0
- data/contracts/CustodianInterface.sol +27 -0
- data/contracts/CustodianRegistry.sol +40 -0
- data/contracts/DigixConfiguration.sol +68 -0
- data/contracts/Directory.sol +67 -0
- data/contracts/DoublyLinked.sol +54 -0
- data/contracts/GenericInterface.sol +56 -0
- data/contracts/GenericRegistry.sol +15 -0
- data/contracts/Gold.sol +105 -0
- data/contracts/GoldRegistry.sol +82 -0
- data/contracts/GoldTokenLedger.sol +3 -0
- data/contracts/Interface.sol +27 -0
- data/contracts/Minter.sol +3 -0
- data/contracts/Recaster.sol +3 -0
- data/contracts/Testing.sol +59 -0
- data/contracts/VendorInterface.sol +82 -0
- data/contracts/VendorRegistry.sol +39 -0
- data/contracts/classic/Digixbot.sol +106 -0
- data/contracts/classic/DigixbotConfiguration.sol +62 -0
- data/contracts/classic/DigixbotEthereum.sol +86 -0
- data/contracts/classic/DigixbotUsers.sol +103 -0
- data/contracts/classic/Gold.sol +497 -0
- data/contracts/classic/GoldRegistry.sol +503 -0
- data/contracts/classic/GoldTokenLedger.sol +560 -0
- data/contracts/classic/GoldTokenMinter.sol +607 -0
- data/contracts/classic/ParticipantRegistry.sol +94 -0
- data/contracts/classic/QueueSample.sol +54 -0
- data/evm_client.gemspec +36 -0
- data/lib/evm_client.rb +15 -0
- data/lib/evm_client/abi.rb +32 -0
- data/lib/evm_client/client.rb +146 -0
- data/lib/evm_client/contract.rb +341 -0
- data/lib/evm_client/contract_event.rb +32 -0
- data/lib/evm_client/contract_initializer.rb +54 -0
- data/lib/evm_client/decoder.rb +99 -0
- data/lib/evm_client/deployment.rb +49 -0
- data/lib/evm_client/encoder.rb +118 -0
- data/lib/evm_client/event_log.rb +88 -0
- data/lib/evm_client/explorer_url_helper.rb +25 -0
- data/lib/evm_client/formatter.rb +146 -0
- data/lib/evm_client/function.rb +40 -0
- data/lib/evm_client/function_input.rb +14 -0
- data/lib/evm_client/function_output.rb +14 -0
- data/lib/evm_client/http_client.rb +44 -0
- data/lib/evm_client/initializer.rb +27 -0
- data/lib/evm_client/ipc_client.rb +57 -0
- data/lib/evm_client/project_initializer.rb +28 -0
- data/lib/evm_client/railtie.rb +12 -0
- data/lib/evm_client/singleton.rb +39 -0
- data/lib/evm_client/solidity.rb +40 -0
- data/lib/evm_client/transaction.rb +41 -0
- data/lib/evm_client/version.rb +3 -0
- data/lib/tasks/ethereum_contract.rake +27 -0
- data/lib/tasks/ethereum_node.rake +52 -0
- data/lib/tasks/ethereum_test.rake +32 -0
- data/lib/tasks/ethereum_transaction.rake +24 -0
- metadata +219 -0
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
import "./lib/tasks/ethereum_test.rake"
|
5
|
+
import "./lib/tasks/ethereum_node.rake"
|
6
|
+
import "./lib/tasks/ethereum_contract.rake"
|
7
|
+
import "./lib/tasks/ethereum_transaction.rake"
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
|
11
|
+
task :default => :spec
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'evm_client'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start
|
data/bin/install_parity
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
echo "Installing parity..."
|
4
|
+
sudo add-apt-repository ppa:ethereum/ethereum -y
|
5
|
+
sudo apt-get update
|
6
|
+
sudo apt-get -y install dpkg
|
7
|
+
sudo apt-get -y install libssl-dev
|
8
|
+
curl -o /usr/bin/solc -fL https://github.com/ethereum/solidity/releases/download/v0.5.16/solc-static-linux \
|
9
|
+
&& chmod 775 /usr/bin/solc \
|
10
|
+
&& chown travis:travis /usr/bin/solc
|
11
|
+
echo "Solc version"
|
12
|
+
solc --version
|
13
|
+
|
14
|
+
wget https://releases.parity.io/ethereum/v$PARITY\/x86_64-unknown-linux-gnu/parity
|
15
|
+
chmod u+x parity
|
16
|
+
chown travis:travis parity
|
17
|
+
|
18
|
+
echo "Setuping parity..."
|
19
|
+
mkdir -p ~/.local/share/io.parity.ethereum/keys/DevelopmentChain
|
20
|
+
chown -R travis:travis ~/.local/share/io.parity.ethereum
|
21
|
+
echo $devwallet > ~/.local/share/io.parity.ethereum/keys/DevelopmentChain/UTC--2017-03-31T14-19-47Z--c05e3b8b-18aa-ab4f-c5ec-09f555bf5357
|
22
|
+
echo $devpassword > ~/.devpass
|
data/bin/setup
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
// Accounting v0.1
|
2
|
+
|
3
|
+
/// @title Accounting Lib - Accounting utilities
|
4
|
+
/// @author Piper Merriam - <pipermerriam@gmail.com>
|
5
|
+
library AccountingLib {
|
6
|
+
struct Bank {
|
7
|
+
mapping (address => uint) accountBalances;
|
8
|
+
}
|
9
|
+
|
10
|
+
/// @dev Low level method for adding funds to an account. Protects against overflow.
|
11
|
+
/// @param self The Bank instance to operate on.
|
12
|
+
/// @param accountAddress The address of the account the funds should be added to.
|
13
|
+
/// @param value The amount that should be added to the account.
|
14
|
+
function addFunds(Bank storage self, address accountAddress, uint value) public {
|
15
|
+
/*
|
16
|
+
* Helper function that should be used for any addition of
|
17
|
+
* account funds. It has error checking to prevent
|
18
|
+
* overflowing the account balance.
|
19
|
+
*/
|
20
|
+
if (self.accountBalances[accountAddress] + value < self.accountBalances[accountAddress]) {
|
21
|
+
// Prevent Overflow.
|
22
|
+
throw;
|
23
|
+
}
|
24
|
+
self.accountBalances[accountAddress] += value;
|
25
|
+
}
|
26
|
+
|
27
|
+
event _Deposit(address indexed _from, address indexed accountAddress, uint value);
|
28
|
+
|
29
|
+
/// @dev Function wrapper around the _Deposit event so that it can be used by contracts. Can be used to log a deposit to an account.
|
30
|
+
/// @param _from The address that deposited the funds.
|
31
|
+
/// @param accountAddress The address of the account the funds were added to.
|
32
|
+
/// @param value The amount that was added to the account.
|
33
|
+
function Deposit(address _from, address accountAddress, uint value) public {
|
34
|
+
_Deposit(_from, accountAddress, value);
|
35
|
+
}
|
36
|
+
|
37
|
+
/// @dev Safe function for depositing funds. Returns boolean for whether the deposit was successful
|
38
|
+
/// @param self The Bank instance to operate on.
|
39
|
+
/// @param accountAddress The address of the account the funds should be added to.
|
40
|
+
/// @param value The amount that should be added to the account.
|
41
|
+
function deposit(Bank storage self, address accountAddress, uint value) public returns (bool) {
|
42
|
+
/*
|
43
|
+
* Public API for depositing funds in a specified account.
|
44
|
+
*/
|
45
|
+
if (self.accountBalances[accountAddress] + value < self.accountBalances[accountAddress]) {
|
46
|
+
return false;
|
47
|
+
}
|
48
|
+
addFunds(self, accountAddress, value);
|
49
|
+
return true;
|
50
|
+
}
|
51
|
+
|
52
|
+
event _Withdrawal(address indexed accountAddress, uint value);
|
53
|
+
|
54
|
+
/// @dev Function wrapper around the _Withdrawal event so that it can be used by contracts. Can be used to log a withdrawl from an account.
|
55
|
+
/// @param accountAddress The address of the account the funds were withdrawn from.
|
56
|
+
/// @param value The amount that was withdrawn to the account.
|
57
|
+
function Withdrawal(address accountAddress, uint value) public {
|
58
|
+
_Withdrawal(accountAddress, value);
|
59
|
+
}
|
60
|
+
|
61
|
+
event _InsufficientFunds(address indexed accountAddress, uint value, uint balance);
|
62
|
+
|
63
|
+
/// @dev Function wrapper around the _InsufficientFunds event so that it can be used by contracts. Can be used to log a failed withdrawl from an account.
|
64
|
+
/// @param accountAddress The address of the account the funds were to be withdrawn from.
|
65
|
+
/// @param value The amount that was attempted to be withdrawn from the account.
|
66
|
+
/// @param balance The current balance of the account.
|
67
|
+
function InsufficientFunds(address accountAddress, uint value, uint balance) public {
|
68
|
+
_InsufficientFunds(accountAddress, value, balance);
|
69
|
+
}
|
70
|
+
|
71
|
+
/// @dev Low level method for removing funds from an account. Protects against underflow.
|
72
|
+
/// @param self The Bank instance to operate on.
|
73
|
+
/// @param accountAddress The address of the account the funds should be deducted from.
|
74
|
+
/// @param value The amount that should be deducted from the account.
|
75
|
+
function deductFunds(Bank storage self, address accountAddress, uint value) public {
|
76
|
+
/*
|
77
|
+
* Helper function that should be used for any reduction of
|
78
|
+
* account funds. It has error checking to prevent
|
79
|
+
* underflowing the account balance which would be REALLY bad.
|
80
|
+
*/
|
81
|
+
if (value > self.accountBalances[accountAddress]) {
|
82
|
+
// Prevent Underflow.
|
83
|
+
throw;
|
84
|
+
}
|
85
|
+
self.accountBalances[accountAddress] -= value;
|
86
|
+
}
|
87
|
+
|
88
|
+
/// @dev Safe function for withdrawing funds. Returns boolean for whether the deposit was successful as well as sending the amount in ether to the account address.
|
89
|
+
/// @param self The Bank instance to operate on.
|
90
|
+
/// @param accountAddress The address of the account the funds should be withdrawn from.
|
91
|
+
/// @param value The amount that should be withdrawn from the account.
|
92
|
+
function withdraw(Bank storage self, address accountAddress, uint value) public returns (bool) {
|
93
|
+
/*
|
94
|
+
* Public API for withdrawing funds.
|
95
|
+
*/
|
96
|
+
if (self.accountBalances[accountAddress] >= value) {
|
97
|
+
deductFunds(self, accountAddress, value);
|
98
|
+
if (!accountAddress.send(value)) {
|
99
|
+
// Potentially sending money to a contract that
|
100
|
+
// has a fallback function. So instead, try
|
101
|
+
// tranferring the funds with the call api.
|
102
|
+
if (!accountAddress.call.value(value)()) {
|
103
|
+
// Revert the entire transaction. No
|
104
|
+
// need to destroy the funds.
|
105
|
+
//throw;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
return true;
|
109
|
+
}
|
110
|
+
return false;
|
111
|
+
}
|
112
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
contract AuditorRegistry {
|
2
|
+
|
3
|
+
address config;
|
4
|
+
Directory.AddressBoolMap auditors;
|
5
|
+
|
6
|
+
function CustodianRegistry(address _conf) {
|
7
|
+
config = _conf;
|
8
|
+
}
|
9
|
+
|
10
|
+
function isAuditor(address _audt) public returns (bool) {
|
11
|
+
return Directory.contains(auditors, _audt);
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import "contracts/Interface.sol";
|
2
|
+
import "contracts/Gold.sol";
|
3
|
+
import "contracts/GoldRegistry.sol";
|
4
|
+
|
5
|
+
contract CustodianInterface is Interface {
|
6
|
+
|
7
|
+
function CustodianInterface(address _config) {
|
8
|
+
owner = msg.sender;
|
9
|
+
config = _config;
|
10
|
+
}
|
11
|
+
|
12
|
+
function receiveFromVendor(address _gold, bytes32 _doc) ifemployee {
|
13
|
+
GoldRegistry(goldRegistry()).receiveFromVendor(_gold, _doc);
|
14
|
+
}
|
15
|
+
|
16
|
+
function transferCustodian(address _gold, address _cstdn) ifemployee {
|
17
|
+
}
|
18
|
+
|
19
|
+
function isRedeemable(address _gold) public returns (bool) {
|
20
|
+
return true;
|
21
|
+
}
|
22
|
+
|
23
|
+
}
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import "contracts/Directory.sol";
|
2
|
+
import "contracts/GenericRegistry.sol";
|
3
|
+
|
4
|
+
contract CustodianRegistry is GenericRegistry {
|
5
|
+
|
6
|
+
Directory.AddressBoolMap custodians;
|
7
|
+
|
8
|
+
struct Custodian {
|
9
|
+
bytes32 name;
|
10
|
+
}
|
11
|
+
|
12
|
+
mapping (address => Custodian) custodianNames;
|
13
|
+
|
14
|
+
function CustodianRegistry(address _conf) {
|
15
|
+
config = _conf;
|
16
|
+
}
|
17
|
+
|
18
|
+
function register(address _acct) ifadmin {
|
19
|
+
if (!Directory.insert(custodians, _acct))
|
20
|
+
throw;
|
21
|
+
}
|
22
|
+
|
23
|
+
function unregister(address _acct) ifadmin {
|
24
|
+
if (!Directory.remove(custodians, _acct))
|
25
|
+
throw;
|
26
|
+
}
|
27
|
+
|
28
|
+
function setCustodianName(address _cstdn, bytes32 _name) ifadmin {
|
29
|
+
custodianNames[_cstdn].name = _name;
|
30
|
+
}
|
31
|
+
|
32
|
+
function getCustodianName(address _cstdn) public returns (bytes32) {
|
33
|
+
return custodianNames[_cstdn].name;
|
34
|
+
}
|
35
|
+
|
36
|
+
function isCustodian(address _cust) public returns (bool) {
|
37
|
+
return Directory.contains(custodians, _cust);
|
38
|
+
}
|
39
|
+
|
40
|
+
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
contract DigixConfiguration {
|
2
|
+
|
3
|
+
address owner;
|
4
|
+
Directory.AddressBoolMap admins;
|
5
|
+
|
6
|
+
mapping (bytes32 => address) configaddr;
|
7
|
+
mapping (bytes32 => uint256) configint;
|
8
|
+
|
9
|
+
event SetOwner(address indexed owner, address indexed by);
|
10
|
+
event AddConfigEntryA(bytes32 indexed key, address indexed val, address indexed by);
|
11
|
+
event AddConfigEntryI(bytes32 indexed key, uint256 indexed val, address indexed by);
|
12
|
+
event RegisterAdmin(address indexed account, address indexed by);
|
13
|
+
event UnregisterAdmin(address indexed account, address indexed by);
|
14
|
+
|
15
|
+
function DigixConfiguration() {
|
16
|
+
owner = msg.sender;
|
17
|
+
}
|
18
|
+
|
19
|
+
modifier ifowner { if(msg.sender == owner) _ }
|
20
|
+
modifier ifadmin { if((msg.sender == owner) || isAdmin(msg.sender)) _ }
|
21
|
+
|
22
|
+
function getOwner() public constant returns (address) {
|
23
|
+
return owner;
|
24
|
+
}
|
25
|
+
|
26
|
+
function setOwner(address _newowner) ifowner {
|
27
|
+
address _oldaddress = owner;
|
28
|
+
owner = _newowner;
|
29
|
+
SetOwner(_newowner, msg.sender);
|
30
|
+
}
|
31
|
+
|
32
|
+
function addConfigEntryAddr(bytes32 _key, address _val) ifowner {
|
33
|
+
address _oldaddress = configaddr[_key];
|
34
|
+
configaddr[_key] = _val;
|
35
|
+
AddConfigEntryA(_key, _val, msg.sender);
|
36
|
+
}
|
37
|
+
|
38
|
+
function getConfigEntryAddr(bytes32 _key) public constant returns (address) {
|
39
|
+
return configaddr[_key];
|
40
|
+
}
|
41
|
+
|
42
|
+
function addConfigEntryInt(bytes32 _key, uint256 _val) ifowner {
|
43
|
+
uint256 _oldaddress = configint[_key];
|
44
|
+
configint[_key] = _val;
|
45
|
+
AddConfigEntryI(_key, _val, msg.sender);
|
46
|
+
}
|
47
|
+
|
48
|
+
function getConfigEntryInt(bytes32 _key) public constant returns (uint256) {
|
49
|
+
return configint[_key];
|
50
|
+
}
|
51
|
+
|
52
|
+
function registerAdmin(address _acct) ifowner {
|
53
|
+
if (!Directory.insert(admins, _acct))
|
54
|
+
throw;
|
55
|
+
RegisterAdmin(_acct, msg.sender);
|
56
|
+
}
|
57
|
+
|
58
|
+
function unregisterAdmin(address _acct) ifowner {
|
59
|
+
if (!Directory.remove(admins, _acct))
|
60
|
+
throw;
|
61
|
+
UnregisterAdmin(_acct, msg.sender);
|
62
|
+
}
|
63
|
+
|
64
|
+
function isAdmin(address _acct) public returns (bool) {
|
65
|
+
return Directory.contains(admins, _acct);
|
66
|
+
}
|
67
|
+
|
68
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
library Directory {
|
2
|
+
|
3
|
+
struct AddressBytesMap { mapping(address => bytes32) bytesentries; }
|
4
|
+
|
5
|
+
struct AddressAddressMap { mapping(address => address) addrentries; }
|
6
|
+
|
7
|
+
struct AddressBoolMap { mapping(address => bool) boolentries; }
|
8
|
+
|
9
|
+
function insert(AddressBytesMap storage self, address key, bytes32 val) returns (bool) {
|
10
|
+
if (self.bytesentries[key] == val) return false;
|
11
|
+
self.bytesentries[key] = val;
|
12
|
+
return true;
|
13
|
+
}
|
14
|
+
|
15
|
+
function insert(AddressBoolMap storage self, address key) returns (bool) {
|
16
|
+
if (self.boolentries[key]) return false;
|
17
|
+
self.boolentries[key] = true;
|
18
|
+
return true;
|
19
|
+
}
|
20
|
+
|
21
|
+
function insert(AddressAddressMap storage self, address key, address val) returns (bool) {
|
22
|
+
if (self.addrentries[key] == val) return false;
|
23
|
+
self.addrentries[key] = val;
|
24
|
+
return true;
|
25
|
+
}
|
26
|
+
|
27
|
+
function remove(AddressBytesMap storage self, address key) returns (bool) {
|
28
|
+
if (self.bytesentries[key] == 0x0) return false;
|
29
|
+
self.bytesentries[key] = 0x0;
|
30
|
+
return true;
|
31
|
+
}
|
32
|
+
|
33
|
+
function remove(AddressBoolMap storage self, address key) returns (bool) {
|
34
|
+
if (!self.boolentries[key]) return false;
|
35
|
+
self.boolentries[key] = false;
|
36
|
+
return true;
|
37
|
+
}
|
38
|
+
|
39
|
+
function remove(AddressAddressMap storage self, address key) returns (bool) {
|
40
|
+
if (self.addrentries[key] == 0x0000000000000000000000000000000000000000) return false;
|
41
|
+
self.addrentries[key] = 0x0000000000000000000000000000000000000000;
|
42
|
+
return true;
|
43
|
+
}
|
44
|
+
|
45
|
+
function contains(AddressBytesMap storage self, address key) returns (bool) {
|
46
|
+
if (self.bytesentries[key] != 0x0) return true;
|
47
|
+
}
|
48
|
+
|
49
|
+
function contains(AddressBoolMap storage self, address key) returns (bool) {
|
50
|
+
return self.boolentries[key];
|
51
|
+
}
|
52
|
+
|
53
|
+
function contains(AddressAddressMap storage self, address key) returns (bool) {
|
54
|
+
if (self.addrentries[key] != 0x0000000000000000000000000000000000000000) return true;
|
55
|
+
}
|
56
|
+
|
57
|
+
function containsAndMatches(AddressBytesMap storage self, address key, bytes32 val) returns (bool) {
|
58
|
+
return (self.bytesentries[key] == val);
|
59
|
+
}
|
60
|
+
|
61
|
+
function containsAndMatches(AddressAddressMap storage self, address key, address val) returns (bool) {
|
62
|
+
return (self.addrentries[key] == val);
|
63
|
+
}
|
64
|
+
|
65
|
+
}
|
66
|
+
|
67
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
library DoublyLinked {
|
2
|
+
|
3
|
+
struct List {
|
4
|
+
uint80 first;
|
5
|
+
uint80 last;
|
6
|
+
uint80 count;
|
7
|
+
Item[] items;
|
8
|
+
}
|
9
|
+
|
10
|
+
uint80 constant None = uint80(-1);
|
11
|
+
|
12
|
+
struct Item {
|
13
|
+
uint80 prev;
|
14
|
+
uint80 next;
|
15
|
+
bytes32 data;
|
16
|
+
}
|
17
|
+
|
18
|
+
function append(List storage self, bytes32 _data) {
|
19
|
+
var index = self.items.push(Item({prev: self.last, next: None, data: _data}));
|
20
|
+
if (self.last == None)
|
21
|
+
{
|
22
|
+
if (self.first != None || self.count != 0) throw;
|
23
|
+
self.first = self.last = uint80(index - 1);
|
24
|
+
self.count = 1;
|
25
|
+
}
|
26
|
+
else
|
27
|
+
{
|
28
|
+
self.items[self.last].next = uint80(index - 1);
|
29
|
+
self.last = uint80(index - 1);
|
30
|
+
self.count ++;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
function remove(List storage self, uint80 _index) {
|
35
|
+
Item item = self.items[_index];
|
36
|
+
if (item.prev == None)
|
37
|
+
self.first = item.next;
|
38
|
+
if (item.next == None)
|
39
|
+
self.last = item.prev;
|
40
|
+
if (item.prev != None)
|
41
|
+
self.items[item.prev].next = item.next;
|
42
|
+
if (item.next != None)
|
43
|
+
self.items[item.next].prev = item.prev;
|
44
|
+
delete self.items[_index];
|
45
|
+
self.count++;
|
46
|
+
}
|
47
|
+
|
48
|
+
// Iterator interface
|
49
|
+
function iterate_start(List storage self) returns (uint80) { return self.first; }
|
50
|
+
function iterate_valid(List storage self, uint80 _index) returns (bool) { return _index < self.items.length; }
|
51
|
+
function iterate_prev(List storage self, uint80 _index) returns (uint80) { return self.items[_index].prev; }
|
52
|
+
function iterate_next(List storage self, uint80 _index) returns (uint80) { return self.items[_index].next; }
|
53
|
+
function iterate_get(List storage self, uint80 _index) returns (bytes32) { return self.items[_index].data; }
|
54
|
+
}
|