Initial commit
This commit is contained in:
467
spec/lib/ethereum/blockchain_spec.rb
Normal file
467
spec/lib/ethereum/blockchain_spec.rb
Normal file
@@ -0,0 +1,467 @@
|
||||
describe Ethereum::Blockchain do
|
||||
|
||||
let(:eth) do
|
||||
Currency.find_by(id: :eth)
|
||||
end
|
||||
|
||||
let(:trst) do
|
||||
Currency.find_by(id: :trst)
|
||||
end
|
||||
|
||||
let(:ring) do
|
||||
Currency.find_by(id: :ring)
|
||||
end
|
||||
|
||||
let!(:tom) do
|
||||
create(:currency, :tom)
|
||||
end
|
||||
|
||||
let!(:address_1) { create(:whitelisted_smart_contract, :address_1, address: '0x6c0b51971650d28821ce30b15b02b9826a20b129') }
|
||||
let!(:address_2) { create(:whitelisted_smart_contract, :address_2) }
|
||||
let!(:address_3) { create(:whitelisted_smart_contract, :address_3) }
|
||||
let!(:address_4) { create(:whitelisted_smart_contract, :address_4) }
|
||||
let!(:address_5) { create(:whitelisted_smart_contract, :address_5) }
|
||||
|
||||
let(:blockchain) do
|
||||
Ethereum::Blockchain.new.tap { |b| b.configure(server: server, currencies: [eth.to_blockchain_api_settings, trst.to_blockchain_api_settings, ring.to_blockchain_api_settings, tom.to_blockchain_api_settings], whitelisted_addresses: [address_1, address_2, address_3, address_4, address_5]) }
|
||||
end
|
||||
|
||||
let(:server) { 'http://127.0.0.1:8545' }
|
||||
let(:endpoint) { 'http://127.0.0.1:8545' }
|
||||
|
||||
context :features do
|
||||
it 'defaults' do
|
||||
blockchain1 = Ethereum::Blockchain.new
|
||||
expect(blockchain1.features).to eq Ethereum::Blockchain::DEFAULT_FEATURES
|
||||
end
|
||||
|
||||
it 'override defaults' do
|
||||
blockchain2 = Ethereum::Blockchain.new(cash_addr_format: true)
|
||||
expect(blockchain2.features[:cash_addr_format]).to be_truthy
|
||||
end
|
||||
|
||||
it 'custom feautures' do
|
||||
blockchain3 = Ethereum::Blockchain.new(custom_feature: :custom)
|
||||
expect(blockchain3.features.keys).to contain_exactly(*Ethereum::Blockchain::SUPPORTED_FEATURES)
|
||||
end
|
||||
end
|
||||
|
||||
context :configure do
|
||||
let(:blockchain) { Ethereum::Blockchain.new }
|
||||
it 'default settings' do
|
||||
expect(blockchain.settings).to eq({})
|
||||
end
|
||||
|
||||
it 'currencies and server configuration' do
|
||||
currencies = Currency.where(type: :coin).first(2).map(&:to_blockchain_api_settings)
|
||||
settings = { server: server,
|
||||
currencies: currencies,
|
||||
something: :custom }
|
||||
blockchain.configure(settings)
|
||||
expect(blockchain.settings).to eq(settings.slice(*Peatio::Blockchain::Abstract::SUPPORTED_SETTINGS))
|
||||
end
|
||||
end
|
||||
|
||||
context :latest_block_number do
|
||||
around do |example|
|
||||
WebMock.disable_net_connect!
|
||||
example.run
|
||||
WebMock.allow_net_connect!
|
||||
end
|
||||
|
||||
let(:blockchain) do
|
||||
Ethereum::Blockchain.new.tap { |b| b.configure(server: server) }
|
||||
end
|
||||
|
||||
let(:method) { :eth_blockNumber }
|
||||
|
||||
it 'returns latest block number' do
|
||||
block_number = '0x16b916'
|
||||
|
||||
stub_request(:post, 'http://127.0.0.1:8545')
|
||||
.with(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :eth_blockNumber,
|
||||
params: [] }.to_json)
|
||||
.to_return(body: { result: block_number,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
|
||||
expect(blockchain.latest_block_number).to eq(block_number.to_i(16))
|
||||
end
|
||||
|
||||
it 'raises error if there is error in response body' do
|
||||
stub_request(:post, 'http://127.0.0.1:8545')
|
||||
.with(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: method,
|
||||
params: [] }.to_json)
|
||||
.to_return(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
error: { code: -32601, message: "The method #{method} does not exist/is not available" },
|
||||
id: 1 }.to_json)
|
||||
|
||||
expect{ blockchain.latest_block_number }.to raise_error(Peatio::Blockchain::ClientError)
|
||||
end
|
||||
|
||||
it 'keeps alive' do
|
||||
stub_request(:post, endpoint)
|
||||
.to_return(body: { result: '0x16b916',
|
||||
error: nil,
|
||||
id: nil }.to_json)
|
||||
.with(headers: { 'Connection': 'keep-alive',
|
||||
'Keep-Alive': '30' })
|
||||
|
||||
blockchain.latest_block_number
|
||||
end
|
||||
end
|
||||
|
||||
context :fetch_block! do
|
||||
around do |example|
|
||||
WebMock.disable_net_connect!
|
||||
example.run
|
||||
WebMock.allow_net_connect!
|
||||
end
|
||||
|
||||
let(:block_file_name) { '2621840-2621842.json' }
|
||||
|
||||
let(:block_data) do
|
||||
Rails.root.join('spec', 'resources', 'ethereum-data', 'rinkeby', block_file_name)
|
||||
.yield_self { |file_path| File.open(file_path) }
|
||||
.yield_self { |file| JSON.load(file) }
|
||||
end
|
||||
|
||||
let(:transaction_receipt_data) do
|
||||
Rails.root.join('spec', 'resources', 'ethereum-data', 'rinkeby/transaction-receipts', block_file_name)
|
||||
.yield_self { |file_path| File.open(file_path) }
|
||||
.yield_self { |file| JSON.load(file) }
|
||||
end
|
||||
|
||||
let(:start_block) { block_data.first['result']['number'].hex }
|
||||
let(:latest_block) { block_data.last['result']['number'].hex }
|
||||
|
||||
def request_block_body(block_height)
|
||||
{ jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :eth_getBlockByNumber,
|
||||
params: [block_height, true]
|
||||
}.to_json
|
||||
end
|
||||
|
||||
def request_receipt_block_body(block_hash)
|
||||
{ jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :eth_getTransactionReceipt,
|
||||
params: [block_hash]
|
||||
}.to_json
|
||||
end
|
||||
|
||||
before do
|
||||
Ethereum::Client.any_instance.stubs(:rpc_call_id).returns(1)
|
||||
block_data.each do |blk|
|
||||
# stub get_block_hash
|
||||
stub_request(:post, endpoint)
|
||||
.with(body: request_block_body(blk['result']['number']))
|
||||
.to_return(body: blk.to_json )
|
||||
end
|
||||
|
||||
transaction_receipt_data.each do |blk|
|
||||
# stub get_receipt
|
||||
stub_request(:post, endpoint)
|
||||
.with(body: request_receipt_block_body(blk['result']['transactionHash']))
|
||||
.to_return(body: blk.to_json)
|
||||
end
|
||||
end
|
||||
|
||||
context 'first block' do
|
||||
let(:expected_transactions) do
|
||||
[{:hash=>"0xb60e22c6eed3dc8cd7bc5c7e38c50aa355c55debddbff5c1c4837b995b8ee96d",
|
||||
:amount=>1.to_d,
|
||||
:to_address=>"0xe3cb6897d83691a8eb8458140a1941ce1d6e6daa",
|
||||
:from_addresses=>['0xb3ebc7b5b631e8d145f383c8cd07f0f00dd56a30'],
|
||||
:txout=>26,
|
||||
:block_number=>2621840,
|
||||
:status=>"pending",
|
||||
:currency_id=>eth.id}]
|
||||
end
|
||||
|
||||
subject { blockchain.fetch_block!(start_block) }
|
||||
|
||||
it 'builds expected number of transactions' do
|
||||
subject.transactions.each_with_index do |t, i|
|
||||
expect(t.as_json).to eq(expected_transactions[i].as_json)
|
||||
end
|
||||
end
|
||||
|
||||
it 'all transactions are valid' do
|
||||
expect(subject.all?(&:valid?)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'last block' do
|
||||
subject { blockchain.fetch_block!(latest_block) }
|
||||
let(:expected_transactions) do
|
||||
[{:hash=>"0x0338e2a59db18596afff8b7a0db3669cc231c7333064640bedf3a73c1c1c31ed",
|
||||
:amount=>18.75.to_d,
|
||||
:to_address=>"0xc4d276bf32b71cdddb18f3b4d258f057a5ffda03",
|
||||
:from_addresses=>['0x31b98d14007bdee637298086988a0bbd31184523'],
|
||||
:txout=>13,
|
||||
:block_number=>2621842,
|
||||
:status=>"pending",
|
||||
:currency_id=>eth.id},
|
||||
{:hash=>"0x826555325cec51c4d39b327e563ce3e8ee87e27be5911383f528724a62f0da5d",
|
||||
:amount=>2.to_d,
|
||||
:to_address=>"0xe3cb6897d83691a8eb8458140a1941ce1d6e6daa",
|
||||
:from_addresses=>['0x4de22dd63afb3bec965dbb734c15fba58800c923'],
|
||||
:txout=>8,
|
||||
:block_number=>2621842,
|
||||
:status=>"success",
|
||||
:currency_id=>trst.id},
|
||||
{:hash=>"0x826555325cec51c4d39b327e563ce3e8ee87e27be5911383f528724a62f0da5d",
|
||||
:amount=>2.to_d,
|
||||
:to_address=>"0x4b6a630ff1f66604d31952bdce2e4950efc99821",
|
||||
:from_addresses=>['0x4de22dd63afb3bec965dbb734c15fba58800c923'],
|
||||
:txout=>9,
|
||||
:block_number=>2621842,
|
||||
:status=>"success",
|
||||
:currency_id=>ring.id},
|
||||
{:hash=>"0xd5cc0d1d5dd35f4b57572b440fb4ef39a4ab8035657a21692d1871353bfbceea",
|
||||
:amount=>2.to_d,
|
||||
:to_address=>"0xe3cb6897d83691a8eb8458140a1941ce1d6e6dac",
|
||||
:from_addresses=>['0x4de22dd63afb3bec965dbb734c15fba58800c923'],
|
||||
:txout=>9,
|
||||
:block_number=>2621842,
|
||||
:status=>"failed",
|
||||
:currency_id=>trst.id},
|
||||
{:hash=>"0x5ab0f1a1f29da4e4ddb021c28e2383ec6bde03fb04a8e25c49a1ae5ae34b6f58",
|
||||
:amount=>0.039082.to_d,
|
||||
:to_address=>"0x40968978cf4e6b53ca161c5ba6918a926a8d5ac2",
|
||||
:from_addresses=>['0x210169700dd7131df7fc4885804a0c92c45e63f6'],
|
||||
:txout=>131,
|
||||
:block_number=>8292243,
|
||||
:status=>"pending",
|
||||
:currency_id=>eth.id},
|
||||
{:hash=>"0xeb92797eb91f53ce7bb68abaf3fd3198980d971dd42f9fcb6eb1272ef3ef2a0e",
|
||||
:to_address=>"0xbbd602bb278edff65cbc967b9b62095ad5be23a3",
|
||||
:from_addresses=>["0x095273adb73e55a8710e448c49eaee16fe115527"],
|
||||
:amount=>2436832050000.to_d,
|
||||
:currency_id=>tom.id,
|
||||
:block_number=>11684206,
|
||||
:status=>"success",
|
||||
:txout=>3}
|
||||
]
|
||||
end
|
||||
|
||||
it 'builds expected number of transactions' do
|
||||
subject.transactions.each_with_index do |t, i|
|
||||
expect(t.as_json).to eq(expected_transactions[i].as_json)
|
||||
end
|
||||
end
|
||||
|
||||
it 'all transactions are valid' do
|
||||
expect(subject.all?(&:valid?)).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context :build_transaction do
|
||||
|
||||
context :eth_transaction do
|
||||
|
||||
let(:tx_file_name) { '0xb60e22c6eed3dc8cd7bc5c7e38c50aa355c55debddbff5c1c4837b995b8ee96d.json' }
|
||||
|
||||
let(:tx_hash) do
|
||||
Rails.root.join('spec', 'resources', 'ethereum-data', 'rinkeby', 'transactions', tx_file_name)
|
||||
.yield_self { |file_path| File.open(file_path) }
|
||||
.yield_self { |file| JSON.load(file) }
|
||||
end
|
||||
let(:expected_transactions) do
|
||||
[{:hash=>"0xb60e22c6eed3dc8cd7bc5c7e38c50aa355c55debddbff5c1c4837b995b8ee96d",
|
||||
:to_address=>"0xe3cb6897d83691a8eb8458140a1941ce1d6e6daa",
|
||||
:from_addresses=>["0xb3ebc7b5b631e8d145f383c8cd07f0f00dd56a30"],
|
||||
:txout=>26,
|
||||
:amount=>1.to_d,
|
||||
:block_number=>2621840,
|
||||
:currency_id=>eth.id,
|
||||
:status=>'pending'}]
|
||||
end
|
||||
|
||||
it 'builds formatted transactions for passed transaction' do
|
||||
expect(blockchain.send(:build_transactions, tx_hash)).to contain_exactly(*expected_transactions)
|
||||
end
|
||||
end
|
||||
|
||||
context :erc20_transaction do
|
||||
|
||||
let(:tx_file_name) { '0x826555325cec51c4d39b327e563ce3e8ee87e27be5911383f528724a62f0da5d.json' }
|
||||
|
||||
let(:tx_hash) do
|
||||
Rails.root.join('spec', 'resources', 'ethereum-data', 'rinkeby', 'transactions', tx_file_name)
|
||||
.yield_self { |file_path| File.open(file_path) }
|
||||
.yield_self { |file| JSON.load(file) }
|
||||
end
|
||||
|
||||
let(:expected_transactions) do
|
||||
[{:hash=>"0x826555325cec51c4d39b327e563ce3e8ee87e27be5911383f528724a62f0da5d",
|
||||
:to_address=>"0xe3cb6897d83691a8eb8458140a1941ce1d6e6daa",
|
||||
:from_addresses=>["0x4de22dd63afb3bec965dbb734c15fba58800c923"],
|
||||
:amount=>2.to_d,
|
||||
:currency_id=>trst.id,
|
||||
:block_number=>2621842,
|
||||
:status=>"success",
|
||||
:txout=>8},
|
||||
{:hash=>"0x826555325cec51c4d39b327e563ce3e8ee87e27be5911383f528724a62f0da5d",
|
||||
:to_address=>"0x4b6a630ff1f66604d31952bdce2e4950efc99821",
|
||||
:from_addresses=>["0x4de22dd63afb3bec965dbb734c15fba58800c923"],
|
||||
:amount=>2.to_d,
|
||||
:currency_id=>ring.id,
|
||||
:block_number=>2621842,
|
||||
:status=>"success",
|
||||
:txout=>9}]
|
||||
end
|
||||
|
||||
it 'builds formatted transactions for passed transaction' do
|
||||
expect(blockchain.send(:build_transactions, tx_hash)).to contain_exactly(*expected_transactions)
|
||||
end
|
||||
|
||||
context :pending_erc20_transaction do
|
||||
let(:tx_file_name) { '0xb44861cb188356c67bec27a35abab1b7ef33fc402330faa9ac4d863ef621d7b1.json' }
|
||||
|
||||
let(:tx_hash) do
|
||||
Rails.root.join('spec', 'resources', 'ethereum-data', 'rinkeby', 'transactions', tx_file_name)
|
||||
.yield_self { |file_path| File.open(file_path) }
|
||||
.yield_self { |file| JSON.load(file) }
|
||||
end
|
||||
|
||||
let(:expected_transactions) do
|
||||
[]
|
||||
end
|
||||
|
||||
it 'builds formatted transactions for passed transaction' do
|
||||
expect(blockchain.send(:build_transactions, tx_hash)).to contain_exactly(*expected_transactions)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context :tom_whitelisted_smart_contract_transaction do
|
||||
let(:tx_file_name) { '0xeb92797eb91f53ce7bb68abaf3fd3198980d971dd42f9fcb6eb1272ef3ef2a0e.json' }
|
||||
|
||||
let(:tx_hash) do
|
||||
Rails.root.join('spec', 'resources', 'ethereum-data', 'rinkeby', 'transactions', tx_file_name)
|
||||
.yield_self { |file_path| File.open(file_path) }
|
||||
.yield_self { |file| JSON.load(file) }
|
||||
end
|
||||
|
||||
let(:expected_transactions) do
|
||||
[{:hash=>"0xeb92797eb91f53ce7bb68abaf3fd3198980d971dd42f9fcb6eb1272ef3ef2a0e",
|
||||
:to_address=>"0xbbd602bb278edff65cbc967b9b62095ad5be23a3",
|
||||
:from_addresses=>["0x095273adb73e55a8710e448c49eaee16fe115527"],
|
||||
:amount=>2436832050000.to_d,
|
||||
:currency_id=>tom.id,
|
||||
:block_number=>11684206,
|
||||
:status=>"success",
|
||||
:txout=>3}
|
||||
]
|
||||
end
|
||||
|
||||
it 'builds formatted transactions for passed transaction' do
|
||||
expect(blockchain.send(:build_transactions, tx_hash)).to contain_exactly(*expected_transactions)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context :load_balance_of_address! do
|
||||
around do |example|
|
||||
WebMock.disable_net_connect!
|
||||
example.run
|
||||
WebMock.allow_net_connect!
|
||||
end
|
||||
|
||||
let(:response1) do
|
||||
{
|
||||
jsonrpc: '2.0',
|
||||
result: "0x71a5c4e9fe8a100",
|
||||
id: 1
|
||||
}
|
||||
end
|
||||
|
||||
let(:response2) do
|
||||
{
|
||||
jsonrpc: '2.0',
|
||||
result: "0x7a120",
|
||||
id: 1
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
stub_request(:post, 'http://127.0.0.1:8545')
|
||||
.with(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :eth_getBalance,
|
||||
params:
|
||||
[
|
||||
'0x1c077de4aa6fa6fa023a9e31b8bdddeb0b44c774',
|
||||
'latest'
|
||||
] }.to_json)
|
||||
.to_return(body: response1.to_json)
|
||||
|
||||
stub_request(:post, 'http://127.0.0.1:8545')
|
||||
.with(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :eth_call,
|
||||
params:
|
||||
[
|
||||
{
|
||||
to: "0x87099add3bcc0821b5b151307c147215f839a110",
|
||||
data: "0x70a082310000000000000000000000001c077de4aa6fa6fa023a9e31b8bdddeb0b44c774"
|
||||
},
|
||||
'latest'
|
||||
] }.to_json)
|
||||
.to_return(body: response2.to_json)
|
||||
end
|
||||
|
||||
context 'get balance of eth/erc20 address' do
|
||||
it 'requests rpc eth_getBalance and get balance' do
|
||||
address = '0x1c077de4aa6fa6fa023a9e31b8bdddeb0b44c774'
|
||||
|
||||
result = blockchain.load_balance_of_address!(address, :eth)
|
||||
expect(result).to be_a(BigDecimal)
|
||||
expect(result).to eq('0.51182300042'.to_d)
|
||||
end
|
||||
|
||||
it 'requests rpc eth_call and get token balance' do
|
||||
address = '0x1c077de4aa6fa6fa023a9e31b8bdddeb0b44c774'
|
||||
|
||||
result = blockchain.load_balance_of_address!(address, :trst)
|
||||
expect(result).to be_a(BigDecimal)
|
||||
expect(result).to eq('0.5'.to_d)
|
||||
end
|
||||
|
||||
it 'raise undefined currency error' do
|
||||
expect { blockchain.load_balance_of_address!('something', :usdt).to raise(Ethereum::Blockchain::UndefinedCurrencyError) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'client error is raised' do
|
||||
before do
|
||||
stub_request(:post, 'http://127.0.0.1:8545')
|
||||
.with(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :eth_getBalance,
|
||||
params:
|
||||
[
|
||||
'anything',
|
||||
'latest'
|
||||
] }.to_json)
|
||||
.to_return(body: { jsonrpc: '2.0',
|
||||
error: { code: -32601, message: 'Method not found' },
|
||||
id: 1 }.to_json)
|
||||
end
|
||||
|
||||
it 'raise wrapped client error' do
|
||||
expect { blockchain.load_balance_of_address!('anything', :eth) }.to raise_error(Peatio::Blockchain::ClientError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
558
spec/lib/ethereum/wallet_spec.rb
Normal file
558
spec/lib/ethereum/wallet_spec.rb
Normal file
@@ -0,0 +1,558 @@
|
||||
describe Ethereum::Wallet do
|
||||
let(:wallet) { Ethereum::Wallet.new }
|
||||
|
||||
context :configure do
|
||||
let(:settings) { { wallet: {}, currency: {} } }
|
||||
it 'requires wallet' do
|
||||
expect { wallet.configure(settings.except(:wallet)) }.to raise_error(Peatio::Wallet::MissingSettingError)
|
||||
|
||||
expect { wallet.configure(settings) }.to_not raise_error
|
||||
end
|
||||
|
||||
it 'requires currency' do
|
||||
expect { wallet.configure(settings.except(:currency)) }.to raise_error(Peatio::Wallet::MissingSettingError)
|
||||
|
||||
expect { wallet.configure(settings) }.to_not raise_error
|
||||
end
|
||||
|
||||
it 'sets settings attribute' do
|
||||
wallet.configure(settings)
|
||||
expect(wallet.settings).to eq(settings.slice(*Ethereum::Wallet::SUPPORTED_SETTINGS))
|
||||
end
|
||||
end
|
||||
|
||||
context :create_address! do
|
||||
around do |example|
|
||||
WebMock.disable_net_connect!
|
||||
example.run
|
||||
WebMock.allow_net_connect!
|
||||
end
|
||||
|
||||
let(:uri) { 'http://127.0.0.1:8545' }
|
||||
let(:uri_with_path) { 'http://127.0.0.1:8545/path/extra' }
|
||||
|
||||
let(:settings) do
|
||||
{
|
||||
wallet:
|
||||
{ address: 'something',
|
||||
uri: uri },
|
||||
currency: {}
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
PasswordGenerator.stubs(:generate).returns('pass@word')
|
||||
wallet.configure(settings)
|
||||
end
|
||||
|
||||
it 'request rpc and creates new address' do
|
||||
address = '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa'
|
||||
stub_request(:post, uri)
|
||||
.with(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :personal_newAccount,
|
||||
params: ['pass@word'] }.to_json)
|
||||
.to_return(body: { jsonrpc: '2.0',
|
||||
result: address,
|
||||
id: 1 }.to_json)
|
||||
|
||||
result = wallet.create_address!(uid: 'UID123')
|
||||
expect(result.as_json.symbolize_keys).to eq(address: address, secret: 'pass@word')
|
||||
end
|
||||
|
||||
it 'works with wallet path' do
|
||||
wallet.configure({
|
||||
wallet:
|
||||
{ address: 'something',
|
||||
uri: uri_with_path },
|
||||
currency: {}
|
||||
})
|
||||
address = '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa'
|
||||
stub_request(:post, uri_with_path)
|
||||
.with(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :personal_newAccount,
|
||||
params: ['pass@word'] }.to_json)
|
||||
.to_return(body: { jsonrpc: '2.0',
|
||||
result: address,
|
||||
id: 1 }.to_json)
|
||||
|
||||
result = wallet.create_address!(uid: 'UID123')
|
||||
expect(result.as_json.symbolize_keys).to eq(address: address, secret: 'pass@word')
|
||||
end
|
||||
end
|
||||
|
||||
context :create_transaction! do
|
||||
around do |example|
|
||||
WebMock.disable_net_connect!
|
||||
example.run
|
||||
WebMock.allow_net_connect!
|
||||
end
|
||||
|
||||
let(:eth) do
|
||||
Currency.find_by(id: :eth)
|
||||
end
|
||||
|
||||
let(:trst) do
|
||||
Currency.find_by(id: :trst)
|
||||
end
|
||||
|
||||
let(:ring) do
|
||||
Currency.find_by(id: :ring)
|
||||
end
|
||||
|
||||
let(:deposit_wallet_eth) { Wallet.joins(:currencies).find_by(currencies: { id: :eth }, kind: :deposit) }
|
||||
let(:hot_wallet_eth) { Wallet.joins(:currencies).find_by(currencies: { id: :eth }, kind: :hot) }
|
||||
let(:fee_wallet) { Wallet.joins(:currencies).find_by(currencies: { id: :eth }, kind: :fee) }
|
||||
let(:deposit_wallet_trst) { Wallet.joins(:currencies).find_by(currencies: { id: :eth }, kind: :deposit) }
|
||||
let(:hot_wallet_trst) { Wallet.joins(:currencies).find_by(currencies: { id: :eth }, kind: :hot) }
|
||||
|
||||
let(:uri) { 'http://127.0.0.1:8545' }
|
||||
|
||||
let(:transaction) do
|
||||
Peatio::Transaction.new(amount: 1.1.to_d, to_address: '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa')
|
||||
end
|
||||
|
||||
context 'eth transaction with subtract fees' do
|
||||
let(:value) { 1_099_979_000_000_000_000 }
|
||||
|
||||
let(:gas_limit) { 21_000 }
|
||||
let(:gas_price) { 1_000_000_000 }
|
||||
let(:gas_price_hex) { '0x' + gas_price.to_s(16) }
|
||||
|
||||
let(:request_body) do
|
||||
{ jsonrpc: '2.0',
|
||||
id: 2,
|
||||
method: :personal_sendTransaction,
|
||||
params: [{
|
||||
from: deposit_wallet_eth.address.downcase,
|
||||
to: '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa',
|
||||
value: '0x' + (value.to_s 16),
|
||||
gas: '0x' + (gas_limit.to_s 16),
|
||||
gasPrice: gas_price_hex
|
||||
}, 'changeme'] }
|
||||
end
|
||||
|
||||
let(:eth_GasPrice) do
|
||||
{
|
||||
"jsonrpc": '2.0',
|
||||
"id": 1,
|
||||
"method": 'eth_gasPrice',
|
||||
"params": []
|
||||
}
|
||||
end
|
||||
|
||||
let(:settings) do
|
||||
{
|
||||
wallet: deposit_wallet_eth.to_wallet_api_settings,
|
||||
currency: eth.to_blockchain_api_settings
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
wallet.configure(settings)
|
||||
end
|
||||
|
||||
it 'requests rpc and sends transaction' do
|
||||
txid = '0xab6ada9608f4cebf799ee8be20fe3fb84b0d08efcdb0d962df45d6fce70cb017'
|
||||
stub_request(:post, uri)
|
||||
.with(body: eth_GasPrice.to_json)
|
||||
.to_return(body: { result: gas_price_hex,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
|
||||
stub_request(:post, uri)
|
||||
.with(body: request_body.to_json)
|
||||
.to_return(body: { result: txid,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
|
||||
result = wallet.create_transaction!(transaction, subtract_fee: true)
|
||||
expect(result.as_json.symbolize_keys).to eq(amount: 1.099979.to_s,
|
||||
currency_id: 'eth',
|
||||
to_address: '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa',
|
||||
hash: txid,
|
||||
status: 'pending',
|
||||
options: { 'gas_limit' => 21_000, 'gas_price' => 1_000_000_000, 'subtract_fee' => true })
|
||||
end
|
||||
|
||||
context 'without subtract fees' do
|
||||
let(:value) { 1_100_000_000_000_000_000 }
|
||||
|
||||
let(:request_body) do
|
||||
{ jsonrpc: '2.0',
|
||||
id: 2,
|
||||
method: :personal_sendTransaction,
|
||||
params: [{
|
||||
from: deposit_wallet_eth.address.downcase,
|
||||
to: '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa',
|
||||
value: '0x' + (value.to_s 16),
|
||||
gas: '0x' + (gas_limit.to_s 16),
|
||||
gasPrice: gas_price_hex
|
||||
}, 'changeme'] }
|
||||
end
|
||||
|
||||
it 'requests rpc and sends transaction' do
|
||||
txid = '0xab6ada9608f4cebf799ee8be20fe3fb84b0d08efcdb0d962df45d6fce70cb017'
|
||||
stub_request(:post, uri)
|
||||
.with(body: eth_GasPrice.to_json)
|
||||
.to_return(body: { result: gas_price_hex,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
|
||||
stub_request(:post, uri)
|
||||
.with(body: request_body.to_json)
|
||||
.to_return(body: { result: txid,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
|
||||
result = wallet.create_transaction!(transaction)
|
||||
expect(result.as_json.symbolize_keys).to eq(amount: 1.1.to_s,
|
||||
currency_id: 'eth',
|
||||
to_address: '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa',
|
||||
hash: txid,
|
||||
status: 'pending',
|
||||
options: { 'gas_limit' => 21_000, 'gas_price' => 1_000_000_000.0 })
|
||||
end
|
||||
end
|
||||
|
||||
context 'custom gas_price and subcstract fees' do
|
||||
let(:value) { 1_099_976_900_000_000_000 }
|
||||
|
||||
let(:gas_price) { 1_100_000_000 }
|
||||
let(:gas_mode) { :standard }
|
||||
|
||||
let(:request_body) do
|
||||
{ jsonrpc: '2.0',
|
||||
id: 2,
|
||||
method: :personal_sendTransaction,
|
||||
params: [{
|
||||
from: deposit_wallet_eth.address.downcase,
|
||||
to: '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa',
|
||||
value: '0x' + (value.to_s 16),
|
||||
gas: '0x' + (gas_limit.to_s 16),
|
||||
gasPrice: gas_price_hex
|
||||
}, 'changeme'] }
|
||||
end
|
||||
|
||||
before do
|
||||
settings[:currency][:options] = { gas_price: gas_mode }
|
||||
wallet.configure(settings)
|
||||
end
|
||||
|
||||
it do
|
||||
txid = '0xab6ada9608f4cebf799ee8be20fe3fb84b0d08efcdb0d962df45d6fce70cb017'
|
||||
stub_request(:post, uri)
|
||||
.with(body: eth_GasPrice.to_json)
|
||||
.to_return(body: { result: gas_price_hex,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
|
||||
stub_request(:post, uri)
|
||||
.with(body: request_body.to_json)
|
||||
.to_return(body: { result: txid,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
result = wallet.create_transaction!(transaction, subtract_fee: true)
|
||||
expect(result.as_json.symbolize_keys).to eq(amount: 1.0999769.to_s,
|
||||
currency_id: 'eth',
|
||||
to_address: '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa',
|
||||
hash: txid,
|
||||
status: 'pending',
|
||||
options: { 'gas_limit' => 21_000, 'gas_price' => 1_100_000_000, 'subtract_fee' => true })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'erc20 transaction' do
|
||||
let(:settings) do
|
||||
{
|
||||
wallet: deposit_wallet_trst.to_wallet_api_settings,
|
||||
currency: trst.to_blockchain_api_settings
|
||||
}
|
||||
end
|
||||
|
||||
let(:gas_price) { 1_000_000_000 }
|
||||
let(:gas_price_hex) { '0x' + gas_price.to_s(16) }
|
||||
|
||||
let(:eth_GasPrice) do
|
||||
{
|
||||
"jsonrpc": '2.0',
|
||||
"id": 1,
|
||||
"method": 'eth_gasPrice',
|
||||
"params": []
|
||||
}
|
||||
end
|
||||
|
||||
let(:request_body) do
|
||||
{ jsonrpc: '2.0',
|
||||
id: 2,
|
||||
method: :personal_sendTransaction,
|
||||
params: [{
|
||||
from: deposit_wallet_eth.address.downcase,
|
||||
to: trst.options.fetch('erc20_contract_address'),
|
||||
data: '0xa9059cbb0000000000000000000000006d6cabaa7232d7f45b143b445114f7e92350a2aa000000000000000000000000000000000000000000000000000000000010c8e0',
|
||||
gas: '0x15f90',
|
||||
gasPrice: gas_price_hex
|
||||
}, 'changeme'] }
|
||||
end
|
||||
|
||||
before do
|
||||
wallet.configure(settings)
|
||||
end
|
||||
|
||||
it do
|
||||
txid = '0xab6ada9608f4cebf799ee8be20fe3fb84b0d08efcdb0d962df45d6fce70cb017'
|
||||
stub_request(:post, uri)
|
||||
.with(body: eth_GasPrice.to_json)
|
||||
.to_return(body: { result: gas_price_hex,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
|
||||
stub_request(:post, uri)
|
||||
.with(body: request_body.to_json)
|
||||
.to_return(body: { result: txid,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
result = wallet.create_transaction!(transaction)
|
||||
expect(result.as_json.symbolize_keys).to eq(amount: 1.1.to_s,
|
||||
to_address: '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa',
|
||||
hash: txid,
|
||||
status: 'pending',
|
||||
options: { 'erc20_contract_address' => '0x87099add3bcc0821b5b151307c147215f839a110', 'gas_limit' => 90_000, 'gas_price' => 1_000_000_000 })
|
||||
end
|
||||
end
|
||||
|
||||
context :prepare_deposit_collection! do
|
||||
let(:value) { '0xa3b5840f4000' }
|
||||
|
||||
let(:gas_price) { 1_000_000_000 }
|
||||
let(:gas_price_hex) { '0x' + gas_price.to_s(16) }
|
||||
|
||||
let(:eth_GasPrice) do
|
||||
{
|
||||
"jsonrpc": '2.0',
|
||||
"id": 1,
|
||||
"method": 'eth_gasPrice',
|
||||
"params": []
|
||||
}
|
||||
end
|
||||
|
||||
let(:request_body) do
|
||||
{ jsonrpc: '2.0',
|
||||
id: 2,
|
||||
method: :personal_sendTransaction,
|
||||
params: [{
|
||||
from: fee_wallet.address.downcase,
|
||||
to: '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa',
|
||||
value: value,
|
||||
gas: '0x5208',
|
||||
gasPrice: '0x3b9aca00'
|
||||
}, 'changeme'] }
|
||||
end
|
||||
|
||||
let(:spread_deposit) do
|
||||
[{ to_address: 'fake-hot',
|
||||
amount: '2.0',
|
||||
currency_id: trst.id },
|
||||
{ to_address: 'fake-hot',
|
||||
amount: '2.0',
|
||||
currency_id: trst.id }]
|
||||
end
|
||||
|
||||
let(:settings) do
|
||||
{
|
||||
wallet: fee_wallet.to_wallet_api_settings,
|
||||
currency: eth.to_blockchain_api_settings
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
wallet.configure(settings)
|
||||
end
|
||||
|
||||
it do
|
||||
txid = '0xab6ada9608f4cebf799ee8be20fe3fb84b0d08efcdb0d962df45d6fce70cb017'
|
||||
|
||||
stub_request(:post, uri)
|
||||
.with(body: eth_GasPrice.to_json)
|
||||
.to_return(body: { result: gas_price_hex,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
|
||||
stub_request(:post, uri)
|
||||
.with(body: request_body.to_json)
|
||||
.to_return(body: { result: txid,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
result = wallet.prepare_deposit_collection!(transaction, spread_deposit, trst.to_blockchain_api_settings)
|
||||
expect(result.first.as_json.symbolize_keys).to eq(amount: '0.00018',
|
||||
currency_id: 'eth',
|
||||
to_address: '0x6d6cabaa7232d7f45b143b445114f7e92350a2aa',
|
||||
hash: txid,
|
||||
status: 'pending',
|
||||
options: {"gas_limit"=>21000, "gas_price"=>1000000000})
|
||||
end
|
||||
|
||||
context 'erc20_contract_address is not configured properly in currency' do
|
||||
it 'returns empty array' do
|
||||
currency = trst.to_blockchain_api_settings.deep_dup
|
||||
currency[:options].delete(:erc20_contract_address)
|
||||
expect(wallet.prepare_deposit_collection!(transaction, spread_deposit, currency)).to eq []
|
||||
end
|
||||
end
|
||||
|
||||
context '#calculate_gas_price' do
|
||||
let(:gas_price) { 1_000_000_000 }
|
||||
let(:gas_price_hex) { '0x' + gas_price.to_s(16) }
|
||||
|
||||
let(:settings) do
|
||||
{
|
||||
wallet: fee_wallet.to_wallet_api_settings,
|
||||
currency: eth.to_blockchain_api_settings
|
||||
}
|
||||
end
|
||||
|
||||
let(:eth_GasPrice) do
|
||||
{
|
||||
"jsonrpc": '2.0',
|
||||
"id": 1,
|
||||
"method": 'eth_gasPrice',
|
||||
"params": []
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
wallet.configure(settings)
|
||||
stub_request(:post, uri)
|
||||
.with(body: eth_GasPrice.to_json)
|
||||
.to_return(body: { result: gas_price_hex,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
end
|
||||
|
||||
it do
|
||||
options = { gas_price: 'standard' }
|
||||
expect(wallet.send(:calculate_gas_price, options)).to eq gas_price
|
||||
end
|
||||
|
||||
it do
|
||||
options = { gas_price: 'fast' }
|
||||
expect(wallet.send(:calculate_gas_price, options)).to eq gas_price * 1.1
|
||||
end
|
||||
|
||||
it do
|
||||
options = { gas_price: 'safelow' }
|
||||
expect(wallet.send(:calculate_gas_price, options)).to eq gas_price * 0.9
|
||||
end
|
||||
|
||||
it do
|
||||
options = { gas_price: 12_346_789.to_s(16) }
|
||||
expect(wallet.send(:calculate_gas_price, options)).to eq gas_price
|
||||
end
|
||||
|
||||
it do
|
||||
expect(wallet.send(:calculate_gas_price)).to eq gas_price
|
||||
end
|
||||
|
||||
it do
|
||||
expect(wallet.send(:calculate_gas_price, {})).to eq gas_price
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context :load_balance_of_address! do
|
||||
around do |example|
|
||||
WebMock.disable_net_connect!
|
||||
example.run
|
||||
WebMock.allow_net_connect!
|
||||
end
|
||||
|
||||
let(:eth) do
|
||||
Currency.find_by(id: :eth)
|
||||
end
|
||||
|
||||
let(:trst) do
|
||||
Currency.find_by(id: :trst)
|
||||
end
|
||||
|
||||
let(:hot_wallet_trst) { Wallet.joins(:currencies).find_by(currencies: { id: :trst }, kind: :hot) }
|
||||
let(:hot_wallet_eth) { Wallet.joins(:currencies).find_by(currencies: { id: :eth }, kind: :hot) }
|
||||
|
||||
let(:response1) do
|
||||
{
|
||||
jsonrpc: '2.0',
|
||||
result: '0x71a5c4e9fe8a100',
|
||||
id: 1
|
||||
}
|
||||
end
|
||||
|
||||
let(:response2) do
|
||||
{
|
||||
jsonrpc: '2.0',
|
||||
result: '0x7a120',
|
||||
id: 1
|
||||
}
|
||||
end
|
||||
|
||||
let(:settings1) do
|
||||
{
|
||||
wallet:
|
||||
{ address: 'something',
|
||||
uri: 'http://127.0.0.1:8545' },
|
||||
currency: eth.to_blockchain_api_settings
|
||||
}
|
||||
end
|
||||
|
||||
let(:settings2) do
|
||||
{
|
||||
wallet:
|
||||
{ address: 'something',
|
||||
uri: 'http://127.0.0.1:8545' },
|
||||
currency: trst.to_blockchain_api_settings
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
stub_request(:post, 'http://127.0.0.1:8545')
|
||||
.with(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :eth_getBalance,
|
||||
params:
|
||||
%w[
|
||||
something
|
||||
latest
|
||||
] }.to_json)
|
||||
.to_return(body: response1.to_json)
|
||||
|
||||
stub_request(:post, 'http://127.0.0.1:8545')
|
||||
.with(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :eth_call,
|
||||
params:
|
||||
[
|
||||
{
|
||||
to: '0x87099add3bcc0821b5b151307c147215f839a110',
|
||||
data: '0x70a082310000000000000000000000000000000000000000000000000000000something'
|
||||
},
|
||||
'latest'
|
||||
] }.to_json)
|
||||
.to_return(body: response2.to_json)
|
||||
end
|
||||
|
||||
it 'requests rpc eth_getBalance and get balance' do
|
||||
wallet.configure(settings1)
|
||||
result = wallet.load_balance!
|
||||
expect(result).to be_a(BigDecimal)
|
||||
expect(result).to eq('0.51182300042'.to_d)
|
||||
end
|
||||
|
||||
it 'requests rpc eth_call and get token balance' do
|
||||
wallet.configure(settings2)
|
||||
result = wallet.load_balance!
|
||||
expect(result).to be_a(BigDecimal)
|
||||
expect(result).to eq('0.5'.to_d)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user