Skip to content

Commit

Permalink
[ETH]: Handle tuple[] ABI type parameter (#3352)
Browse files Browse the repository at this point in the history
  • Loading branch information
satoshiotomakan authored Aug 8, 2023
1 parent f28d866 commit d7b23b7
Show file tree
Hide file tree
Showing 19 changed files with 521 additions and 177 deletions.
17 changes: 15 additions & 2 deletions src/Ethereum/ABI/Array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ bool ParamArray::decode(const Data& encoded, size_t& offset_inout) {
// pad with first type
auto first = _params.getParamUnsafe(0);
for (size_t i = 0; i < len - n; i++) {
_params.addParam(ParamFactory::make(first->getType()));
_params.addParam(first->clone());
}
}

Expand All @@ -105,7 +105,7 @@ bool ParamArray::setValueJson(const std::string& value) {
}
// make sure enough elements are in the array
while (_params.getCount() < valuesJson.size()) {
addParam(ParamFactory::make(getProtoType()));
addParam(getProtoElem()->clone());
}
int cnt = 0;
for (const auto& e : valuesJson) {
Expand Down Expand Up @@ -133,6 +133,13 @@ std::string ParamArray::getExtraTypes(std::vector<std::string>& ignoreList) cons
return (proto != nullptr) ? proto->getExtraTypes(ignoreList) : "";
}

std::shared_ptr<ParamBase> ParamArray::clone() const {
auto newArray = std::make_shared<ParamArray>();
newArray->_params = _params.clone();
newArray->_proto = _proto->clone();
return newArray;
}

void ParamArrayFix::encode(Data& data) const {
this->_params.encode(data);
}
Expand All @@ -156,6 +163,12 @@ bool ParamArrayFix::setValueJson(const std::string& value) {
return true;
}

std::shared_ptr<ParamBase> ParamArrayFix::clone() const {
auto newArray = std::make_shared<ParamArrayFix>();
newArray->_params = _params.clone();
return newArray;
}

void ParamArrayFix::addParams(const Params& params) {
auto addParamFunctor = [this](auto&& param) {
if (param == nullptr) {
Expand Down
41 changes: 23 additions & 18 deletions src/Ethereum/ABI/Array.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace TW::Ethereum::ABI {
/// Dynamic array of the same types, "<type>[]"
/// Normally has at least one element. Empty array can have prototype set so its type is known.
/// Empty with no prototype is possible, but should be avoided.
class ParamArray : public ParamCollection {
class ParamArray final : public ParamCollection {
private:
ParamSet _params;
std::shared_ptr<ParamBase> _proto; // an optional prototype element, determines the array type, useful in empty array case
Expand All @@ -36,15 +36,17 @@ class ParamArray : public ParamCollection {
void addParams(const std::vector<std::shared_ptr<ParamBase>>& params);
void setProto(const std::shared_ptr<ParamBase>& proto) { _proto = proto; }
std::shared_ptr<ParamBase> getParam(int paramIndex) { return _params.getParamUnsafe(paramIndex); }
virtual std::string getType() const { return getProtoType() + "[]"; }
virtual size_t getSize() const;
virtual bool isDynamic() const { return true; }
virtual size_t getCount() const { return _params.getCount(); }
virtual void encode(Data& data) const;
virtual bool decode(const Data& encoded, size_t& offset_inout);
virtual bool setValueJson(const std::string& value);
virtual Data hashStruct() const;
virtual std::string getExtraTypes(std::vector<std::string>& ignoreList) const;

std::string getType() const override { return getProtoType() + "[]"; }
size_t getSize() const override;
bool isDynamic() const override { return true; }
size_t getCount() const override { return _params.getCount(); }
void encode(Data& data) const override;
bool decode(const Data& encoded, size_t& offset_inout) override;
bool setValueJson(const std::string& value) override;
Data hashStruct() const override;
std::string getExtraTypes(std::vector<std::string>& ignoreList) const override;
std::shared_ptr<ParamBase> clone() const override;
};

/// Fixed-size array of the same type e.g, "type[4]"
Expand All @@ -53,20 +55,23 @@ class ParamArrayFix final : public ParamCollection {
//! Public Definitions
using Params = std::vector<std::shared_ptr<ParamBase>>;

//! Public constructor
//! Public constructors
ParamArrayFix() = default;

explicit ParamArrayFix(const Params& params) noexcept(false)
: ParamCollection() {
this->addParams(params);
}

//! Public member methods
[[nodiscard]] std::size_t getCount() const final { return _params.getCount(); }
[[nodiscard]] size_t getSize() const final { return _params.getSize(); }
[[nodiscard]] bool isDynamic() const final { return false; }
[[nodiscard]] std::string getType() const final { return _params.getParamUnsafe(0)->getType() + "[" + std::to_string(_params.getCount()) + "]"; }
void encode(Data& data) const final;
bool decode(const Data& encoded, size_t& offset_inout) final;
bool setValueJson(const std::string& value) final;
[[nodiscard]] std::size_t getCount() const override { return _params.getCount(); }
[[nodiscard]] size_t getSize() const override { return _params.getSize(); }
[[nodiscard]] bool isDynamic() const override { return false; }
[[nodiscard]] std::string getType() const override { return _params.getParamUnsafe(0)->getType() + "[" + std::to_string(_params.getCount()) + "]"; }
void encode(Data& data) const override;
bool decode(const Data& encoded, size_t& offset_inout) override;
bool setValueJson(const std::string& value) override;
std::shared_ptr<ParamBase> clone() const override;

private:
//! Private member functions
Expand Down
12 changes: 12 additions & 0 deletions src/Ethereum/ABI/Bytes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ Data ParamByteArray::hashStruct() const {
return Hash::keccak256(_bytes);
}

std::shared_ptr<ParamBase> ParamByteArray::clone() const {
return std::make_shared<ParamByteArray>(_bytes);
}

void ParamByteArrayFix::setVal(const Data& val) {
if (val.size() > _n) { // crop right
_bytes = subData(val, 0, _n);
Expand Down Expand Up @@ -105,6 +109,10 @@ Data ParamByteArrayFix::hashStruct() const {
return ParamBase::hashStruct();
}

std::shared_ptr<ParamBase> ParamByteArrayFix::clone() const {
return std::make_shared<ParamByteArrayFix>(_n, _bytes);
}

void ParamString::encodeString(const std::string& decoded, Data& data) {
auto bytes = Data(decoded.begin(), decoded.end());
ParamByteArray::encodeBytes(bytes, data);
Expand All @@ -126,4 +134,8 @@ Data ParamString::hashStruct() const {
return hash;
}

std::shared_ptr<ParamBase> ParamString::clone() const {
return std::make_shared<ParamString>(_str);
}

} // namespace TW::Ethereum::ABI
59 changes: 31 additions & 28 deletions src/Ethereum/ABI/Bytes.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
namespace TW::Ethereum::ABI {

/// Dynamic array of bytes "bytes"
class ParamByteArray: public ParamCollection
class ParamByteArray final: public ParamCollection
{
private:
Data _bytes;
Expand All @@ -22,22 +22,23 @@ class ParamByteArray: public ParamCollection
ParamByteArray(const Data& val) : ParamCollection() { setVal(val); }
void setVal(const Data& val) { _bytes = val; }
const Data& getVal() const { return _bytes; }
virtual std::string getType() const { return "bytes"; };
virtual size_t getSize() const { return 32 + ValueEncoder::paddedTo32(_bytes.size()); }
virtual bool isDynamic() const { return true; }
virtual size_t getCount() const { return _bytes.size(); }
std::string getType() const override { return "bytes"; };
size_t getSize() const override { return 32 + ValueEncoder::paddedTo32(_bytes.size()); }
bool isDynamic() const override { return true; }
size_t getCount() const override { return _bytes.size(); }
static void encodeBytes(const Data& bytes, Data& data);
virtual void encode(Data& data) const { encodeBytes(_bytes, data); }
void encode(Data& data) const override { encodeBytes(_bytes, data); }
static bool decodeBytes(const Data& encoded, Data& decoded, size_t& offset_inout);
virtual bool decode(const Data& encoded, size_t& offset_inout) {
bool decode(const Data& encoded, size_t& offset_inout) override {
return decodeBytes(encoded, _bytes, offset_inout);
}
virtual bool setValueJson(const std::string& value);
virtual Data hashStruct() const;
bool setValueJson(const std::string& value) override;
Data hashStruct() const override;
std::shared_ptr<ParamBase> clone() const override;
};

/// Fixed-size array of bytes, "bytes<N>"
class ParamByteArrayFix: public ParamCollection
class ParamByteArrayFix final: public ParamCollection
{
private:
size_t _n;
Expand All @@ -47,41 +48,43 @@ class ParamByteArrayFix: public ParamCollection
ParamByteArrayFix(size_t n, const Data& val): ParamCollection(), _n(n), _bytes(Data(_n)) { setVal(val); }
void setVal(const Data& val);
const std::vector<uint8_t>& getVal() const { return _bytes; }
virtual std::string getType() const { return "bytes" + std::to_string(_n); };
virtual size_t getSize() const { return ValueEncoder::paddedTo32(_bytes.size()); }
virtual bool isDynamic() const { return false; }
virtual size_t getCount() const { return _bytes.size(); }
virtual void encode(Data& data) const;
std::string getType() const override { return "bytes" + std::to_string(_n); };
size_t getSize() const override { return ValueEncoder::paddedTo32(_bytes.size()); }
bool isDynamic() const override { return false; }
size_t getCount() const override { return _bytes.size(); }
void encode(Data& data) const override;
static bool decodeBytesFix(const Data& encoded, size_t n, Data& decoded, size_t& offset_inout);
virtual bool decode(const Data& encoded, size_t& offset_inout) {
bool decode(const Data& encoded, size_t& offset_inout) override {
return decodeBytesFix(encoded, _n, _bytes, offset_inout);
}
virtual bool setValueJson(const std::string& value);
virtual Data hashStruct() const;
bool setValueJson(const std::string& value) override;
Data hashStruct() const override;
std::shared_ptr<ParamBase> clone() const override;
};

/// Var-length string parameter
class ParamString: public ParamCollection
class ParamString final: public ParamCollection
{
private:
std::string _str;
public:
ParamString() = default;
ParamString(std::string val): ParamCollection() { setVal(val); }
ParamString(const std::string& val): ParamCollection() { setVal(val); }
void setVal(const std::string& val) { _str = val; }
const std::string& getVal() const { return _str; }
virtual std::string getType() const { return "string"; };
virtual size_t getSize() const { return 32 + ValueEncoder::paddedTo32(_str.size()); }
virtual bool isDynamic() const { return true; }
virtual size_t getCount() const { return _str.size(); }
std::string getType() const override { return "string"; };
size_t getSize() const override { return 32 + ValueEncoder::paddedTo32(_str.size()); }
bool isDynamic() const override { return true; }
size_t getCount() const override { return _str.size(); }
static void encodeString(const std::string& decoded, Data& data);
virtual void encode(Data& data) const { ParamString::encodeString(_str, data); }
void encode(Data& data) const override { ParamString::encodeString(_str, data); }
static bool decodeString(const Data& encoded, std::string& decoded, size_t& offset_inout);
virtual bool decode(const Data& encoded, size_t& offset_inout) {
bool decode(const Data& encoded, size_t& offset_inout) override {
return decodeString(encoded, _str, offset_inout);
}
virtual bool setValueJson(const std::string& value) { _str = value; return true; }
virtual Data hashStruct() const;
bool setValueJson(const std::string& value) override { _str = value; return true; }
Data hashStruct() const override;
std::shared_ptr<ParamBase> clone() const override;
};

} // namespace TW::Ethereum::ABI
8 changes: 6 additions & 2 deletions src/Ethereum/ABI/ParamAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@
namespace TW::Ethereum::ABI {

Data ParamAddress::getData() const {
Data data = store(getVal(), bytes);
Data data = store(_val.getVal(), bytes);
return data;
}

bool ParamAddress::setValueJson(const std::string& value) {
setVal(load(parse_hex(value)));
_val.setVal(load(parse_hex(value)));
return true;
}

std::shared_ptr<ParamBase> ParamAddress::clone() const {
return std::make_shared<ParamAddress>(getData());
}

} // namespace TW::Ethereum::ABI
17 changes: 12 additions & 5 deletions src/Ethereum/ABI/ParamAddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,23 @@
namespace TW::Ethereum::ABI {

/// 160-bit Address parameter, "address". Padded to the right, treated like ParamUInt160
class ParamAddress: public ParamUIntN
class ParamAddress final: public ParamBase
{
private:
ParamUIntN _val;
public:
static const size_t bytes = 20;
ParamAddress(): ParamUIntN(bytes * 8) {}
ParamAddress(const Data& val): ParamUIntN(bytes * 8, load(val)) {}
virtual std::string getType() const { return "address"; };
ParamAddress(): _val(bytes * 8) {}
explicit ParamAddress(const Data& val): _val(bytes * 8, load(val)) {}
std::string getType() const override { return "address"; };
size_t getSize() const override { return _val.getSize(); }
bool isDynamic() const override { return _val.isDynamic(); }
void encode(Data& data) const override { _val.encode(data); }
bool decode(const Data& encoded, size_t& offset_inout) override { return _val.decode(encoded, offset_inout); }
// get the value as (20-byte) byte array (as opposed to uint256_t)
Data getData() const;
virtual bool setValueJson(const std::string& value);
bool setValueJson(const std::string& value) override;
std::shared_ptr<ParamBase> clone() const override;
};

} // namespace TW::Ethereum::ABI
4 changes: 4 additions & 0 deletions src/Ethereum/ABI/ParamBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Data.h"

#include <string>
#include <memory>

namespace TW::Ethereum::ABI {

Expand All @@ -27,6 +28,9 @@ class ParamBase
virtual Data hashStruct() const;
// Helper for EIP712 encoding; provide full type of all used types (recursively). Default is empty implementation.
virtual std::string getExtraTypes([[maybe_unused]] std::vector<std::string>& ignoreList) const { return ""; }
// Creates a copy of this element.
// This method **must** be implemented in a `final` class only.
virtual std::shared_ptr<ParamBase> clone() const = 0;
};

/// Collection of parameters base class
Expand Down
Loading

0 comments on commit d7b23b7

Please sign in to comment.