You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.2 KiB
158 lines
4.2 KiB
/*
|
|
This file is part of cpp-ethereum.
|
|
|
|
cpp-ethereum is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
cpp-ethereum is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
/** @file ICAP.cpp
|
|
* @author Gav Wood <i@gavwood.com>
|
|
* @date 2014
|
|
*/
|
|
|
|
#include "ICAP.h"
|
|
#include <boost/algorithm/string/case_conv.hpp>
|
|
#include <boost/algorithm/string.hpp>
|
|
#include <libdevcore/Base64.h>
|
|
#include <libdevcrypto/SHA3.h>
|
|
#include "Exceptions.h"
|
|
#include "ABI.h"
|
|
using namespace std;
|
|
using namespace dev;
|
|
using namespace dev::eth;
|
|
|
|
namespace dev
|
|
{
|
|
namespace eth
|
|
{
|
|
|
|
string ICAP::iban(std::string _c, std::string _d)
|
|
{
|
|
boost::to_upper(_c);
|
|
boost::to_upper(_d);
|
|
auto totStr = _d + _c + "00";
|
|
bigint tot = 0;
|
|
for (char x: totStr)
|
|
if (x >= 'A')
|
|
tot = tot * 100 + x - 'A' + 10;
|
|
else
|
|
tot = tot * 10 + x - '0';
|
|
unsigned check = (unsigned)(u256)(98 - tot % 97);
|
|
ostringstream out;
|
|
out << _c << setfill('0') << setw(2) << check << _d;
|
|
return out.str();
|
|
}
|
|
|
|
std::pair<string, string> ICAP::fromIBAN(std::string _iban)
|
|
{
|
|
if (_iban.size() < 4)
|
|
return std::make_pair(string(), string());
|
|
boost::to_upper(_iban);
|
|
std::string c = _iban.substr(0, 2);
|
|
std::string d = _iban.substr(4);
|
|
if (iban(c, d) != _iban)
|
|
return std::make_pair(string(), string());
|
|
return make_pair(c, d);
|
|
}
|
|
|
|
ICAP ICAP::decoded(std::string const& _encoded)
|
|
{
|
|
ICAP ret;
|
|
std::string country;
|
|
std::string data;
|
|
std::tie(country, data) = fromIBAN(_encoded);
|
|
if (country != "XE")
|
|
throw InvalidICAP();
|
|
if (data.size() == 30)
|
|
{
|
|
ret.m_type = Direct;
|
|
// Direct ICAP
|
|
ret.m_direct = fromBase36<Address::size>(data);
|
|
}
|
|
else if (data.size() == 16)
|
|
{
|
|
ret.m_type = Indirect;
|
|
ret.m_asset = data.substr(0, 3);
|
|
if (ret.m_asset == "XET" || ret.m_asset == "ETH")
|
|
{
|
|
ret.m_institution = data.substr(3, 4);
|
|
ret.m_client = data.substr(7);
|
|
}
|
|
else
|
|
throw InvalidICAP();
|
|
}
|
|
else
|
|
throw InvalidICAP();
|
|
|
|
return ret;
|
|
}
|
|
|
|
std::string ICAP::encoded() const
|
|
{
|
|
if (m_type == Direct)
|
|
{
|
|
if (!!m_direct[0])
|
|
throw InvalidICAP();
|
|
std::string d = toBase36<Address::size>(m_direct);
|
|
while (d.size() < 30)
|
|
d = "0" + d;
|
|
return iban("XE", d);
|
|
}
|
|
else if (m_type == Indirect)
|
|
{
|
|
if (
|
|
m_asset.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos ||
|
|
m_institution.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos ||
|
|
m_client.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos ||
|
|
m_asset.size() != 3 ||
|
|
(boost::to_upper_copy(m_asset) != "XET" && boost::to_upper_copy(m_asset) != "ETH") ||
|
|
m_institution.size() != 4 ||
|
|
m_client.size() != 9
|
|
)
|
|
throw InvalidICAP();
|
|
return iban("XE", m_asset + m_institution + m_client);
|
|
}
|
|
else
|
|
throw InvalidICAP();
|
|
}
|
|
|
|
pair<Address, bytes> ICAP::lookup(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const
|
|
{
|
|
auto resolve = [&](string const& s)
|
|
{
|
|
vector<string> ss;
|
|
boost::algorithm::split(ss, s, boost::is_any_of("/"));
|
|
Address r = _reg;
|
|
for (unsigned i = 0; i < ss.size() - 1; ++i)
|
|
r = abiOut<Address>(_call(r, abiIn("subRegistrar(bytes32)", toString32(ss[i]))));
|
|
return abiOut<Address>(_call(r, abiIn("addr(bytes32)", toString32(ss.back()))));
|
|
};
|
|
if (m_asset == "XET")
|
|
{
|
|
Address a = resolve(m_institution);
|
|
bytes d = abiIn("deposit(uint64)", fromBase36<8>(m_client));
|
|
return make_pair(a, d);
|
|
}
|
|
else if (m_asset == "ETH")
|
|
{
|
|
if (m_institution == "XREG")
|
|
return make_pair(resolve(m_client), bytes());
|
|
else if (m_institution[0] != 'X')
|
|
return make_pair(resolve(m_institution + "/" + m_client), bytes());
|
|
else
|
|
throw InterfaceNotSupported("ICAP::lookup(), bad institution");
|
|
}
|
|
throw InterfaceNotSupported("ICAP::lookup(), bad asset");
|
|
}
|
|
|
|
}
|
|
}
|
|
|