Created
July 4, 2024 06:56
-
-
Save marcovc/582d5368dd1476ccddc3c5729450a9f0 to your computer and use it in GitHub Desktop.
Encoding cow amm (in c++)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ExecFMAMMOrder::EncodingData ExecFMAMMOrder::compute_encoding_data( | |
std::chrono::system_clock::time_point const& valid_to | |
) const | |
{ | |
using ABI = EthereumABIEncoding; | |
auto owner = order().fm_amm().id(); | |
auto valid_to_seconds = std::chrono::duration_cast<std::chrono::seconds>(valid_to.time_since_epoch()).count(); | |
auto encoding_parameters = order().fm_amm().encoding_parameters(); | |
auto app_data_bytes = ABI::hex_string_as_bytes32(encoding_parameters.at("app_data").get<std::string>()); | |
auto order_kind_bytes = ABI::hex_string_as_bytes32("0xf3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775"); // sell order | |
auto erc_token_balance_bytes = ABI::hex_string_as_bytes32("0x5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9"); // erc20 | |
auto order = ABI::from_tuple({ | |
ABI::from_address(sell_token().name()), | |
ABI::from_address(buy_token().name()), | |
ABI::from_address("0x0000000000000000000000000000000000000000"), // means the receiver=sender | |
ABI::from_uint(sell_amount_after_fees().convert_to<BigInt>()), | |
ABI::from_uint(min_buy_amount_after_fees().convert_to<BigInt>()), | |
ABI::from_uint(valid_to_seconds), | |
ABI::from_static_bytes(app_data_bytes), | |
ABI::from_uint(0), // order fee != executed order fee. Like limit orders, order fee is 0 meaning the solvers choose them | |
ABI::from_static_bytes(order_kind_bytes), // sell order | |
ABI::from_uint(0), | |
ABI::from_static_bytes(erc_token_balance_bytes), // erc20 | |
ABI::from_static_bytes(erc_token_balance_bytes) // erc20 | |
}); | |
auto handler = encoding_parameters.at("handler").get<std::string>(); | |
auto salt = encoding_parameters.at("salt").get<std::string>(); | |
auto static_input = encoding_parameters.at("static_input").get<std::string>(); | |
auto params = ABI::from_tuple({ | |
ABI::from_address(handler), | |
ABI::from_static_bytes(ABI::hex_string_as_bytes32(salt)), | |
ABI::from_dynamic_bytes(ABI::hex_string_as_bytes(static_input)) | |
}); | |
// See https://newworkspace-nmq6115.slack.com/archives/C0690QX4R5X/p1719998847351919?thread_ts=1719040615.437539&cid=C0690QX4R5X. | |
auto payload_struct = ABI::from_tuple({ | |
ABI::from_tuple( | |
{ | |
ABI::from_dynamic_array({}), // proof | |
params, | |
ABI::from_dynamic_bytes({}) // offchainInput | |
} | |
)} | |
); | |
auto type_hash = ABI::hex_string_as_bytes32("0xd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e489"); | |
auto separator = ABI::hex_string_as_bytes32("0xc078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943"); | |
// As Martin explained https://newworkspace-nmq6115.slack.com/archives/C0690QX4R5X/p1718820504910619?thread_ts=1718818633.608049&cid=C0690QX4R5X | |
// the docs are wrong in the sense that the owner needs to be prepended in the signature: | |
auto signature_as_in_docs = ABI::to_calldata_bytes("safeSignature(bytes32,bytes32,bytes,bytes)", { | |
ABI::from_static_bytes(separator), // separator | |
ABI::from_static_bytes(type_hash), // type hash | |
ABI::from_dynamic_bytes(order.to_bytes()), | |
ABI::from_dynamic_bytes(payload_struct.to_bytes()) | |
}); | |
auto signature_bytes = hex_string_as_bytes(owner); | |
signature_bytes.insert(signature_bytes.end(), signature_as_in_docs.begin(), signature_as_in_docs.end()); | |
auto signature = bytes_as_hex_string(signature_bytes); | |
// order hash. From https://github.com/cowprotocol/services/blob/main/crates/model/src/order.rs#L257-L279 | |
std::vector<std::byte> eip712_message_hash; | |
{ | |
std::vector<std::byte> order_hash; | |
std::vector<std::byte> hash_data(416, std::byte{0}); | |
asserta(type_hash.size() == 32); | |
for (auto i = 0; i < type_hash.size(); ++i) | |
hash_data[i] = type_hash[i]; | |
auto sell_token_bytes = hex_string_as_bytes(sell_token().name()); | |
asserta(sell_token_bytes.size() == 20); | |
for (auto i = 0; i < sell_token_bytes.size(); ++i) | |
hash_data[i + 44] = sell_token_bytes[i]; | |
auto buy_token_bytes = hex_string_as_bytes(buy_token().name()); | |
asserta(buy_token_bytes.size() == 20); | |
for (auto i = 0; i < buy_token_bytes.size(); ++i) | |
hash_data[i + 76] = buy_token_bytes[i]; | |
// Leaving receiver as 0x0 | |
auto sell_amount_bytes = ABI::from_uint(sell_amount_after_fees().convert_to<BigInt>()).to_bytes(); | |
asserta(sell_amount_bytes.size() == 32) | |
for (auto i = 0; i < sell_amount_bytes.size(); ++i) | |
hash_data[i + 128] = sell_amount_bytes[i]; | |
auto min_buy_amount_bytes = ABI::from_uint(min_buy_amount_after_fees().convert_to<BigInt>()).to_bytes(); | |
asserta(min_buy_amount_bytes.size() == 32) | |
for (auto i = 0; i < min_buy_amount_bytes.size(); ++i) | |
hash_data[i + 160] = min_buy_amount_bytes[i]; | |
auto valid_to_bytes = uint_as_byte_vector(valid_to_seconds, 4); | |
asserta(valid_to_bytes.size() == 4); | |
for (auto i = 0; i < valid_to_bytes.size(); ++i) | |
hash_data[i + 220] = valid_to_bytes[i]; | |
asserta(app_data_bytes.size() == 32); | |
for (auto i = 0; i < app_data_bytes.size(); ++i) | |
hash_data[i + 224] = app_data_bytes[i]; | |
// Leaving fee amount as 0 | |
asserta(order_kind_bytes.size() == 32); | |
for (auto i = 0; i < order_kind_bytes.size(); ++i) | |
hash_data[i + 288] = order_kind_bytes[i]; | |
// Leaving partially fillable as 0 | |
asserta(erc_token_balance_bytes.size() == 32); | |
for (auto i = 0; i < erc_token_balance_bytes.size(); ++i) | |
hash_data[i + 352] = erc_token_balance_bytes[i]; | |
asserta(erc_token_balance_bytes.size() == 32); | |
for (auto i = 0; i < erc_token_balance_bytes.size(); ++i) | |
hash_data[i + 384] = erc_token_balance_bytes[i]; | |
std::vector<std::byte> eip712_message(66, std::byte{0}); | |
eip712_message[0] = std::byte{0x19}; | |
eip712_message[1] = std::byte{0x01}; | |
for (auto i = 0; i < 32; ++i) | |
eip712_message[i + 2] = separator[i]; | |
order_hash = keccak256(hash_data); | |
for (auto i = 0; i < 32; ++i) | |
eip712_message[i + 34] = order_hash[i]; | |
eip712_message_hash = keccak256(order_hash); | |
} | |
// pre interaction | |
auto pre_interaction = Interaction{ | |
.target = "0x34323b933096534e43958f6c7bf44f2bb59424da", | |
.value = 0, | |
.call_data = ABI::to_calldata_hex_string("commit(address,bytes32)", { | |
ABI::from_address(owner), | |
ABI::from_static_bytes(eip712_message_hash) | |
}), | |
.exec_plan_coords = std::nullopt, | |
.buy_amount = std::nullopt, | |
.sell_amount = std::nullopt | |
}; | |
auto empty_commitment = std::vector<std::byte>(32, std::byte{0}); | |
auto post_interaction = Interaction{ | |
.target = "0x34323b933096534e43958f6c7bf44f2bb59424da", | |
.value = 0, | |
.call_data = ABI::to_calldata_hex_string("commit(address,bytes32)", { | |
ABI::from_address(owner), | |
ABI::from_static_bytes(empty_commitment) | |
}), | |
.exec_plan_coords = std::nullopt, | |
.buy_amount = std::nullopt, | |
.sell_amount = std::nullopt | |
}; | |
return { | |
.signature = signature, | |
.pre_interaction = pre_interaction, | |
.post_interaction = post_interaction | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment