-
Notifications
You must be signed in to change notification settings - Fork 819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(wallet): extend ABI decoder to support dynamic and nested types #23730
base: master
Are you sure you want to change the base?
Conversation
e0d518e
to
6b20104
Compare
explicit Type(TypeKind kind); | ||
Type(TypeKind kind, size_t m); | ||
~Type(); | ||
|
||
// Delete copy constructor and copy assignment operator | ||
Type(const Type&) = delete; | ||
Type& operator=(const Type&) = delete; | ||
|
||
// Define move constructor | ||
Type(Type&& other) noexcept; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these kinds of methods typically come first
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeBuilder Array(size_t m) { | ||
return TypeBuilder(TypeKind::kArray, m); | ||
} | ||
|
||
Type Address() { | ||
return Type{TypeKind::kAddress}; | ||
} | ||
|
||
Type UintM(size_t m) { | ||
return Type{TypeKind::kUintM, m}; | ||
} | ||
|
||
Type Uint() { | ||
return Type{TypeKind::kUintM, 256}; | ||
} | ||
|
||
Type Bool() { | ||
return Type{TypeKind::kBool}; | ||
} | ||
|
||
Type Bytes() { | ||
return Type{TypeKind::kBytes}; | ||
} | ||
|
||
Type Bytes(size_t m) { | ||
return Type{TypeKind::kBytes, m}; | ||
} | ||
|
||
Type String() { | ||
return Type{TypeKind::kString}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's CHECK(...) limits from spec where applicable
bytes<M>: binary type of M bytes, 0 < M <= 32.
uint<M>: unsigned integer type of M bits, 0 < M <= 256, M % 8 == 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeBuilder& setArrayType(Type array_type); | ||
TypeBuilder& addTupleType(Type tuple_type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SetArrayType
and
AddTupleType
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -1188,7 +1188,9 @@ void JsonRpcService::OnGetERC20TokenBalance( | |||
return; | |||
} | |||
|
|||
const auto& args = eth::DecodeEthCallResponse(*result, {"uint256"}); | |||
// (uint256) | |||
auto type = eth_abi::Tuple().addTupleType(eth_abi::UintM(256)).build(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eth_abi::Uint()
or I'd rather add Unit256()
which is the least ambiguous
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and same for two cases below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find UintM(256)
a better choice here compared to Uint()
since the actual type is uint256
, so there's less confusion.
Also is defining a Unit256()
really necessary? The idea of having UintM(<size>)
was to have less code. Btw I renamed UintM(<size>)
to Uint(<size>)
.
std::vector<std::string>{"address", // recipient | ||
"uint256"}, // amount | ||
std::vector<std::string>{decoded.value()[0].GetString(), | ||
decoded.value()[1].GetString()}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Idea for future refactor: technically we can infer
std::vector<std::string>{"address", "uint256"},
from type
std::vector<std::string>{fill_path, | ||
"", // maker asset is ETH, amount is txn value | ||
tx_args.at(1)}); | ||
decoded_calldata.value()[1].GetString()}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why these tx_args are not
decoded_calldata.value()[0].GetString(),
decoded_calldata.value()[1].GetString(),
decoded_calldata.value()[2].GetString(),
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tx_args
corresponds to the ETHSwap
transaction type. The idea is to parse the calldata using the relevant ABI but eventually format it as per the tx_args
expected by ETHSwap
.
std::vector<std::string>{"bytes", // fill path, | ||
"uint256", // maker amount | ||
"uint256"}, // taker amount | ||
std::vector<std::string>{fill_path, tx_args.at(1), tx_args.at(2)}); | ||
std::vector<std::string>{fill_path, | ||
decoded_calldata.value()[1].GetString(), | ||
decoded_calldata.value()[2].GetString()}); | ||
} else if (selector == kSellToUniswapSelector) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this doesn't match with type
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #23730 (comment)
return std::make_tuple( | ||
mojom::TransactionType::ETHSwap, | ||
std::vector<std::string>{"bytes", // fill path, | ||
"uint256", // maker amount | ||
"uint256"}, // taker amount | ||
std::vector<std::string>{tx_args.at(0) + tx_args.at(1).substr(2), | ||
tx_args.at(2), tx_args.at(3)}); | ||
std::vector<std::string>{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't match with type
at all
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw this code has not been changed. We do not pass the exact parsed calldata in order to simply the frontend integration - they just need to know how to handle ETHSwap
transactions.
// Unrecognized types are considered errors. | ||
return std::nullopt; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTREACHED_NORETURN
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
6b20104
to
1a9d2e5
Compare
[puLL-Merge] - brave/brave-core@23730 DescriptionThis PR updates the The main changes include:
ChangesChanges
Overall, this is a significant refactor that improves the robustness and flexibility of the ABI decoding code. The new type system allows decoding complex nested values which was not possible before. |
1a9d2e5
to
a997420
Compare
Resolves brave/brave-browser#38402
Improved
ABIDecode
to handle arbitrary calldata with complex types. The result is now encoded into abase::Value
to be generic. Also added a new parser for LiFi transactions, which utilises these the decoder improvements.Submitter Checklist:
QA/Yes
orQA/No
;release-notes/include
orrelease-notes/exclude
;OS/...
) to the associated issuenpm run test -- brave_browser_tests
,npm run test -- brave_unit_tests
wikinpm run presubmit
wiki,npm run gn_check
,npm run tslint
git rebase master
(if needed)Reviewer Checklist:
gn
After-merge Checklist:
changes has landed on
Test Plan:
See linked issue