From f5c62398181ca6ddf84e67d6bb9bda5e12c1fd45 Mon Sep 17 00:00:00 2001 From: Mauro Piazza Date: Mon, 4 Nov 2024 18:27:57 +0100 Subject: [PATCH 1/8] feat(PAM.sol): add EOS on chain event parsing --- solidity/src/contracts/PAM.sol | 56 ++++++++++++++++++++++++++++++++-- solidity/test/forge/PAM.t.sol | 43 ++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/solidity/src/contracts/PAM.sol b/solidity/src/contracts/PAM.sol index 615282f1..6342095e 100644 --- a/solidity/src/contracts/PAM.sol +++ b/solidity/src/contracts/PAM.sol @@ -90,7 +90,6 @@ contract PAM is Ownable, IPAM { if (ECDSA.recover(eventId, metadata.signature) != teeAddress) return (false, eventId); - // Event payload format // | emitter | topic-0 | topics-1 | topics-2 | topics-3 | eventBytes | // | 32B | 32B | 32B | 32B | 32B | varlen | @@ -110,7 +109,28 @@ contract PAM is Ownable, IPAM { offset += 32 * 3; // skip other topics - if (!this.doesContentMatchOperation(eventPayload[offset:], operation)) + // Checking the protocol id against 0x02 (EOS chains) + // If the condition is satified we expect data content to be + // a JSON string like: + // + // '{"event_bytes":"00112233445566"}' + // + // in hex would be + // + // 7b226576656e745f6279746573223a223030313132323333343435353636227d + // + // We want to extract 00112233445566, so this is performed by skipping + // the first 16 chars and the trailing 2 chars + // + // Can't factor out these into variables because otherwise it would + // raise the "stack too deep" error + bytes memory eventBytes = uint8(metadata.preimage[1]) == 0x02 + ? _fromUTF8EncodedToBytes( + eventPayload[(offset + 16):(eventPayload.length - 2)] + ) + : eventPayload[offset:]; + + if (!this.doesContentMatchOperation(eventBytes, operation)) return (false, eventId); return (true, eventId); @@ -150,6 +170,7 @@ contract PAM is Ownable, IPAM { Metadata calldata metadata ) internal pure returns (bool) { uint16 offset = 2; // skip protocol, version + bytes32 originChainId = bytes32(metadata.preimage[offset:offset += 32]); if (originChainId != operation.originChainId) return false; @@ -163,6 +184,37 @@ contract PAM is Ownable, IPAM { return true; } + function _fromUTF8EncodedToBytes( + bytes memory utf8Encoded + ) internal pure returns (bytes memory) { + require(utf8Encoded.length % 2 == 0, "invalid utf-8 encoded string"); + bytes memory x = new bytes(utf8Encoded.length / 2); + + uint k; + uint8 b1; + uint8 b2; + for (uint i = 0; i < utf8Encoded.length; i += 2) { + b1 = uint8(utf8Encoded[i]); + b2 = uint8(utf8Encoded[i + 1]); + if ((b1 >= 97) && (b1 <= 102)) { + b1 -= 87; + } else if ((b1 >= 65) && (b1 <= 70)) { + b1 -= 55; + } else if ((b1 >= 48) && (b1 <= 57)) { + b1 -= 48; + } + if ((b2 >= 97) && (b2 <= 102)) { + b2 -= 87; + } else if ((b2 >= 65) && (b2 <= 70)) { + b2 -= 55; + } else if ((b2 >= 48) && (b2 <= 57)) { + b2 -= 48; + } + x[k++] = bytes1(b1 * 16 + b2); + } + return x; + } + function _bytesToAddress(bytes memory tmp) internal pure returns (address) { uint160 iaddr = 0; uint160 b1; diff --git a/solidity/test/forge/PAM.t.sol b/solidity/test/forge/PAM.t.sol index 8697296d..43e4c78e 100644 --- a/solidity/test/forge/PAM.t.sol +++ b/solidity/test/forge/PAM.t.sol @@ -304,4 +304,47 @@ contract PAMTest is Test, Helper { assertFalse(authorized); } + + function test_isAuthrorized_TrueWhen_ValidEosEvent() public { + bytes32 eosTopicZero = 0x0000000000000000000000000000000000000000000000000000000073776170; // 'swap' + bytes32 eosChainId = 0xaca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906; + bytes32 eosAdapter = 0x0000000000000000000000000000000000000000000000000061646170746572; // 'adapter' + bytes memory userdata; + + // Retrieved from the ProofcastEventAttestator testing code + metadata.preimage = vm.parseBytes( + "0x0102aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906179ed57f474f446f2c9f6ea6702724cdad0cf26422299b368755ed93c0134a3527598a45ee610287d85695f823f8992c10602ce5bf3240ee20635219de4f734f000000000000000000000000000000000000000000000000006164617074657200000000000000000000000000000000000000000000000000000000737761700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b226576656e745f6279746573223a22303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303037343662366532653734366636623635366530303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303338303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030386138386636646334363536343030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030373537333635373230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303261333037383336333836323632363536343336363133343337333133393334363536363636333136333636333533313334363233353330363536313339333133383339333533353339333736363633333933313635227d" + ); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + uint256(vm.parseBytes32(attestatorPrivateKey)), + sha256(metadata.preimage) + ); + + metadata.signature = abi.encodePacked(r, s, v); + + operation = IAdapter.Operation( + 0x179ed57f474f446f2c9f6ea6702724cdad0cf26422299b368755ed93c0134a35, // blockhash + 0x27598a45ee610287d85695f823f8992c10602ce5bf3240ee20635219de4f734f, // txHash + 0, // nonce + 0x0000000000000000000000000000000000000000000000746b6e2e746f6b656e, // token ('tkn.token') + eosChainId, // origin chain id + bytes32(destinationChainId), // destination chain id + 9982500000000000000, // amount + 0x0000000000000000000000000000000000000000000000000000000075736572, // sender + 0x68BbEd6A47194EFf1CF514B50Ea91895597fc91E, // recipient + userdata // user data + ); + + vm.chainId(destinationChainId); + + pam = new PAM(); + pam.setEmitter(eosChainId, eosAdapter); + pam.setTopicZero(eosChainId, eosTopicZero); + pam.setTeeSigner(vm.parseBytes(attestatorPublicKey), attestation); + + (bool authorized, ) = pam.isAuthorized(operation, metadata); + + assertTrue(authorized); + } } From ac54a562fddb6f490efcc604ea99642bd5fe0faa Mon Sep 17 00:00:00 2001 From: Mauro Piazza Date: Mon, 4 Nov 2024 18:28:42 +0100 Subject: [PATCH 2/8] fix(ProofcastEventAttestator.spec.js): rm `0x` from event_bytes --- .../test/ProofcastEventAttestator.spec.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/javascript/event-attestator/test/ProofcastEventAttestator.spec.js b/javascript/event-attestator/test/ProofcastEventAttestator.spec.js index fe8d29bc..507b4886 100644 --- a/javascript/event-attestator/test/ProofcastEventAttestator.spec.js +++ b/javascript/event-attestator/test/ProofcastEventAttestator.spec.js @@ -54,8 +54,12 @@ describe('Proofcast Event Attestator Tests', () => { // We are going to extract this = require( the a subfield of the) // official data - const data = - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746b6e2e746f6b656e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008a88f6dc465640000000000000000000000000000000000000000000000000000000000075736572000000000000000000000000000000000000000000000000000000000000002a307836386262656436613437313934656666316366353134623530656139313839353539376663393165' + const data = { + event_bytes: + '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746b6e2e746f6b656e00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000008a88f6dc465640000000000000000000000000000000000000000000000000000000000075736572000000000000000000000000000000000000000000000000000000000000002a307836386262656436613437313934656666316366353134623530656139313839353539376663393165', + } + + const hexData = `0x${Buffer.from(JSON.stringify(data)).toString('hex')}` const ea = new ProofcastEventAttestator({ version: Versions.V1, @@ -69,11 +73,11 @@ describe('Proofcast Event Attestator Tests', () => { transactionHash, account, action, - data, + data: hexData, } const expectedSignature = - '0x1cfc81a6dc16147e5d82d3b9c2fef1ef2125403b92f328439da20ddd5903aef1276adefaeaca2579a342b00149c6916f93d988f81514ab535ebf19dd4eebed3519' + '0x1b546cb297b24aab5b445756f1d0beece3dad851d2cbd8d973f89f69e83f82b77016c87be815fa95bf25d37fb10c3f884cb200d38495e2d1c1bb686e9de38842a5' expect(ea.formatEosSignature(ea.sign(event))).toStrictEqual( expectedSignature, From 53429c5c2099d80abb7c387997ee57a6372764dd Mon Sep 17 00:00:00 2001 From: Mauro Piazza Date: Tue, 5 Nov 2024 13:41:28 +0100 Subject: [PATCH 3/8] fix(utils.hpp): indentation --- cpp/contracts/utils.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/contracts/utils.hpp b/cpp/contracts/utils.hpp index 257b8d07..7d36cb12 100644 --- a/cpp/contracts/utils.hpp +++ b/cpp/contracts/utils.hpp @@ -132,8 +132,8 @@ namespace eosio { } bytes extract_32bytes(const bytes& data, uint128_t offset) { - bytes _data(data.begin() + offset, data.begin() + offset + 32); - return _data; + bytes _data(data.begin() + offset, data.begin() + offset + 32); + return _data; } signature convert_bytes_to_signature(const bytes& input_bytes) { From c38abbe478eee64d72ec0402e8828705d483140a Mon Sep 17 00:00:00 2001 From: Mauro Piazza Date: Tue, 5 Nov 2024 15:00:26 +0100 Subject: [PATCH 4/8] fix(ProofcastEventAttestator.js): stringify data --- javascript/event-attestator/src/ProofcastEventAttestator.js | 2 +- .../event-attestator/test/ProofcastEventAttestator.spec.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/javascript/event-attestator/src/ProofcastEventAttestator.js b/javascript/event-attestator/src/ProofcastEventAttestator.js index ff08cb9b..d85b46e2 100644 --- a/javascript/event-attestator/src/ProofcastEventAttestator.js +++ b/javascript/event-attestator/src/ProofcastEventAttestator.js @@ -55,7 +55,7 @@ class ProofcastEventAttestator { return concat([ zeroPadValue(Buffer.from(event.account, 'utf-8'), 32), ...topics, - event.data, + Buffer.from(JSON.stringify(event.data), 'utf-8'), ]) } diff --git a/javascript/event-attestator/test/ProofcastEventAttestator.spec.js b/javascript/event-attestator/test/ProofcastEventAttestator.spec.js index 507b4886..20809a66 100644 --- a/javascript/event-attestator/test/ProofcastEventAttestator.spec.js +++ b/javascript/event-attestator/test/ProofcastEventAttestator.spec.js @@ -59,8 +59,6 @@ describe('Proofcast Event Attestator Tests', () => { '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746b6e2e746f6b656e00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000008a88f6dc465640000000000000000000000000000000000000000000000000000000000075736572000000000000000000000000000000000000000000000000000000000000002a307836386262656436613437313934656666316366353134623530656139313839353539376663393165', } - const hexData = `0x${Buffer.from(JSON.stringify(data)).toString('hex')}` - const ea = new ProofcastEventAttestator({ version: Versions.V1, protocolId: Protocols.Eos, @@ -73,7 +71,7 @@ describe('Proofcast Event Attestator Tests', () => { transactionHash, account, action, - data: hexData, + data, } const expectedSignature = From 7a627601045da97f8fed62b1f106a0bc9da87fc5 Mon Sep 17 00:00:00 2001 From: Mauro Piazza Date: Tue, 5 Nov 2024 15:01:45 +0100 Subject: [PATCH 5/8] chore(PAM.t.sol): adjust comments --- solidity/test/forge/PAM.t.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/solidity/test/forge/PAM.t.sol b/solidity/test/forge/PAM.t.sol index 43e4c78e..5a0d7427 100644 --- a/solidity/test/forge/PAM.t.sol +++ b/solidity/test/forge/PAM.t.sol @@ -323,6 +323,8 @@ contract PAMTest is Test, Helper { metadata.signature = abi.encodePacked(r, s, v); + // Ugly but necessary in order to avoid the stack + // too deep error operation = IAdapter.Operation( 0x179ed57f474f446f2c9f6ea6702724cdad0cf26422299b368755ed93c0134a35, // blockhash 0x27598a45ee610287d85695f823f8992c10602ce5bf3240ee20635219de4f734f, // txHash @@ -331,7 +333,7 @@ contract PAMTest is Test, Helper { eosChainId, // origin chain id bytes32(destinationChainId), // destination chain id 9982500000000000000, // amount - 0x0000000000000000000000000000000000000000000000000000000075736572, // sender + 0x0000000000000000000000000000000000000000000000000000000075736572, // sender ('user') 0x68BbEd6A47194EFf1CF514B50Ea91895597fc91E, // recipient userdata // user data ); From 8e702e9e7f94a1661bb2275831ba9a316790995f Mon Sep 17 00:00:00 2001 From: Mauro Piazza Date: Tue, 5 Nov 2024 15:04:17 +0100 Subject: [PATCH 6/8] feat(pam.hpp): add EOSIO event on chain event parsing --- cpp/contracts/pam.hpp | 74 +++++++++++++++++++++++++++++++++++++++---- cpp/test/pam.test.js | 74 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 140 insertions(+), 8 deletions(-) diff --git a/cpp/contracts/pam.hpp b/cpp/contracts/pam.hpp index 518681db..dfa74108 100644 --- a/cpp/contracts/pam.hpp +++ b/cpp/contracts/pam.hpp @@ -10,6 +10,7 @@ namespace eosio { using bytes = std::vector; namespace pam { + // aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906 const bytes CHAIN_ID = { 0xac, 0xa3, 0x76, 0xf2, 0x06, 0xb8, 0xfc, 0x25, 0xa6, 0xed, 0x44, 0xdb, 0xdc, 0x66, 0x54, 0x7c, @@ -64,7 +65,43 @@ namespace eosio { return true; } + bytes _fromUTF8EncodedToBytes(const bytes &utf8_encoded) { + check(utf8_encoded.size() % 2 == 0, "invalid utf-8 encoded string"); + + bytes x(utf8_encoded.size() / 2, 0); // fill it with zeros + + uint64_t k = 0; + uint8_t b1, b2; + for (uint64_t i = 0; i < utf8_encoded.size(); i += 2) { + b1 = utf8_encoded[i]; + b2 = utf8_encoded[i + 1]; + + if ((b1 >= 97) && (b1 <= 102)) { // [a, b, c, ..., f] + b1 -= 87; + } else if ((b1 >= 65) && (b1 <= 70)) { // [A, B, C, ..., F] + b1 -= 55; + } else if ((b1 >= 48) && (b1 <= 57)) { // [0, 1, 2, ... ,9] + b1 -= 48; + } + if ((b2 >= 97) && (b2 <= 102)) { + b2 -= 87; + } else if ((b2 >= 65) && (b2 <= 70)) { + b2 -= 55; + } else if ((b2 >= 48) && (b2 <= 57)) { + b2 -= 48; + } + + x[k++] = b1 * 16 + b2; + } + + return x; + } + void check_authorization(name adapter, const operation& operation, const metadata& metadata, checksum256& event_id) { + // Metadata preimage format: + // | version | protocol | origin | blockHash | txHash | eventPayload | + // | 1B | 1B | 32B | 32B | 32B | varlen | + // +----------- context ---------+------------- event ---------------+ check(context_checks(operation, metadata), "unexpected context"); tee_pubkey _tee_pubkey(adapter, adapter.value); @@ -84,6 +121,9 @@ namespace eosio { public_key recovered_pubkey = recover_key(event_id, sig); check(recovered_pubkey == tee_key, "invalid signature"); + // Event payload format + // | emitter | topic-0 | topics-1 | topics-2 | topics-3 | eventBytes | + // | 32B | 32B | 32B | 32B | 32B | varlen | offset = 0; bytes event_payload(metadata.preimage.begin() + 98, metadata.preimage.end()); bytes emitter = extract_32bytes(event_payload, offset); @@ -94,8 +134,33 @@ namespace eosio { check(topic_zero == exp_topic_zero && !is_all_zeros(topic_zero), "unexpected topic zero"); offset += 32 * 4; // skip other topics - // check nonce - bytes event_data(event_payload.begin() + offset, event_payload.end()); + // Checking the protocol id against 0x02 (EOS chains) + // If the condition is satified we expect data content to be + // a JSON string like: + // + // '{"event_bytes":"00112233445566"}' + // + // in hex would be + // + // 7b226576656e745f6279746573223a223030313132323333343435353636227d + // + // We want to extract 00112233445566, so this is performed by skipping + // the first 16 chars and the trailing 2 chars + uint8_t protocol_id = metadata.preimage[1]; + auto start = protocol_id == 2 // EOSIO protocol + ? event_payload.begin() + offset + 16 + : event_payload.begin() + offset; + + auto end = protocol_id == 2 + ? event_payload.end() - 2 + : event_payload.end(); + + bytes raw_data(start, end); + + bytes event_data = protocol_id == 2 + ? _fromUTF8EncodedToBytes(raw_data) + : raw_data; + offset = 0; bytes nonce = extract_32bytes(event_data, offset); uint64_t nonce_int = bytes32_to_uint64(nonce); @@ -103,30 +168,25 @@ namespace eosio { check(operation.nonce == nonce_int, "nonce do not match"); offset += 32; - // check origin token bytes token = extract_32bytes(event_data, offset); checksum256 token_hash = bytes32_to_checksum256(token); check(operation.token == token_hash, "token address do not match"); offset += 32; - // check destination chain id bytes dest_chain_id = extract_32bytes(event_data, offset); check(operation.destinationChainId == dest_chain_id, "destination chain id does not match with the expected one"); check(CHAIN_ID == dest_chain_id, "destination chain id does not match with the current chain"); offset += 32; - // check amount bytes amount = extract_32bytes(event_data, offset); uint128_t amount_num = bytes32_to_uint128(amount); check(to_wei(operation.amount) == amount_num, "amount do not match"); offset += 32; - // check sender address bytes sender = extract_32bytes(event_data, offset); check(operation.sender == sender, "sender do not match"); offset += 32; - // check recipient address bytes recipient_len = extract_32bytes(event_data, offset); offset += 32; uint128_t recipient_len_num = bytes32_to_uint128(recipient_len); diff --git a/cpp/test/pam.test.js b/cpp/test/pam.test.js index 64ef67af..0c315163 100644 --- a/cpp/test/pam.test.js +++ b/cpp/test/pam.test.js @@ -56,11 +56,13 @@ describe('PAM testing', () => { const attestation = [] const blockchain = new Blockchain() + const eosChainId = + 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906' const operation = getOperationSample({ amount: '1337.0000 TKN', sender: '0000000000000000000000002b5ad5c4795c026514f8317c7a215e218dccd6cf', token: '000000000000000000000000f2e246bb76df876cef8b38ae84130f4f55de395b', - chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', + chainId: eosChainId, recipient, }) const data = @@ -314,5 +316,75 @@ describe('PAM testing', () => { expect(pam.contract.bc.console).to.be.equal(expectedEventId) }) }) + + it('Should authorize an EOSIO operation successfully', async () => { + const blockId = + '179ed57f474f446f2c9f6ea6702724cdad0cf26422299b368755ed93c0134a35' + const txId = + '27598a45ee610287d85695f823f8992c10602ce5bf3240ee20635219de4f734f' + const nonce = 0 + const token = + '0000000000000000000000000000000000000000000000746b6e2e746f6b656e' + const originChainId = no0x(Chains(Protocols.Eos).Jungle) + const destinationChainId = eosChainId + const amount = '9.9825 TKN' + const sender = + '0000000000000000000000000000000000000000000000000000000075736572' + const recipient = 'recipient' + const data = '' + const operation2 = getOperationSample({ + blockId, + txId, + nonce, + token, + originChainId, + destinationChainId, + amount, + sender, + recipient, + data, + }) + + const eosEmitter = Buffer.from('adapter') + .toString('hex') + .padStart(64, '0') + const eosTopic0 = Buffer.from('swap').toString('hex').padStart(64, '0') + + const ea2 = new ProofcastEventAttestator({ + version: Versions.V1, + protocolId: Protocols.Eos, + chainId: Chains(Protocols.Eos).Jungle, + privateKey, + }) + + const eventData = { + event_bytes: + '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746b6e2e746f6b656eaca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e9060000000000000000000000000000000000000000000000008a88f6dc4656400000000000000000000000000000000000000000000000000000000000757365720000000000000000000000000000000000000000000000000000000000000009726563697069656e74', + } + + const event2 = { + blockHash: operation2.blockId, + transactionHash: operation2.txId, + account: 'adapter', + action: 'swap', + data: eventData, + } + + await adapter.contract.actions + .setorigin([operation2.originChainId, eosEmitter, eosTopic0]) + .send(active(adapter.account)) + + const metadata2 = getMetadataSample({ + signature: no0x(ea2.formatEosSignature(ea2.sign(event2))), + preimage: no0x(ea2.getEventPreImage(event2)), + }) + + await pam.contract.actions + .isauthorized([operation2, metadata2]) + .send(active(user)) + expect(pam.contract.bc.console).to.be.equal( + '42cde5d898147a7bd21006e0fe541092151262cb2bde3a3244587e7993c473e0', + ) + }) }) }) From bebc02f655d2cbd980d9eca538155a94fc0d6532 Mon Sep 17 00:00:00 2001 From: Mauro Piazza Date: Tue, 5 Nov 2024 15:09:46 +0100 Subject: [PATCH 7/8] chore(PAM.sol): factor out common code --- solidity/src/contracts/PAM.sol | 47 +++++++++++----------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/solidity/src/contracts/PAM.sol b/solidity/src/contracts/PAM.sol index 6342095e..3831a5e6 100644 --- a/solidity/src/contracts/PAM.sol +++ b/solidity/src/contracts/PAM.sol @@ -184,6 +184,17 @@ contract PAM is Ownable, IPAM { return true; } + function _fromHexCharToUint8(uint8 x) internal pure returns (uint8) { + if ((x >= 97) && (x <= 102)) { + x -= 87; + } else if ((x >= 65) && (x <= 70)) { + x -= 55; + } else if ((x >= 48) && (x <= 57)) { + x -= 48; + } + return x; + } + function _fromUTF8EncodedToBytes( bytes memory utf8Encoded ) internal pure returns (bytes memory) { @@ -194,22 +205,8 @@ contract PAM is Ownable, IPAM { uint8 b1; uint8 b2; for (uint i = 0; i < utf8Encoded.length; i += 2) { - b1 = uint8(utf8Encoded[i]); - b2 = uint8(utf8Encoded[i + 1]); - if ((b1 >= 97) && (b1 <= 102)) { - b1 -= 87; - } else if ((b1 >= 65) && (b1 <= 70)) { - b1 -= 55; - } else if ((b1 >= 48) && (b1 <= 57)) { - b1 -= 48; - } - if ((b2 >= 97) && (b2 <= 102)) { - b2 -= 87; - } else if ((b2 >= 65) && (b2 <= 70)) { - b2 -= 55; - } else if ((b2 >= 48) && (b2 <= 57)) { - b2 -= 48; - } + b1 = _fromHexCharToUint8(uint8(utf8Encoded[i])); + b2 = _fromHexCharToUint8(uint8(utf8Encoded[i + 1])); x[k++] = bytes1(b1 * 16 + b2); } return x; @@ -221,22 +218,8 @@ contract PAM is Ownable, IPAM { uint160 b2; for (uint256 i = 2; i < 2 + 2 * 20; i += 2) { iaddr *= 256; - b1 = uint160(uint8(tmp[i])); - b2 = uint160(uint8(tmp[i + 1])); - if ((b1 >= 97) && (b1 <= 102)) { - b1 -= 87; - } else if ((b1 >= 65) && (b1 <= 70)) { - b1 -= 55; - } else if ((b1 >= 48) && (b1 <= 57)) { - b1 -= 48; - } - if ((b2 >= 97) && (b2 <= 102)) { - b2 -= 87; - } else if ((b2 >= 65) && (b2 <= 70)) { - b2 -= 55; - } else if ((b2 >= 48) && (b2 <= 57)) { - b2 -= 48; - } + b1 = uint160(_fromHexCharToUint8(uint8(tmp[i]))); + b2 = uint160(_fromHexCharToUint8(uint8(tmp[i + 1]))); iaddr += (b1 * 16 + b2); } return address(iaddr); From b47f775e759d50d152ca133781ec9e9b6ed88187 Mon Sep 17 00:00:00 2001 From: Mauro Piazza Date: Tue, 5 Nov 2024 15:18:48 +0100 Subject: [PATCH 8/8] chore(pam.hpp): factor out & fix name --- cpp/contracts/pam.hpp | 34 +--------------------------------- cpp/contracts/utils.hpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/cpp/contracts/pam.hpp b/cpp/contracts/pam.hpp index dfa74108..156d1820 100644 --- a/cpp/contracts/pam.hpp +++ b/cpp/contracts/pam.hpp @@ -65,38 +65,6 @@ namespace eosio { return true; } - bytes _fromUTF8EncodedToBytes(const bytes &utf8_encoded) { - check(utf8_encoded.size() % 2 == 0, "invalid utf-8 encoded string"); - - bytes x(utf8_encoded.size() / 2, 0); // fill it with zeros - - uint64_t k = 0; - uint8_t b1, b2; - for (uint64_t i = 0; i < utf8_encoded.size(); i += 2) { - b1 = utf8_encoded[i]; - b2 = utf8_encoded[i + 1]; - - if ((b1 >= 97) && (b1 <= 102)) { // [a, b, c, ..., f] - b1 -= 87; - } else if ((b1 >= 65) && (b1 <= 70)) { // [A, B, C, ..., F] - b1 -= 55; - } else if ((b1 >= 48) && (b1 <= 57)) { // [0, 1, 2, ... ,9] - b1 -= 48; - } - if ((b2 >= 97) && (b2 <= 102)) { - b2 -= 87; - } else if ((b2 >= 65) && (b2 <= 70)) { - b2 -= 55; - } else if ((b2 >= 48) && (b2 <= 57)) { - b2 -= 48; - } - - x[k++] = b1 * 16 + b2; - } - - return x; - } - void check_authorization(name adapter, const operation& operation, const metadata& metadata, checksum256& event_id) { // Metadata preimage format: // | version | protocol | origin | blockHash | txHash | eventPayload | @@ -158,7 +126,7 @@ namespace eosio { bytes raw_data(start, end); bytes event_data = protocol_id == 2 - ? _fromUTF8EncodedToBytes(raw_data) + ? from_utf8_encoded_to_bytes(raw_data) : raw_data; offset = 0; diff --git a/cpp/contracts/utils.hpp b/cpp/contracts/utils.hpp index 7d36cb12..1330ff94 100644 --- a/cpp/contracts/utils.hpp +++ b/cpp/contracts/utils.hpp @@ -214,4 +214,32 @@ namespace eosio { name name_value(name_str); return name_value; } + + uint8_t from_hex_char_to_uint8(uint8_t x) { + if ((x >= 97) && (x <= 102)) { // [a, b, c, ..., f] + x -= 87; + } else if ((x >= 65) && (x <= 70)) { // [A, B, C, ..., F] + x -= 55; + } else if ((x >= 48) && (x <= 57)) { // [0, 1, 2, ... ,9] + x -= 48; + } + + return x; + } + + bytes from_utf8_encoded_to_bytes(const bytes &utf8_encoded) { + check(utf8_encoded.size() % 2 == 0, "invalid utf-8 encoded string"); + + bytes x(utf8_encoded.size() / 2, 0); // fill it with zeros + + uint64_t k = 0; + uint8_t b1, b2; + for (uint64_t i = 0; i < utf8_encoded.size(); i += 2) { + b1 = from_hex_char_to_uint8(utf8_encoded[i]); + b2 = from_hex_char_to_uint8(utf8_encoded[i + 1]); + x[k++] = b1 * 16 + b2; + } + + return x; + } } \ No newline at end of file