From 0209ff4c40b34dc1c319bf6476a05c02dc46db94 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:06:48 +0000 Subject: [PATCH 01/25] update fixtures --- tests/fixtures/evm-sign.json | 32 ++++++++++---------- tests/fixtures/multipayment-empty.json | 34 ++++++++++----------- tests/fixtures/multipayment-single.json | 34 ++++++++++----------- tests/fixtures/multipayment.json | 35 +++++++++++----------- tests/fixtures/transfer-0.json | 34 ++++++++++----------- tests/fixtures/transfer-large-amount.json | 34 ++++++++++----------- tests/fixtures/transfer.json | 34 ++++++++++----------- tests/fixtures/unvote.json | 34 ++++++++++----------- tests/fixtures/username-registration.json | 34 ++++++++++----------- tests/fixtures/username-resignation.json | 33 ++++++++++---------- tests/fixtures/validator-registration.json | 34 ++++++++++----------- tests/fixtures/validator-resignation.json | 34 ++++++++++----------- tests/fixtures/vote.json | 34 ++++++++++----------- 13 files changed, 220 insertions(+), 220 deletions(-) diff --git a/tests/fixtures/evm-sign.json b/tests/fixtures/evm-sign.json index a171db39..65ae60a0 100644 --- a/tests/fixtures/evm-sign.json +++ b/tests/fixtures/evm-sign.json @@ -1,18 +1,18 @@ { - "data": { - "network": 30, - "nonce": "1", - "gasPrice": 5, - "gasLimit": 1000000, - "value": "0", - "recipientAddress": "0xe536720791a7dadbebdbcd8c8546fb0791a11901", - "data": "a9059cbb00000000000000000000000027fa7caffaae77ddb9ab232fdbda56d5e5af23930000000000000000000000000000000000000000000000000000000000000064", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "2cfa9d51e71f014f8054881052e41dc61267587f9dba04c59a31cc881f8ce35b", - "v": 27, - "r": "a56cf78a7203927af0c8216fdbc804182a0788569e460067efec519b6f7b2e55", - "s": "52ce951a20c7406a4a34707557f02e5a2af1451cc4e216645778c4ee0391a4cd" - }, - "serialized": "02f8a81e018005830f424094e536720791a7dadbebdbcd8c8546fb0791a1190180b844a9059cbb00000000000000000000000027fa7caffaae77ddb9ab232fdbda56d5e5af23930000000000000000000000000000000000000000000000000000000000000064c080a0a56cf78a7203927af0c8216fdbc804182a0788569e460067efec519b6f7b2e55a052ce951a20c7406a4a34707557f02e5a2af1451cc4e216645778c4ee0391a4cd" + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0xE536720791A7DaDBeBdBCD8c8546fb0791a11901", + "value": "0", + "data": "a9059cbb00000000000000000000000027fa7caffaae77ddb9ab232fdbda56d5e5af23930000000000000000000000000000000000000000000000000000000000000064", + "v": 28, + "r": "8cd7afafdfaaa6c4b6c97e49888dff89713c99f8b1324693ef4427ce88994bbe", + "s": "01c589bb8d3bc908aaee56d64ca35458f2cebf977bbc29180c574aba8bc12b0d", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "85cdc2ae6cd4569dd1b5b11df10fc409b3996864032d6acf87ff907286f40a03" + }, + "serialized": "02f8af822710018085012a05f20083030d4094e536720791a7dadbebdbcd8c8546fb0791a1190180b844a9059cbb00000000000000000000000027fa7caffaae77ddb9ab232fdbda56d5e5af23930000000000000000000000000000000000000000000000000000000000000064c001a08cd7afafdfaaa6c4b6c97e49888dff89713c99f8b1324693ef4427ce88994bbea001c589bb8d3bc908aaee56d64ca35458f2cebf977bbc29180c574aba8bc12b0d" } diff --git a/tests/fixtures/multipayment-empty.json b/tests/fixtures/multipayment-empty.json index 7a235183..a0dd6bd6 100644 --- a/tests/fixtures/multipayment-empty.json +++ b/tests/fixtures/multipayment-empty.json @@ -1,18 +1,18 @@ { - "data": { - "network": 30, - "nonce": "1", - "gasPrice": 5, - "gasLimit": 1000000, - "value": "0", - "recipientAddress": "0x83769BeEB7e5405ef0B7dc3C66C43E3a51A6d27f", - "data": "084ce7080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "d816a0f8b51eb618c4497aeddcc9d4596f94fefc39de306282f50596c9e1c071", - "v": 28, - "r": "bfab2a6634cfbf8bc802d0259dea575b7618131e8de9e29ca7df1950e68ce8eb", - "s": "5e7eeb4c2f973a8397f38b68520123798b07b4f1bf251bbaaacafb36e8e05a55" - }, - "serialized": "02f8e81e018005830f42409483769beeb7e5405ef0b7dc3c66c43e3a51a6d27f80b884084ce7080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c001a0bfab2a6634cfbf8bc802d0259dea575b7618131e8de9e29ca7df1950e68ce8eba05e7eeb4c2f973a8397f38b68520123798b07b4f1bf251bbaaacafb36e8e05a55" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x00EFd0D4639191C49908A7BddbB9A11A994A8527", + "value": "0", + "data": "084ce7080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "v": 27, + "r": "cbec73e1cba1177789adf44fcd3cea797d132563635fae211c350acd7c328046", + "s": "216eabb6cd1eb5c0000e7eb74f66595bd5b688f43dd646f15f33e3827c8c966b", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "555fcaca65f9319c638ebb15c5ffdee0a5e41b7dc3b171aca3707bc43f40ed57" + }, + "serialized": "02f8ef822710018085012a05f20083030d409400efd0d4639191c49908a7bddbb9a11a994a852780b884084ce7080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080a0cbec73e1cba1177789adf44fcd3cea797d132563635fae211c350acd7c328046a0216eabb6cd1eb5c0000e7eb74f66595bd5b688f43dd646f15f33e3827c8c966b" +} \ No newline at end of file diff --git a/tests/fixtures/multipayment-single.json b/tests/fixtures/multipayment-single.json index b2e6098b..65e4df03 100644 --- a/tests/fixtures/multipayment-single.json +++ b/tests/fixtures/multipayment-single.json @@ -1,18 +1,18 @@ { - "data": { - "network": 30, - "nonce": "1", - "gasPrice": 5, - "gasLimit": 1000000, - "value": "100000000", - "recipientAddress": "0x83769BeEB7e5405ef0B7dc3C66C43E3a51A6d27f", - "data": "084ce7080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008233f6df6449d7655f4643d2e752dc8d2283fad500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000005f5e100", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "d3775117889fce2397bded88564427dda03c31f2b85a839567f98ae776e3ff4c", - "v": 28, - "r": "c00a8f6a658c1dda434bceb708c74d62d086ec143939c2373010284221d25995", - "s": "43f6e7e5988f37c4336638c1b6a0cf4aa6caeefd5bda6937aa03464bdf44536c" - }, - "serialized": "02f9012c1e018005830f42409483769beeb7e5405ef0b7dc3c66c43e3a51a6d27f8405f5e100b8c4084ce7080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008233f6df6449d7655f4643d2e752dc8d2283fad500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000005f5e100c001a0c00a8f6a658c1dda434bceb708c74d62d086ec143939c2373010284221d25995a043f6e7e5988f37c4336638c1b6a0cf4aa6caeefd5bda6937aa03464bdf44536c" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x00EFd0D4639191C49908A7BddbB9A11A994A8527", + "value": "100000", + "data": "084ce7080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006f0182a0cc707b055322ccf6d4cb6a5aff1aeb22000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000186a0", + "v": 28, + "r": "e381eb89f21e450009706650346e3abfaee0c91c5685c8ec923d86b8212a2427", + "s": "5b3a7bfdec8ca69469e989805e7715f5d317bf62304f868a905224e7dabe7b37", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "1d0e3d567ffa39defba7904202941070b224f885f9399c817a58aeb36f4f3863" + }, + "serialized": "02f90132822710018085012a05f20083030d409400efd0d4639191c49908a7bddbb9a11a994a8527830186a0b8c4084ce7080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006f0182a0cc707b055322ccf6d4cb6a5aff1aeb22000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000186a0c001a0e381eb89f21e450009706650346e3abfaee0c91c5685c8ec923d86b8212a2427a05b3a7bfdec8ca69469e989805e7715f5d317bf62304f868a905224e7dabe7b37" +} \ No newline at end of file diff --git a/tests/fixtures/multipayment.json b/tests/fixtures/multipayment.json index 20e781c9..62e21f44 100644 --- a/tests/fixtures/multipayment.json +++ b/tests/fixtures/multipayment.json @@ -1,19 +1,18 @@ { - "data": { - "network": 30, - "nonce": "1", - "gasPrice": 5, - "gasLimit": 1000000, - "valaue": "3000000000000000000", - "value": "300000000", - "recipientAddress": "0x83769BeEB7e5405ef0B7dc3C66C43E3a51A6d27f", - "data": "084ce708000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000008233f6df6449d7655f4643d2e752dc8d2283fad50000000000000000000000008233f6df6449d7655f4643d2e752dc8d2283fad500000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000000bebc200", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "8ef542e888c41642297bf3e4cb0f58cfe3a07e38adcb74cd2f121b5653c4db9e", - "v": 27, - "r": "39e6a6fb8c41c33d1c56c6b0f8c15f977582f9fcf626dbc84b82526db201c8dc", - "s": "285f0849073a3952511bdc34682668272799eacf3cd7556a9800f46d57e557ea" - }, - "serialized": "02f9016d1e018005830f42409483769beeb7e5405ef0b7dc3c66c43e3a51a6d27f8411e1a300b90104084ce708000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000008233f6df6449d7655f4643d2e752dc8d2283fad50000000000000000000000008233f6df6449d7655f4643d2e752dc8d2283fad500000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000000bebc200c080a039e6a6fb8c41c33d1c56c6b0f8c15f977582f9fcf626dbc84b82526db201c8dca0285f0849073a3952511bdc34682668272799eacf3cd7556a9800f46d57e557ea" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x00EFd0D4639191C49908A7BddbB9A11A994A8527", + "value": "300000", + "data": "084ce708000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000006f0182a0cc707b055322ccf6d4cb6a5aff1aeb22000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000186a00000000000000000000000000000000000000000000000000000000000030d40", + "v": 27, + "r": "0c7cfc6e77249b44385decfd49b8d4deac3c4c49147a0a8d539d82d51da81581", + "s": "6af2959905394b401c87872f78ae321cf8cfdd03fe80a815a99bdd723cc90462", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "d2b7d9e8730de8ab788a37905974c11f6df1a7e5bea5f9a716bffbec17b1d3a8" + }, + "serialized": "02f90173822710018085012a05f20083030d409400efd0d4639191c49908a7bddbb9a11a994a8527830493e0b90104084ce708000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000006f0182a0cc707b055322ccf6d4cb6a5aff1aeb22000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000186a00000000000000000000000000000000000000000000000000000000000030d40c080a00c7cfc6e77249b44385decfd49b8d4deac3c4c49147a0a8d539d82d51da81581a06af2959905394b401c87872f78ae321cf8cfdd03fe80a815a99bdd723cc90462" +} \ No newline at end of file diff --git a/tests/fixtures/transfer-0.json b/tests/fixtures/transfer-0.json index 8d69083d..261344bb 100644 --- a/tests/fixtures/transfer-0.json +++ b/tests/fixtures/transfer-0.json @@ -1,18 +1,18 @@ { - "data": { - "network": 30, - "nonce": "123", - "gasPrice": 5, - "gasLimit": 21000, - "recipientAddress": "0xb693449adda7efc015d87944eae8b7c37eb1690a", - "value": "0", - "data": "", - "v": 28, - "r": "f7bae93b75f06c39600f123ca6c805a38636db9643eac29d20d21c6bf0d2eca2", - "s": "17265ff237bff3fe0620c53ff1615c4b8ad9136fe3d61dca38562c60dc5fcae2", - "senderPublicKey": "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", - "senderAddress": "0x41aD2bc63A2059f9b623533d87fe99887D794847", - "id": "7d6ad61dabbc9907484080100096c9c7c6364c130ca003f9dd730901c112437f" - }, - "serialized": "02f8621e7b800582520894b693449adda7efc015d87944eae8b7c37eb1690a8080c001a0f7bae93b75f06c39600f123ca6c805a38636db9643eac29d20d21c6bf0d2eca2a017265ff237bff3fe0620c53ff1615c4b8ad9136fe3d61dca38562c60dc5fcae2" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 21000, + "recipientAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", + "value": "0", + "data": "", + "v": 27, + "r": "2c42ef45cb01b01c0a59b61a7e82d37c8566e0fc0f0f47c2a2825d1cbc8abefc", + "s": "455bb2aec9d8d038db506d5a964728c78eaa4f237e0d40666742e4d5d686f576", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "241ce787680623dea7b9acf2951e2f8b8afac5f92b33b9909ab2bfbadf4be92c" + }, + "serialized": "02f869822710018085012a05f200825208946f0182a0cc707b055322ccf6d4cb6a5aff1aeb228080c080a02c42ef45cb01b01c0a59b61a7e82d37c8566e0fc0f0f47c2a2825d1cbc8abefca0455bb2aec9d8d038db506d5a964728c78eaa4f237e0d40666742e4d5d686f576" +} \ No newline at end of file diff --git a/tests/fixtures/transfer-large-amount.json b/tests/fixtures/transfer-large-amount.json index 0fcee465..45a87c02 100644 --- a/tests/fixtures/transfer-large-amount.json +++ b/tests/fixtures/transfer-large-amount.json @@ -1,18 +1,18 @@ { - "data": { - "network": 30, - "nonce": "17", - "gasPrice": 5, - "gasLimit": 21000, - "recipientAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "value": "10000000000000000000", - "data": "", - "v": 27, - "r": "c741f8ccf811e7080216b71e0cbcad1138a4f187b08c749c5e8780568f1ff4bc", - "s": "530341bef473fa92db1fe96922758ed010ba8eb80f2e527c9441771fa4c5368b", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "fb9e521867f484cae4b59585d55ac55a99a8c6adfa0cf8b8b50d242115cbb40d" - }, - "serialized": "02f86a1e118005825208946f0182a0cc707b055322ccf6d4cb6a5aff1aeb22888ac7230489e8000080c080a0c741f8ccf811e7080216b71e0cbcad1138a4f187b08c749c5e8780568f1ff4bca0530341bef473fa92db1fe96922758ed010ba8eb80f2e527c9441771fa4c5368b" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 21000, + "recipientAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", + "value": "10000000000000000000", + "data": "", + "v": 27, + "r": "62666b937e4c3f55c87c44ee72b5a228c1377adbdad44264dd953b3c2b878734", + "s": "2d8670a69ce09018cfac5604d59a2b74bee18c99a91cbd14ac33c3ccfe96a35a", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "0d22ff14b09da9c5fa975d8fe79b93086853d223000cf88ff923a57650c93e4a" + }, + "serialized": "02f871822710018085012a05f200825208946f0182a0cc707b055322ccf6d4cb6a5aff1aeb22888ac7230489e8000080c080a062666b937e4c3f55c87c44ee72b5a228c1377adbdad44264dd953b3c2b878734a02d8670a69ce09018cfac5604d59a2b74bee18c99a91cbd14ac33c3ccfe96a35a" +} \ No newline at end of file diff --git a/tests/fixtures/transfer.json b/tests/fixtures/transfer.json index 24a2b1aa..31647d8d 100644 --- a/tests/fixtures/transfer.json +++ b/tests/fixtures/transfer.json @@ -1,18 +1,18 @@ { - "data": { - "network": 30, - "nonce": "1", - "gasPrice": 5, - "gasLimit": 21000, - "recipientAddress": "0x6f0182a0cc707b055322ccf6d4cb6a5aff1aeb22", - "value": "100000000", - "data": "", - "v": 27, - "r": "0567c4def813a66e03fa1cd499a27c6922698a67e25e0b38458d8f4bb0e581fc", - "s": "25fcdf9d110b82bde15bae4a49118deb83cfc3ec1656c2a29286d7836d328abe", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "id": "0b8a05781cc5ea130573f33330a739f9a17f7d889bcfab519b09ee5ccc7f359d" - }, - "serialized": "02f8661e018005825208946f0182a0cc707b055322ccf6d4cb6a5aff1aeb228405f5e10080c080a00567c4def813a66e03fa1cd499a27c6922698a67e25e0b38458d8f4bb0e581fca025fcdf9d110b82bde15bae4a49118deb83cfc3ec1656c2a29286d7836d328abe" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 21000, + "recipientAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", + "value": "100000000", + "data": "", + "v": 28, + "r": "104665257d4dea61c4654e74c6c0f6cd0a398905781c3040bea67dc641a66da0", + "s": "46d718d04b2331f3b0561808549ed3f3f0d867a284acf6b334869078df7a9136", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "b7927d90b38cd1296351f26145b3d8b0674fdc9b8721bc1a10f71a12bcbccf60" + }, + "serialized": "02f86d822710018085012a05f200825208946f0182a0cc707b055322ccf6d4cb6a5aff1aeb228405f5e10080c001a0104665257d4dea61c4654e74c6c0f6cd0a398905781c3040bea67dc641a66da0a046d718d04b2331f3b0561808549ed3f3f0d867a284acf6b334869078df7a9136" +} \ No newline at end of file diff --git a/tests/fixtures/unvote.json b/tests/fixtures/unvote.json index 5dccb90f..3b099dbf 100644 --- a/tests/fixtures/unvote.json +++ b/tests/fixtures/unvote.json @@ -1,18 +1,18 @@ { - "data": { - "gasPrice": 5, - "network": 30, - "id": "4f43cc9b97433bfc86f3aaa55dbedfad1f15c76b527ec68f7a80fc15105d2e43", - "gasLimit": 1000000, - "nonce": "1", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "recipientAddress": "0x535b3d7a252fa034ed71f0c53ec0c6f784cb64e1", - "value": "0", - "data": "3174b689", - "v": 27, - "r": "2853135c30a6b131e9270ce1b52999b8d2bdc18b25bef5b1c13ef4ca8a20ce9e", - "s": "3999a9d5d1ff826efa13052394b28b101535c92dcd8744c916c003431e08744e" - }, - "serialized": "02f8671e018005830f424094535b3d7a252fa034ed71f0c53ec0c6f784cb64e180843174b689c080a02853135c30a6b131e9270ce1b52999b8d2bdc18b25bef5b1c13ef4ca8a20ce9ea03999a9d5d1ff826efa13052394b28b101535c92dcd8744c916c003431e08744e" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x535B3D7A252fa034Ed71F0C53ec0C6F784cB64E1", + "value": "0", + "data": "3174b689", + "v": 27, + "r": "bd7f932c18b49e05600cd1603808fd0a19701ee4af99035fc7b1a9159458d08d", + "s": "18a4420edfdc90fcff7c6e4d062ae11dae7a62a7ab53f6499862f3e79d67a252", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "ed937a96f4edc0fa89e7d6146b88f17a3de71f86fc200da49c73e7c93eabfea9" + }, + "serialized": "02f86e822710018085012a05f20083030d4094535b3d7a252fa034ed71f0c53ec0c6f784cb64e180843174b689c080a0bd7f932c18b49e05600cd1603808fd0a19701ee4af99035fc7b1a9159458d08da018a4420edfdc90fcff7c6e4d062ae11dae7a62a7ab53f6499862f3e79d67a252" +} \ No newline at end of file diff --git a/tests/fixtures/username-registration.json b/tests/fixtures/username-registration.json index 46d03a63..77d6e66e 100644 --- a/tests/fixtures/username-registration.json +++ b/tests/fixtures/username-registration.json @@ -1,18 +1,18 @@ { - "data": { - "gasPrice": 5, - "network": 30, - "id": "6643b3dec8d2e8aaa188fb83b96c9ebf2ed21d547ff641f267ddc5ef29152f6b", - "gasLimit": 1000000, - "nonce": "1", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "recipientAddress": "0x2c1de3b4dbb4adebebb5dcecae825be2a9fc6eb6", - "value": "0", - "data": "36a94134000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000037068700000000000000000000000000000000000000000000000000000000000", - "v": 27, - "r": "48f36028509a88c8670b2baaac14b5ba6a8c88bbd90cce4149a3070e57f0fa42", - "s": "297fe9a4d2df4c682e8705311d1143d2df9c89dc8689853544c1eb96121f5e85" - }, - "serialized": "02f8c81e018005830f4240942c1de3b4dbb4adebebb5dcecae825be2a9fc6eb680b86436a94134000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000037068700000000000000000000000000000000000000000000000000000000000c080a048f36028509a88c8670b2baaac14b5ba6a8c88bbd90cce4149a3070e57f0fa42a0297fe9a4d2df4c682e8705311d1143d2df9c89dc8689853544c1eb96121f5e85" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x2c1DE3b4Dbb4aDebEbB5dcECAe825bE2a9fc6eb6", + "value": "0", + "data": "36a94134000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000076669787475726500000000000000000000000000000000000000000000000000", + "v": 28, + "r": "4564cc1adbde3e8a309bf9d3eb76b45fecfae62fbdc0604f70483197de4d66b3", + "s": "4d4573a50c9a80221c21d11ce51b9b8bd196f9e1ab1a805b7d8b8e56fcfe2003", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "781979a58ac75475b91a1e401b50f9cc52465b21fe83e1c30e05676aaeb6a806" + }, + "serialized": "02f8cf822710018085012a05f20083030d40942c1de3b4dbb4adebebb5dcecae825be2a9fc6eb680b86436a94134000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000076669787475726500000000000000000000000000000000000000000000000000c001a04564cc1adbde3e8a309bf9d3eb76b45fecfae62fbdc0604f70483197de4d66b3a04d4573a50c9a80221c21d11ce51b9b8bd196f9e1ab1a805b7d8b8e56fcfe2003" +} \ No newline at end of file diff --git a/tests/fixtures/username-resignation.json b/tests/fixtures/username-resignation.json index 2211eed3..8846b88c 100644 --- a/tests/fixtures/username-resignation.json +++ b/tests/fixtures/username-resignation.json @@ -1,17 +1,18 @@ { - "data": { - "gasPrice": 5, - "network": 30, - "id": "b9a6712e63dafc05583d89c0a31a7199d027f06a21369e9df79e2ae2f20dca7e", - "gasLimit": 1000000, - "nonce": "1", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "recipientAddress": "0x2c1DE3b4Dbb4aDebEbB5dcECAe825bE2a9fc6eb6", - "value": "0", - "data": "ebed6dab", - "v": 28, - "r": "76ade83c279901613b31e41b9cf0e55223ef728edc5d920d108d239929abf523", - "s": "0a8fe944d4217ebfe6afad28f1fce2f03e4cfe7aa90ea932c1dae4216603a82c" - }, - "serialized": "02f8671e018005830f4240942c1de3b4dbb4adebebb5dcecae825be2a9fc6eb68084ebed6dabc001a076ade83c279901613b31e41b9cf0e55223ef728edc5d920d108d239929abf523a00a8fe944d4217ebfe6afad28f1fce2f03e4cfe7aa90ea932c1dae4216603a82c" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x2c1DE3b4Dbb4aDebEbB5dcECAe825bE2a9fc6eb6", + "value": "0", + "data": "ebed6dab", + "v": 27, + "r": "c786beafa03da8c6485bc15870ea8512db27427e3aa38654a7b8d534b30c48da", + "s": "78b2b4568f4d0f5d482c670001e6877b282ed6e16cdcbea6bd29195ca2bb036d", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "d1647fe630bcf63a23bda6015295dafe246356b0e7930cdc8a52f216fa4429a5" + }, + "serialized": "02f86e822710018085012a05f20083030d40942c1de3b4dbb4adebebb5dcecae825be2a9fc6eb68084ebed6dabc080a0c786beafa03da8c6485bc15870ea8512db27427e3aa38654a7b8d534b30c48daa078b2b4568f4d0f5d482c670001e6877b282ed6e16cdcbea6bd29195ca2bb036d" +} \ No newline at end of file diff --git a/tests/fixtures/validator-registration.json b/tests/fixtures/validator-registration.json index 8b276b3d..9e2279b6 100644 --- a/tests/fixtures/validator-registration.json +++ b/tests/fixtures/validator-registration.json @@ -1,18 +1,18 @@ { - "data": { - "gasPrice": 5, - "network": 30, - "id": "7d7a6fcda2c5c16347f42f909e3002509c07780aabb7896f42e3172f2f25e92a", - "gasLimit": 1000000, - "nonce": "1", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "recipientAddress": "0x535b3d7a252fa034ed71f0c53ec0c6f784cb64e1", - "value": "0", - "data": "602a9eee00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030954f46d6097a1d314e900e66e11e0dad0a57cd03e04ec99f0dedd1c765dcb11e6d7fa02e22cf40f9ee23d9cc1c0624bd00000000000000000000000000000000", - "v": 27, - "r": "609cfbaf2a8195741dcf2054e73c88e93103d4c13e7f9d5fc83f881c01a38773", - "s": "79266d0b2c9bdaccbc3fba88c6dfad4538bcdcda803b8e0faa33cdd84b73abed" - }, - "serialized": "02f8e81e018005830f424094535b3d7a252fa034ed71f0c53ec0c6f784cb64e180b884602a9eee00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030954f46d6097a1d314e900e66e11e0dad0a57cd03e04ec99f0dedd1c765dcb11e6d7fa02e22cf40f9ee23d9cc1c0624bd00000000000000000000000000000000c080a0609cfbaf2a8195741dcf2054e73c88e93103d4c13e7f9d5fc83f881c01a38773a079266d0b2c9bdaccbc3fba88c6dfad4538bcdcda803b8e0faa33cdd84b73abed" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x535B3D7A252fa034Ed71F0C53ec0C6F784cB64E1", + "value": "0", + "data": "602a9eee0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003030954f46d6097a1d314e900e66e11e0dad0a57cd03e04ec99f0dedd1c765dcb11e6d7fa02e22cf40f9ee23d9cc1c062400000000000000000000000000000000", + "v": 28, + "r": "57216346b5252f6db63a2c78b5bc0a3697d2247377e9d9ef1b67849a87eb2413", + "s": "66ea02477fc19671b3b626e3c4d33939a8ba43004f0a56e900efc1e580739d11", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "5064b50091b8e5d50ec1d1eb7c5b71cdcf9c7355bba18ee0efeaeacb0b1c95d5" + }, + "serialized": "02f8ef822710018085012a05f20083030d4094535b3d7a252fa034ed71f0c53ec0c6f784cb64e180b884602a9eee0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003030954f46d6097a1d314e900e66e11e0dad0a57cd03e04ec99f0dedd1c765dcb11e6d7fa02e22cf40f9ee23d9cc1c062400000000000000000000000000000000c001a057216346b5252f6db63a2c78b5bc0a3697d2247377e9d9ef1b67849a87eb2413a066ea02477fc19671b3b626e3c4d33939a8ba43004f0a56e900efc1e580739d11" +} \ No newline at end of file diff --git a/tests/fixtures/validator-resignation.json b/tests/fixtures/validator-resignation.json index 5cc76fdd..c494f176 100644 --- a/tests/fixtures/validator-resignation.json +++ b/tests/fixtures/validator-resignation.json @@ -1,18 +1,18 @@ { - "data": { - "gasPrice": 5, - "network": 30, - "id": "c4407fe1d819a689c0ad0f7f2a872a15bf26a099865f1d221bddc69f217c4038", - "gasLimit": 1000000, - "nonce": "1", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "recipientAddress": "0x535b3d7a252fa034ed71f0c53ec0c6f784cb64e1", - "value": "0", - "data": "b85f5da2", - "v": 27, - "r": "52d016bfb61cb3b57d36a7444ce26d3c557b2acb31a10b5951fc3c9e8d2e49a6", - "s": "4940013218020780485b24cea9afbc6c93249286a308af33735c0c87bdeb4b5a" - }, - "serialized": "02f8671e018005830f424094535b3d7a252fa034ed71f0c53ec0c6f784cb64e18084b85f5da2c080a052d016bfb61cb3b57d36a7444ce26d3c557b2acb31a10b5951fc3c9e8d2e49a6a04940013218020780485b24cea9afbc6c93249286a308af33735c0c87bdeb4b5a" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x535B3D7A252fa034Ed71F0C53ec0C6F784cB64E1", + "value": "0", + "data": "b85f5da2", + "v": 28, + "r": "5670e5d314906eeaf92da15b55eaeabbb92814874f2fe6c72bcbee7e13e7ff40", + "s": "32a34c8438e441d10e83180b5a8a84cf1bfb92fc0fe8b53cd23dc4105631b83d", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "2dc3b976d8dee25e2ecf341c1493670d9d087cc338ed63f764c0eb9e28869dc3" + }, + "serialized": "02f86e822710018085012a05f20083030d4094535b3d7a252fa034ed71f0c53ec0c6f784cb64e18084b85f5da2c001a05670e5d314906eeaf92da15b55eaeabbb92814874f2fe6c72bcbee7e13e7ff40a032a34c8438e441d10e83180b5a8a84cf1bfb92fc0fe8b53cd23dc4105631b83d" +} \ No newline at end of file diff --git a/tests/fixtures/vote.json b/tests/fixtures/vote.json index be55d915..965df204 100644 --- a/tests/fixtures/vote.json +++ b/tests/fixtures/vote.json @@ -1,18 +1,18 @@ { - "data": { - "gasPrice": 5, - "network": 30, - "id": "991a3a63dc47be84d7982acb4c2aae488191373f31b8097e07d3ad95c0997e69", - "gasLimit": 1000000, - "nonce": "1", - "senderPublicKey": "023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3", - "senderAddress": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22", - "recipientAddress": "0x535b3d7a252fa034ed71f0c53ec0c6f784cb64e1", - "value": "0", - "data": "6dd7d8ea000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763", - "v": 27, - "r": "1e0b168c7520f39fb99f9bf1ea7c0086a3a9e78f215da5a7e997fd8ef5657f5f", - "s": "35019ef68773310144587b228dbc626e8cf3654377e92901f8d7f13119b0e09e" - }, - "serialized": "02f8871e018005830f424094535b3d7a252fa034ed71f0c53ec0c6f784cb64e180a46dd7d8ea000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763c080a01e0b168c7520f39fb99f9bf1ea7c0086a3a9e78f215da5a7e997fd8ef5657f5fa035019ef68773310144587b228dbc626e8cf3654377e92901f8d7f13119b0e09e" -} + "data": { + "network": 10000, + "nonce": "1", + "gasPrice": 5000000000, + "gasLimit": 200000, + "recipientAddress": "0x535B3D7A252fa034Ed71F0C53ec0C6F784cB64E1", + "value": "0", + "data": "6dd7d8ea000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763", + "v": 27, + "r": "67734fadb38bd9cd584d39fc08af836f15dd6337b05511b312add11a3586451a", + "s": "08ba89cec57c38b1e1f488d3507b9cbe1a21aa3f441482e62bd9c1eef61d3bd9", + "senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d", + "senderAddress": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd", + "id": "351114ee096ad8a02ddb7abee6f4fe283b8dadceff17157722d7a8153de710c1" + }, + "serialized": "02f88e822710018085012a05f20083030d4094535b3d7a252fa034ed71f0c53ec0c6f784cb64e180a46dd7d8ea000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763c080a067734fadb38bd9cd584d39fc08af836f15dd6337b05511b312add11a3586451aa008ba89cec57c38b1e1f488d3507b9cbe1a21aa3f441482e62bd9c1eef61d3bd9" +} \ No newline at end of file From 9214b03dbad7a4c4f999cac4bb71e6033accece5 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:09:03 +0000 Subject: [PATCH 02/25] keccak integration --- crypto/identity/private_key.py | 8 +++++++- crypto/utils/transaction_utils.py | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/crypto/identity/private_key.py b/crypto/identity/private_key.py index 6ff93a8f..647c269b 100644 --- a/crypto/identity/private_key.py +++ b/crypto/identity/private_key.py @@ -1,9 +1,15 @@ from binascii import hexlify from hashlib import sha256 from coincurve import PrivateKey as PvtKey +from Cryptodome.Hash import keccak from crypto.enums.constants import Constants +def keccak256(data: bytes) -> bytes: + """Keccak256 hash function""" + + return bytes.fromhex(keccak.new(data=data, digest_bits=256).hexdigest()) + class PrivateKey(object): def __init__(self, private_key: str): self.private_key = PvtKey.from_hex(private_key) @@ -31,7 +37,7 @@ def sign_compact(self, message: bytes) -> bytes: Returns: bytes: signature of the signed message """ - der = self.private_key.sign_recoverable(message) + der = self.private_key.sign_recoverable(message, hasher=keccak256) return bytes([der[64] + Constants.ETHEREUM_RECOVERY_ID_OFFSET.value]) + der[0:64] diff --git a/crypto/utils/transaction_utils.py b/crypto/utils/transaction_utils.py index 3cfbda5b..89b90648 100644 --- a/crypto/utils/transaction_utils.py +++ b/crypto/utils/transaction_utils.py @@ -1,6 +1,7 @@ from binascii import unhexlify import hashlib +from Cryptodome.Hash import keccak from crypto.enums.constants import Constants from crypto.utils.rlp_encoder import RlpEncoder @@ -42,7 +43,7 @@ def to_buffer(cls, transaction: dict, skip_signature: bool = False) -> bytes: @classmethod def to_hash(cls, transaction: dict, skip_signature: bool = False) -> str: - return hashlib.sha256(unhexlify(cls.to_buffer(transaction, skip_signature))).hexdigest() + return keccak.new(data=unhexlify(cls.to_buffer(transaction, skip_signature)), digest_bits=256).hexdigest() @classmethod def get_id(cls, transaction: dict) -> str: From ab8ce087854099cb18fbc173204e25252b761198 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:12:03 +0000 Subject: [PATCH 03/25] handle different contracts when deserializing --- crypto/transactions/deserializer.py | 45 ++++++++++++------- .../types/abstract_transaction.py | 13 ++---- .../types/username_registration.py | 5 ++- 3 files changed, 36 insertions(+), 27 deletions(-) diff --git a/crypto/transactions/deserializer.py b/crypto/transactions/deserializer.py index ab21002b..544cd57c 100644 --- a/crypto/transactions/deserializer.py +++ b/crypto/transactions/deserializer.py @@ -2,9 +2,12 @@ from binascii import unhexlify from typing import Optional from crypto.enums.constants import Constants +from crypto.enums.contract_abi_type import ContractAbiType from crypto.transactions.types.abstract_transaction import AbstractTransaction from crypto.transactions.types.transfer import Transfer from crypto.transactions.types.evm_call import EvmCall +from crypto.transactions.types.username_registration import UsernameRegistration +from crypto.transactions.types.username_resignation import UsernameResignation from crypto.transactions.types.vote import Vote from crypto.transactions.types.unvote import Unvote from crypto.transactions.types.validator_registration import ValidatorRegistration @@ -59,30 +62,40 @@ def guess_transaction_from_data(self, data: dict) -> AbstractTransaction: if data['value'] != '0': return Transfer(data) - payload_data = self.decode_payload(data) + consensus_payload_data = self.decode_payload(data) + if consensus_payload_data is not None: + function_name = consensus_payload_data.get('functionName') + if function_name == AbiFunction.VOTE.value: + return Vote(data) - if payload_data is None: - return EvmCall(data) + if function_name == AbiFunction.UNVOTE.value: + return Unvote(data) - function_name = payload_data.get('functionName') - if function_name == AbiFunction.VOTE.value: - return Vote(data) - elif function_name == AbiFunction.UNVOTE.value: - return Unvote(data) - elif function_name == AbiFunction.VALIDATOR_REGISTRATION.value: - return ValidatorRegistration(data) - elif function_name == AbiFunction.VALIDATOR_RESIGNATION.value: - return ValidatorResignation(data) - else: - return EvmCall(data) + if function_name == AbiFunction.VALIDATOR_REGISTRATION.value: + return ValidatorRegistration(data) - def decode_payload(self, data: dict) -> Optional[dict]: + if function_name == AbiFunction.VALIDATOR_RESIGNATION.value: + return ValidatorResignation(data) + + username_payload_data = self.decode_payload(data, ContractAbiType.USERNAMES) + if username_payload_data is not None: + function_name = username_payload_data.get('functionName') + if function_name == AbiFunction.USERNAME_REGISTRATION.value: + return UsernameRegistration(data) + + if function_name == AbiFunction.USERNAME_RESIGNATION.value: + return UsernameResignation(data) + + return EvmCall(data) + + @staticmethod + def decode_payload(data: dict, abi_type: ContractAbiType = ContractAbiType.CONSENSUS) -> Optional[dict]: payload = data.get('data', '') if payload == '': return None - decoder = AbiDecoder() + decoder = AbiDecoder(abi_type) try: return decoder.decode_function_data(payload) except Exception as e: diff --git a/crypto/transactions/types/abstract_transaction.py b/crypto/transactions/types/abstract_transaction.py index d66ed034..1618805e 100644 --- a/crypto/transactions/types/abstract_transaction.py +++ b/crypto/transactions/types/abstract_transaction.py @@ -3,6 +3,7 @@ from crypto.configuration.network import get_network from crypto.enums.constants import Constants +from crypto.enums.contract_abi_type import ContractAbiType from crypto.identity.address import address_from_public_key from crypto.identity.private_key import PrivateKey from crypto.utils.transaction_utils import TransactionUtils @@ -17,16 +18,10 @@ def __init__(self, data: Optional[dict] = None): def get_payload(self) -> str: return '' - def decode_payload(self, data: dict) -> Optional[dict]: - if 'data' not in data or data['data'] == '': - return None + def decode_payload(self, data: dict, abi_type: ContractAbiType = ContractAbiType.CONSENSUS) -> Optional[dict]: + from crypto.transactions.deserializer import Deserializer - payload = data['data'] - decoder = AbiDecoder() - - decoded_data = decoder.decode_function_data(payload) - - return decoded_data + return Deserializer.decode_payload(data, abi_type) def refresh_payload_data(self): self.data['data'] = self.get_payload().lstrip('0x') diff --git a/crypto/transactions/types/username_registration.py b/crypto/transactions/types/username_registration.py index 100333a8..12fb21a0 100644 --- a/crypto/transactions/types/username_registration.py +++ b/crypto/transactions/types/username_registration.py @@ -1,12 +1,13 @@ +from typing import Optional from crypto.enums.contract_abi_type import ContractAbiType from crypto.transactions.types.abstract_transaction import AbstractTransaction from crypto.utils.abi_encoder import AbiEncoder from crypto.enums.abi_function import AbiFunction class UsernameRegistration(AbstractTransaction): - def __init__(self, data: dict = None): + def __init__(self, data: Optional[dict] = None): data = data or {} - payload = self.decode_payload(data) + payload = self.decode_payload(data, ContractAbiType.USERNAMES) if payload: data['username'] = payload.get('args', [None])[0] if payload.get('args') else None From 79a35c39614190aa27525e9593fb8ff82c3cd75c Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:13:23 +0000 Subject: [PATCH 04/25] better handling of stripping 0x from data --- crypto/transactions/deserializer.py | 4 ++-- crypto/transactions/types/abstract_transaction.py | 2 +- crypto/transactions/types/validator_registration.py | 6 ++++-- crypto/utils/transaction_utils.py | 5 +++++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/crypto/transactions/deserializer.py b/crypto/transactions/deserializer.py index 544cd57c..125292ab 100644 --- a/crypto/transactions/deserializer.py +++ b/crypto/transactions/deserializer.py @@ -1,4 +1,3 @@ -import re from binascii import unhexlify from typing import Optional from crypto.enums.constants import Constants @@ -16,6 +15,7 @@ from crypto.enums.abi_function import AbiFunction from crypto.utils.abi_decoder import AbiDecoder from crypto.utils.rlp_decoder import RlpDecoder +from crypto.utils.transaction_utils import TransactionUtils class Deserializer: SIGNATURE_SIZE = 64 @@ -113,7 +113,7 @@ def parse_big_number(value: str) -> str: @staticmethod def parse_hex(value: str) -> str: - return re.sub(r'^0x', '', value) + return TransactionUtils.parse_hex_from_str(value) @staticmethod def parse_address(value: str) -> Optional[str]: diff --git a/crypto/transactions/types/abstract_transaction.py b/crypto/transactions/types/abstract_transaction.py index 1618805e..16b0fa96 100644 --- a/crypto/transactions/types/abstract_transaction.py +++ b/crypto/transactions/types/abstract_transaction.py @@ -24,7 +24,7 @@ def decode_payload(self, data: dict, abi_type: ContractAbiType = ContractAbiType return Deserializer.decode_payload(data, abi_type) def refresh_payload_data(self): - self.data['data'] = self.get_payload().lstrip('0x') + self.data['data'] = TransactionUtils.parse_hex_from_str(self.get_payload()) def get_id(self) -> str: return TransactionUtils.get_id(self.data) diff --git a/crypto/transactions/types/validator_registration.py b/crypto/transactions/types/validator_registration.py index a8b8bf80..a11f3cd6 100644 --- a/crypto/transactions/types/validator_registration.py +++ b/crypto/transactions/types/validator_registration.py @@ -1,13 +1,15 @@ +from typing import Optional from crypto.transactions.types.abstract_transaction import AbstractTransaction from crypto.utils.abi_encoder import AbiEncoder from crypto.enums.abi_function import AbiFunction +from crypto.utils.transaction_utils import TransactionUtils class ValidatorRegistration(AbstractTransaction): - def __init__(self, data: dict = None): + def __init__(self, data: Optional[dict] = None): data = data or {} payload = self.decode_payload(data) if payload: - data['validatorPublicKey'] = payload.get('args', [None])[0].lstrip('0x') if payload.get('args') else None + data['validatorPublicKey'] = TransactionUtils.parse_hex_from_str(payload.get('args', [None])[0].lstrip('0x')) if payload.get('args') else None super().__init__(data) def get_payload(self) -> str: diff --git a/crypto/utils/transaction_utils.py b/crypto/utils/transaction_utils.py index 89b90648..f8885e0f 100644 --- a/crypto/utils/transaction_utils.py +++ b/crypto/utils/transaction_utils.py @@ -1,5 +1,6 @@ from binascii import unhexlify import hashlib +import re from Cryptodome.Hash import keccak from crypto.enums.constants import Constants @@ -61,3 +62,7 @@ def to_be_array(value): return value raise TypeError("Unsupported type for to_be_array") + + @staticmethod + def parse_hex_from_str(value: str) -> str: + return re.sub(r'^0x', '', value) From feecff0ee2c176649e2b763650c31632280c8eaa Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:15:16 +0000 Subject: [PATCH 05/25] scrub --- crypto/transactions/types/validator_registration.py | 2 +- crypto/transactions/types/vote.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crypto/transactions/types/validator_registration.py b/crypto/transactions/types/validator_registration.py index a11f3cd6..718f93c3 100644 --- a/crypto/transactions/types/validator_registration.py +++ b/crypto/transactions/types/validator_registration.py @@ -16,4 +16,4 @@ def get_payload(self) -> str: if 'validatorPublicKey' not in self.data: return '' encoder = AbiEncoder() - return encoder.encode_function_call(AbiFunction.VALIDATOR_REGISTRATION.value, ['0x' + self.data['validatorPublicKey']]) \ No newline at end of file + return encoder.encode_function_call(AbiFunction.VALIDATOR_REGISTRATION.value, ['0x' + self.data['validatorPublicKey']]) diff --git a/crypto/transactions/types/vote.py b/crypto/transactions/types/vote.py index 93e8428a..27124ef0 100644 --- a/crypto/transactions/types/vote.py +++ b/crypto/transactions/types/vote.py @@ -1,9 +1,10 @@ +from typing import Optional from crypto.transactions.types.abstract_transaction import AbstractTransaction from crypto.utils.abi_encoder import AbiEncoder from crypto.enums.abi_function import AbiFunction class Vote(AbstractTransaction): - def __init__(self, data: dict = None): + def __init__(self, data: Optional[dict] = None): data = data or {} payload = self.decode_payload(data) if payload: @@ -15,4 +16,4 @@ def get_payload(self) -> str: if 'vote' not in self.data: return '' encoder = AbiEncoder() - return encoder.encode_function_call(AbiFunction.VOTE.value, [self.data['vote']]) \ No newline at end of file + return encoder.encode_function_call(AbiFunction.VOTE.value, [self.data['vote']]) From 15e922cf94b7bdfc018031831f13b89cc55e282c Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:15:35 +0000 Subject: [PATCH 06/25] update other fixture data --- tests/conftest.py | 2 +- tests/identity/conftest.py | 26 ++++++++++++++------------ tests/transactions/builder/conftest.py | 14 +++++++++++++- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index db71646b..6e3ae9f5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -36,7 +36,7 @@ def _load_transaction_fixture(fixture_name): def passphrase(): """Passphrase used for tests""" - return 'my super secret passphrase' + return 'found lobster oblige describe ready addict body brave live vacuum display salute lizard combine gift resemble race senior quality reunion proud tell adjust angle' @pytest.fixture def transaction_type_0(): diff --git a/tests/identity/conftest.py b/tests/identity/conftest.py index faa90bb6..ebda2616 100644 --- a/tests/identity/conftest.py +++ b/tests/identity/conftest.py @@ -6,12 +6,14 @@ def identity(): """ data = { 'data': { - 'private_key': 'bef98d4c0e58d0e4695560594f91a349421b7cdc3e63a560470ccb259f99f087', - 'public_key': '023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d3', - 'address': '0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22', - 'wif': 'SFyRYRYL1DddchRpuhp94hKN1tpYjzAEkLuUDAMjGJBkoAaz2RQk' - }, - 'passphrase': 'my super secret passphrase' + 'private_key': '50829dd3b7ffbe2df401d730b5e60cea7520ba3f3a18e5b1490707667fb43fae', + 'public_key': '0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d', + 'address': '0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd', + 'wif': 'UZYnRZ8qpeQWTLeCNzw93guWSdKLmr2vHEWGG4sNv7TJofL7TZvy', + 'validatorPublicKey': 'b209f4a7454ae17c5808991dffbf204c747b851f351d2ce72a6e18903d0e2f609e0328ebbc3fb97cd4d3660b4bc156f1', + 'validatorPrivateKey': '6ec4993df152b10e672567c1fdf854a4cee50708fa30986a7d9b259673099175', + }, + 'passphrase': 'found lobster oblige describe ready addict body brave live vacuum display salute lizard combine gift resemble race senior quality reunion proud tell adjust angle' } return data @@ -21,13 +23,13 @@ def sign_compact(): """ data = { 'data': { - 'serialized': '1b0567c4def813a66e03fa1cd499a27c6922698a67e25e0b38458d8f4bb0e581fc25fcdf9d110b82bde15bae4a49118deb83cfc3ec1656c2a29286d7836d328abe', - 'message': '02e31e018005825208946f0182a0cc707b055322ccf6d4cb6a5aff1aeb228405f5e10080c0', - 'v': 27, - 'r': '0567c4def813a66e03fa1cd499a27c6922698a67e25e0b38458d8f4bb0e581fc', - 's': '25fcdf9d110b82bde15bae4a49118deb83cfc3ec1656c2a29286d7836d328abe', + 'serialized': '1c104665257d4dea61c4654e74c6c0f6cd0a398905781c3040bea67dc641a66da046d718d04b2331f3b0561808549ed3f3f0d867a284acf6b334869078df7a9136', + 'message': '02ea822710018085012a05f200825208946f0182a0cc707b055322ccf6d4cb6a5aff1aeb228405f5e10080c0', + 'v': 28, + 'r': '104665257d4dea61c4654e74c6c0f6cd0a398905781c3040bea67dc641a66da0', + 's': '46d718d04b2331f3b0561808549ed3f3f0d867a284acf6b334869078df7a9136', }, - 'passphrase': 'my super secret passphrase' + 'passphrase': 'found lobster oblige describe ready addict body brave live vacuum display salute lizard combine gift resemble race senior quality reunion proud tell adjust angle' } return data diff --git a/tests/transactions/builder/conftest.py b/tests/transactions/builder/conftest.py index 374172f8..c819610c 100644 --- a/tests/transactions/builder/conftest.py +++ b/tests/transactions/builder/conftest.py @@ -4,4 +4,16 @@ def passphrase(): """Passphrase used for tests""" - return 'my super secret passphrase' + return 'found lobster oblige describe ready addict body brave live vacuum display salute lizard combine gift resemble race senior quality reunion proud tell adjust angle' + +@pytest.fixture +def validator_public_key(): + """BLS Public used for validator tests""" + + return '30954f46d6097a1d314e900e66e11e0dad0a57cd03e04ec99f0dedd1c765dcb11e6d7fa02e22cf40f9ee23d9cc1c0624' + +@pytest.fixture +def username(): + """Username used for tests""" + + return 'fixture' From 029b9bea34bd4d6be6361a8dc9ad7fe7dcea7dbd Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:16:05 +0000 Subject: [PATCH 07/25] fix wif test --- tests/identity/test_wif.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/identity/test_wif.py b/tests/identity/test_wif.py index ddb7b936..ec3b12e6 100644 --- a/tests/identity/test_wif.py +++ b/tests/identity/test_wif.py @@ -1,6 +1,10 @@ +from crypto.configuration.network import set_network from crypto.identity.wif import wif_from_passphrase +from crypto.networks.testnet import Testnet def test_wif_from_passphrase(identity): + set_network(Testnet) + result = wif_from_passphrase(identity['passphrase']) assert result == identity['data']['wif'] From abe3f34221f40ef50432a2947074f60940cd68f5 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:16:25 +0000 Subject: [PATCH 08/25] move hardcoded tx values to fixtures --- .../builder/test_username_registration_builder.py | 4 ++-- .../builder/test_validator_registration_builder.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/transactions/builder/test_username_registration_builder.py b/tests/transactions/builder/test_username_registration_builder.py index c8536466..5befa727 100644 --- a/tests/transactions/builder/test_username_registration_builder.py +++ b/tests/transactions/builder/test_username_registration_builder.py @@ -1,7 +1,7 @@ from crypto.exceptions import InvalidUsernameException from crypto.transactions.builder.username_registration_builder import UsernameRegistrationBuilder -def test_username_registration_transaction(passphrase, load_transaction_fixture): +def test_username_registration_transaction(passphrase, username, load_transaction_fixture): fixture = load_transaction_fixture('username-registration') builder = ( @@ -10,7 +10,7 @@ def test_username_registration_transaction(passphrase, load_transaction_fixture) .nonce(fixture['data']['nonce']) .network(fixture['data']['network']) .gas_limit(fixture['data']['gasLimit']) - .username('php') + .username(username) .sign(passphrase) ) diff --git a/tests/transactions/builder/test_validator_registration_builder.py b/tests/transactions/builder/test_validator_registration_builder.py index 284cd43a..34d5b80d 100644 --- a/tests/transactions/builder/test_validator_registration_builder.py +++ b/tests/transactions/builder/test_validator_registration_builder.py @@ -1,6 +1,6 @@ from crypto.transactions.builder.validator_registration_builder import ValidatorRegistrationBuilder -def test_validator_registration_transaction(passphrase, load_transaction_fixture): +def test_validator_registration_transaction(passphrase, validator_public_key, load_transaction_fixture): fixture = load_transaction_fixture('validator-registration') builder = ( @@ -9,11 +9,12 @@ def test_validator_registration_transaction(passphrase, load_transaction_fixture .nonce(fixture['data']['nonce']) .network(fixture['data']['network']) .gas_limit(fixture['data']['gasLimit']) - .validator_public_key('954f46d6097a1d314e900e66e11e0dad0a57cd03e04ec99f0dedd1c765dcb11e6d7fa02e22cf40f9ee23d9cc1c0624bd') + .validator_public_key(validator_public_key) .recipient_address(fixture['data']['recipientAddress']) .sign(passphrase) ) + assert builder.transaction.serialize().hex() == fixture['serialized'] assert builder.transaction.data['gasPrice'] == fixture['data']['gasPrice'] assert builder.transaction.data['nonce'] == fixture['data']['nonce'] assert builder.transaction.data['network'] == fixture['data']['network'] From 3348de0f1fd89875127434fe61ee92e0c297d3eb Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:18:18 +0000 Subject: [PATCH 09/25] deserialize test other contract transactions --- tests/transactions/test_deserializer.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/transactions/test_deserializer.py b/tests/transactions/test_deserializer.py index 4c4c44ba..f5b1d895 100644 --- a/tests/transactions/test_deserializer.py +++ b/tests/transactions/test_deserializer.py @@ -1,5 +1,7 @@ from crypto.transactions.deserializer import Deserializer from crypto.transactions.types.transfer import Transfer +from crypto.transactions.types.username_registration import UsernameRegistration +from crypto.transactions.types.username_resignation import UsernameResignation from crypto.transactions.types.vote import Vote from crypto.transactions.types.unvote import Unvote from crypto.transactions.types.validator_registration import ValidatorRegistration @@ -27,7 +29,7 @@ def test_deserialize_vote(load_transaction_fixture): assert isinstance(transaction, Vote) assert transaction.data['vote'].lower() == '0xc3bbe9b1cee1ff85ad72b87414b0e9b7f2366763' - assert transaction.data['id'] == '991a3a63dc47be84d7982acb4c2aae488191373f31b8097e07d3ad95c0997e69' + assert transaction.data['id'] == fixture['data']['id'] def test_deserialize_unvote(load_transaction_fixture): fixture = load_transaction_fixture('unvote') @@ -47,6 +49,18 @@ def test_deserialize_validator_resignation(load_transaction_fixture): assert isinstance(transaction, ValidatorResignation) +def test_deserialize_username_registration(load_transaction_fixture): + fixture = load_transaction_fixture('username-registration') + transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) + + assert isinstance(transaction, UsernameRegistration) + +def test_deserialize_username_resignation(load_transaction_fixture): + fixture = load_transaction_fixture('username-resignation') + transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) + + assert isinstance(transaction, UsernameResignation) + def test_parse_number(): assert Deserializer.parse_number('0x01') == 1 assert Deserializer.parse_number('0x0100') == 256 From a1064a1c8f6b7c2d228513a032d802ee56973c7c Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:18:36 +0000 Subject: [PATCH 10/25] update rpl decoder expectations --- tests/utils/test_rpl_decoder.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/utils/test_rpl_decoder.py b/tests/utils/test_rpl_decoder.py index e896c426..2dc000c1 100644 --- a/tests/utils/test_rpl_decoder.py +++ b/tests/utils/test_rpl_decoder.py @@ -7,18 +7,18 @@ def test_decode_function_call(load_transaction_fixture): decoded_rlp = RlpDecoder.decode('0x' + fixture['serialized'][2:]) assert len(decoded_rlp) == 12 - assert decoded_rlp[0] == '0x1e' + assert decoded_rlp[0] == '0x2710' assert decoded_rlp[1] == '0x01' assert decoded_rlp[2] == '0x' - assert decoded_rlp[3] == '0x05' + assert decoded_rlp[3] == '0x012a05f200' assert decoded_rlp[4] == '0x5208' assert decoded_rlp[5] == '0x6f0182a0cc707b055322ccf6d4cb6a5aff1aeb22' assert decoded_rlp[6] == '0x05f5e100' assert decoded_rlp[7] == '0x' assert decoded_rlp[8] == [] - assert decoded_rlp[9] == '0x' - assert decoded_rlp[10] == '0x0567c4def813a66e03fa1cd499a27c6922698a67e25e0b38458d8f4bb0e581fc' - assert decoded_rlp[11] == '0x25fcdf9d110b82bde15bae4a49118deb83cfc3ec1656c2a29286d7836d328abe' + assert decoded_rlp[9] == '0x01' + assert decoded_rlp[10] == '0x104665257d4dea61c4654e74c6c0f6cd0a398905781c3040bea67dc641a66da0' + assert decoded_rlp[11] == '0x46d718d04b2331f3b0561808549ed3f3f0d867a284acf6b334869078df7a9136' def test_decoding_str(): decoded = RlpDecoder.decode('0x8774657374696e67') From b144d17660afc008fed344fef3728ae65112866e Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:25:35 +0000 Subject: [PATCH 11/25] remove unused transaction class --- crypto/transactions/transaction.py | 234 ----------------------------- 1 file changed, 234 deletions(-) delete mode 100644 crypto/transactions/transaction.py diff --git a/crypto/transactions/transaction.py b/crypto/transactions/transaction.py deleted file mode 100644 index 306d06d5..00000000 --- a/crypto/transactions/transaction.py +++ /dev/null @@ -1,234 +0,0 @@ -import json -from hashlib import sha256 -from typing import Optional - -from binary.hex.writer import write_high -from binary.unsigned_integer.writer import write_bit8 - -from crypto.constants import TRANSACTION_VALIDATOR_REGISTRATION, TRANSACTION_MULTI_SIGNATURE_REGISTRATION, TRANSACTION_VOTE -from crypto.exceptions import ArkInvalidTransaction -from crypto.transactions.serializer import Serializer -from crypto.transactions.signature import Signature - -TRANSACTION_ATTRIBUTES = { - 'amount': 0, - 'asset': dict, - 'fee': None, - 'id': None, - 'network': None, - 'recipientId': None, - 'secondSignature': None, - 'senderPublicKey': None, - 'signature': None, - 'signatures': None, - 'signSignature': None, - 'nonce': None, - 'type': None, - 'typeGroup': None, - 'vendorField': None, - 'vendorFieldHex': None, - 'version': None, - 'lockTransactionId': None, - 'lockSecret': None, - 'expiration': None -} - -class Transaction(object): - id: str - type: int - fee: int - nonce: int - typeGroup: int - signatures: list - version: int - expiration: int - type: int - amount: int - recipientId: str - senderPublicKey: str - asset: dict - vendorField: Optional[bytes] - vendorFieldHex: bytes - network: int - - def __init__(self, **kwargs): - for attribute, attribute_value in TRANSACTION_ATTRIBUTES.items(): - if callable(attribute_value): - attribute_value = attribute_value() - if attribute in kwargs: - attribute_value = kwargs[attribute] - setattr(self, attribute, attribute_value) - - def get_id(self): - """Convert the byte representation to a unique identifier - - Returns: - str: - """ - return sha256(self.to_bytes(skip_signature=False, skip_second_signature=False, skip_multi_signature=False)).hexdigest() - - def to_dict(self): - """Convert the transaction into a dictionary representation - - Returns: - dict: only includes values that are set - """ - data = {} - for key in TRANSACTION_ATTRIBUTES.keys(): - attribute = getattr(self, key, None) - if attribute is None: - continue - # todo: get rid of the bytes check and handle this outside of the to_dict function - data[key] = attribute.decode() if isinstance(attribute, bytes) else attribute - return data - - def to_json(self): - data = self.to_dict() - return json.dumps(data) - - def to_bytes(self, skip_signature=True, skip_second_signature=True, skip_multi_signature=True) -> bytes: - """Convert the transaction to its byte representation - - Args: - skip_signature (bool, optional): do you want to skip the signature - skip_second_signature (bool, optional): do you want to skip the 2nd signature - skip_multi_signature (bool, optional): do you want to skip multi signature - - Returns: - bytes: bytes representation of the transaction - """ - return Serializer(self.to_dict()).serialize_bytes(skip_signature=skip_signature, - skip_second_signature=skip_second_signature, - skip_multi_signature=skip_multi_signature) - - def parse_signatures(self, serialized: str, start_offset: int): - """Parse the signature, second signature and multi signatures - - Args: - serialized (str): parses a given serialized string - start_offset (int): - """ - - signature_end_offset = start_offset + (64 * 2) - - if len(serialized) - signature_end_offset % 65 != 0: - self.signature = serialized[start_offset:signature_end_offset] - - second_signature_end_offset = signature_end_offset + (64 * 2) - if len(serialized) - signature_end_offset > 0 and (len(serialized) - signature_end_offset) % 64 == 0: - self.signSignature = serialized[signature_end_offset:second_signature_end_offset] - - if len(serialized) - second_signature_end_offset > 0 and (len(serialized) - signature_end_offset) % 65 == 0: - multi_sig_part = serialized[signature_end_offset:] - index = 0 - index_size = 2 - signature_size = 128 - - while index != len(multi_sig_part): - signature_index = multi_sig_part[index:index + index_size] - signature = multi_sig_part[index + index_size:index + index_size + signature_size] - index += index_size + signature_size - signature_formatted = signature_index + signature - self.signatures.append(signature_formatted) - - def serialize(self, skip_signature=True, skip_second_signature=True, skip_multi_signature=True) -> str: - """Perform AIP11 compliant serialization. - - Args: - skip_signature (bool, optional): do you want to skip the signature - skip_second_signature (bool, optional): do you want to skip the 2nd signature - skip_multi_signature (bool, optional): do you want to skip multi signature - - Returns: - str: Serialized string - """ - data = self.to_dict() - - return Serializer(data).serialize(skip_signature, skip_second_signature, skip_multi_signature) - - @staticmethod - def deserialize(serialized: bytes): - """Perform AIP11 compliant deserialization. - - Args: - serialized (bytes): parses a given serialized string - - Returns: - crypto.transactions.transaction.Transaction: Transaction - """ - from crypto.transactions.deserializer import Deserializer - - return Deserializer(serialized).deserialize() - - def verify_schnorr(self): - """Verify the transaction. Method will raise an exception if invalid, if it's valid it will - returns True - """ - is_valid = Signature.verify(self.signature, self.to_bytes(), self.senderPublicKey) - - if not is_valid: - raise ArkInvalidTransaction('Transaction could not be verified') - - return is_valid - - def verify_secondsig_schnorr(self, secondPublicKey: bytes): - """Verify the transaction. Method will raise an exception if invalid, if it's valid it will - returns True - """ - is_valid = Signature.verify(self.signSignature, self.to_bytes(False, True), secondPublicKey) - - if not is_valid: - raise ArkInvalidTransaction('Transaction could not be verified') - - return is_valid - - def verify_multisig_schnorr(self): - """Verify the multisignatures transaction. Method will raise an exception if invalid, it will - returns True - """ - is_valid = Signature.verify(self.signature, self.to_bytes(True, True, False), self.senderPublicKey) - - if not is_valid: - raise ArkInvalidTransaction('Transaction could not be verified') - - return is_valid - - def _handle_transaction_type(self, bytes_data) -> bytes: - """Handled each transaction type differently - - Args: - bytes_data (bytes): input the bytes data to which you want to append new bytes - - Raises: - NotImplementedError: raised only if the child transaction doesn't implement this - required method - """ - if self.type == TRANSACTION_VALIDATOR_REGISTRATION: - bytes_data += self.asset['validator']['username'].encode() - elif self.type == TRANSACTION_VOTE: - bytes_data += ''.join(self.asset['votes']).encode() - elif self.type == TRANSACTION_MULTI_SIGNATURE_REGISTRATION: - bytes_data += write_bit8(self.asset['multiSignature']['min']) - bytes_data += ''.join(self.asset['multiSignature']['publicKeys']).encode() - - return bytes_data - - def _handle_signature(self, bytes_data, skip_signature, skip_second_signature, skip_multi_signature) -> bytes: - """Internal method, used to handle the signature - - Args: - bytes_data (bytes): input the bytes data to which you want to append new bytes from - signature - skip_signature (bool): whether you want to skip it or not - skip_second_signature (bool): whether you want to skip it or not - - Returns: - bytes: bytes string - """ - if not skip_signature and self.signature: - bytes_data += write_high(self.signature) - if not skip_second_signature and self.signSignature: - bytes_data += write_high(self.signSignature) - if not skip_multi_signature and self.signatures: - bytes_data += write_high(self.signatures) - return bytes_data From a8a17a646ef5de9e0ef7c147cfbc3e5550d0aa55 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:33:12 +0000 Subject: [PATCH 12/25] remove additional lstrips --- crypto/transactions/builder/evm_call_builder.py | 7 +++++-- crypto/transactions/types/validator_registration.py | 2 +- crypto/utils/transaction_utils.py | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/crypto/transactions/builder/evm_call_builder.py b/crypto/transactions/builder/evm_call_builder.py index 4a541dd7..7b30095d 100644 --- a/crypto/transactions/builder/evm_call_builder.py +++ b/crypto/transactions/builder/evm_call_builder.py @@ -1,11 +1,14 @@ from crypto.transactions.builder.base import AbstractTransactionBuilder from crypto.transactions.types.evm_call import EvmCall +from crypto.utils.transaction_utils import TransactionUtils class EvmCallBuilder(AbstractTransactionBuilder): def payload(self, payload: str): - payload = payload.lstrip('0x') # Remove '0x' prefix if present + payload = TransactionUtils.parse_hex_from_str(payload) # Remove '0x' prefix if present + self.transaction.data['data'] = payload + return self def get_transaction_instance(self, data: dict): - return EvmCall(data) \ No newline at end of file + return EvmCall(data) diff --git a/crypto/transactions/types/validator_registration.py b/crypto/transactions/types/validator_registration.py index 718f93c3..ecaf86ee 100644 --- a/crypto/transactions/types/validator_registration.py +++ b/crypto/transactions/types/validator_registration.py @@ -9,7 +9,7 @@ def __init__(self, data: Optional[dict] = None): data = data or {} payload = self.decode_payload(data) if payload: - data['validatorPublicKey'] = TransactionUtils.parse_hex_from_str(payload.get('args', [None])[0].lstrip('0x')) if payload.get('args') else None + data['validatorPublicKey'] = TransactionUtils.parse_hex_from_str(payload.get('args', [None])[0]) if payload.get('args') else None super().__init__(data) def get_payload(self) -> str: diff --git a/crypto/utils/transaction_utils.py b/crypto/utils/transaction_utils.py index f8885e0f..de663935 100644 --- a/crypto/utils/transaction_utils.py +++ b/crypto/utils/transaction_utils.py @@ -10,7 +10,7 @@ class TransactionUtils: @classmethod def to_buffer(cls, transaction: dict, skip_signature: bool = False) -> bytes: # Process recipientAddress - hex_address = transaction.get('recipientAddress', '').lstrip('0x') + hex_address = cls.parse_hex_from_str(transaction.get('recipientAddress', '')) # Pad with leading zero if necessary if len(hex_address) % 2 != 0: @@ -27,7 +27,7 @@ def to_buffer(cls, transaction: dict, skip_signature: bool = False) -> bytes: cls.to_be_array(int(transaction['gasLimit'])), recipient_address, cls.to_be_array(int(transaction.get('value', 0))), - bytes.fromhex(transaction.get('data', '').lstrip('0x')) if transaction.get('data') else b'', + bytes.fromhex(cls.parse_hex_from_str(transaction.get('data', ''))) if transaction.get('data') else b'', [], ] From ee8ea60a3fee8249dd4c305f29b3bc608a5da0ba Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:45:18 +0000 Subject: [PATCH 13/25] made AbstractTransaction decode_payload method static --- crypto/transactions/types/abstract_transaction.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crypto/transactions/types/abstract_transaction.py b/crypto/transactions/types/abstract_transaction.py index 16b0fa96..c400cac5 100644 --- a/crypto/transactions/types/abstract_transaction.py +++ b/crypto/transactions/types/abstract_transaction.py @@ -18,11 +18,6 @@ def __init__(self, data: Optional[dict] = None): def get_payload(self) -> str: return '' - def decode_payload(self, data: dict, abi_type: ContractAbiType = ContractAbiType.CONSENSUS) -> Optional[dict]: - from crypto.transactions.deserializer import Deserializer - - return Deserializer.decode_payload(data, abi_type) - def refresh_payload_data(self): self.data['data'] = TransactionUtils.parse_hex_from_str(self.get_payload()) @@ -100,3 +95,9 @@ def get_signature(self): return bytes.fromhex(r) + bytes.fromhex(s) + bytes([recover_id]) return None + + @staticmethod + def decode_payload(data: dict, abi_type: ContractAbiType = ContractAbiType.CONSENSUS) -> Optional[dict]: + from crypto.transactions.deserializer import Deserializer + + return Deserializer.decode_payload(data, abi_type) From 5655d2ddf62cacb6c130d905fa4e1f08f4d140db Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:51:28 +0000 Subject: [PATCH 14/25] pass payload to tx type constructor to prevent double-up of decoding payload --- crypto/transactions/deserializer.py | 6 +++--- crypto/transactions/types/username_registration.py | 6 ++++-- crypto/transactions/types/validator_registration.py | 7 +++++-- crypto/transactions/types/vote.py | 6 ++++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/crypto/transactions/deserializer.py b/crypto/transactions/deserializer.py index 125292ab..55b2df2e 100644 --- a/crypto/transactions/deserializer.py +++ b/crypto/transactions/deserializer.py @@ -66,13 +66,13 @@ def guess_transaction_from_data(self, data: dict) -> AbstractTransaction: if consensus_payload_data is not None: function_name = consensus_payload_data.get('functionName') if function_name == AbiFunction.VOTE.value: - return Vote(data) + return Vote(data, consensus_payload_data) if function_name == AbiFunction.UNVOTE.value: return Unvote(data) if function_name == AbiFunction.VALIDATOR_REGISTRATION.value: - return ValidatorRegistration(data) + return ValidatorRegistration(data, consensus_payload_data) if function_name == AbiFunction.VALIDATOR_RESIGNATION.value: return ValidatorResignation(data) @@ -81,7 +81,7 @@ def guess_transaction_from_data(self, data: dict) -> AbstractTransaction: if username_payload_data is not None: function_name = username_payload_data.get('functionName') if function_name == AbiFunction.USERNAME_REGISTRATION.value: - return UsernameRegistration(data) + return UsernameRegistration(data, username_payload_data) if function_name == AbiFunction.USERNAME_RESIGNATION.value: return UsernameResignation(data) diff --git a/crypto/transactions/types/username_registration.py b/crypto/transactions/types/username_registration.py index 12fb21a0..3fcd8583 100644 --- a/crypto/transactions/types/username_registration.py +++ b/crypto/transactions/types/username_registration.py @@ -5,9 +5,11 @@ from crypto.enums.abi_function import AbiFunction class UsernameRegistration(AbstractTransaction): - def __init__(self, data: Optional[dict] = None): + def __init__(self, data: Optional[dict] = None, payload: Optional[dict] = None): data = data or {} - payload = self.decode_payload(data, ContractAbiType.USERNAMES) + if payload is None: + payload = self.decode_payload(data, ContractAbiType.USERNAMES) + if payload: data['username'] = payload.get('args', [None])[0] if payload.get('args') else None diff --git a/crypto/transactions/types/validator_registration.py b/crypto/transactions/types/validator_registration.py index ecaf86ee..28123468 100644 --- a/crypto/transactions/types/validator_registration.py +++ b/crypto/transactions/types/validator_registration.py @@ -5,9 +5,12 @@ from crypto.utils.transaction_utils import TransactionUtils class ValidatorRegistration(AbstractTransaction): - def __init__(self, data: Optional[dict] = None): + def __init__(self, data: Optional[dict] = None, payload: Optional[dict] = None): data = data or {} - payload = self.decode_payload(data) + + if payload is None: + payload = self.decode_payload(data) + if payload: data['validatorPublicKey'] = TransactionUtils.parse_hex_from_str(payload.get('args', [None])[0]) if payload.get('args') else None super().__init__(data) diff --git a/crypto/transactions/types/vote.py b/crypto/transactions/types/vote.py index 27124ef0..261f2984 100644 --- a/crypto/transactions/types/vote.py +++ b/crypto/transactions/types/vote.py @@ -4,9 +4,11 @@ from crypto.enums.abi_function import AbiFunction class Vote(AbstractTransaction): - def __init__(self, data: Optional[dict] = None): + def __init__(self, data: Optional[dict] = None, payload: Optional[dict] = None): data = data or {} - payload = self.decode_payload(data) + if payload is None: + payload = self.decode_payload(data) + if payload: data['vote'] = payload.get('args', [None])[0] if payload.get('args') else None From 3aa900c358b77365ab66ff95dbe7cca70c1ce6ca Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:52:06 +0000 Subject: [PATCH 15/25] update multipayment address --- crypto/enums/contract_addresses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/enums/contract_addresses.py b/crypto/enums/contract_addresses.py index ac0b0510..c7379dec 100644 --- a/crypto/enums/contract_addresses.py +++ b/crypto/enums/contract_addresses.py @@ -2,5 +2,5 @@ class ContractAddresses(Enum): CONSENSUS = '0x535B3D7A252fa034Ed71F0C53ec0C6F784cB64E1' - MULTIPAYMENT = '0x83769BeEB7e5405ef0B7dc3C66C43E3a51A6d27f' + MULTIPAYMENT = '0x00EFd0D4639191C49908A7BddbB9A11A994A8527' USERNAMES = '0x2c1DE3b4Dbb4aDebEbB5dcECAe825bE2a9fc6eb6' From ec8f0e00fb790f3745b4c626b4d9641a133f9bff Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:52:22 +0000 Subject: [PATCH 16/25] fix check for valid address --- crypto/utils/abi_base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/utils/abi_base.py b/crypto/utils/abi_base.py index d810c551..6812bf31 100644 --- a/crypto/utils/abi_base.py +++ b/crypto/utils/abi_base.py @@ -39,7 +39,8 @@ def strip_hex_prefix(self, hex_str): def is_valid_address(self, address): # Compute the checksum address and compare computed_checksum_address = get_checksum_address(address.lower()) - return address == computed_checksum_address + + return address.lower() == computed_checksum_address.lower() def keccak256(self, input_str): k = keccak.new(digest_bits=256) From 9cab1f84652c33ef5c5c2293eed4311d355f43e5 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:52:37 +0000 Subject: [PATCH 17/25] add multipayment abi --- crypto/utils/abi/json/Abi.Multipayment.json | 110 ++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 crypto/utils/abi/json/Abi.Multipayment.json diff --git a/crypto/utils/abi/json/Abi.Multipayment.json b/crypto/utils/abi/json/Abi.Multipayment.json new file mode 100644 index 00000000..b2ab88ce --- /dev/null +++ b/crypto/utils/abi/json/Abi.Multipayment.json @@ -0,0 +1,110 @@ +{ + "abi": [ + { + "type": "function", + "name": "pay", + "inputs": [ + { + "name": "recipients", + "type": "address[]", + "internalType": "address payable[]" + }, + { + "name": "amounts", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { "type": "error", "name": "FailedToSendEther", "inputs": [] }, + { "type": "error", "name": "InvalidValue", "inputs": [] }, + { + "type": "error", + "name": "RecipientsAndAmountsMismatch", + "inputs": [] + } + ], + "bytecode": { + "object": "0x6080604052348015600e575f5ffd5b506102c98061001c5f395ff3fe60806040526004361061001d575f3560e01c8063084ce70814610021575b5f5ffd5b61003461002f3660046101c1565b610036565b005b828114610056576040516366d5293b60e11b815260040160405180910390fd5b5f805b8281101561008f578383828181106100735761007361022d565b90506020020135826100859190610241565b9150600101610059565b508034146100b057604051632a9ffab760e21b815260040160405180910390fd5b5f5b84811015610171575f8686838181106100cd576100cd61022d565b90506020020160208101906100e29190610266565b6001600160a01b03168585848181106100fd576100fd61022d565b905060200201356040515f6040518083038185875af1925050503d805f8114610141576040519150601f19603f3d011682016040523d82523d5f602084013e610146565b606091505b505090508061016857604051630dcf35db60e41b815260040160405180910390fd5b506001016100b2565b505050505050565b5f5f83601f840112610189575f5ffd5b50813567ffffffffffffffff8111156101a0575f5ffd5b6020830191508360208260051b85010111156101ba575f5ffd5b9250929050565b5f5f5f5f604085870312156101d4575f5ffd5b843567ffffffffffffffff8111156101ea575f5ffd5b6101f687828801610179565b909550935050602085013567ffffffffffffffff811115610215575f5ffd5b61022187828801610179565b95989497509550505050565b634e487b7160e01b5f52603260045260245ffd5b8082018082111561026057634e487b7160e01b5f52601160045260245ffd5b92915050565b5f60208284031215610276575f5ffd5b81356001600160a01b038116811461028c575f5ffd5b939250505056fea2646970667358221220bfee9113d4628767f3e4ea5baeb21f9c3bd88ea4c440d0a915dae090d37cd9a664736f6c634300081b0033", + "sourceMap": "81:836:23:-:0;;;;;;;;;;;;;;;;;;;", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x60806040526004361061001d575f3560e01c8063084ce70814610021575b5f5ffd5b61003461002f3660046101c1565b610036565b005b828114610056576040516366d5293b60e11b815260040160405180910390fd5b5f805b8281101561008f578383828181106100735761007361022d565b90506020020135826100859190610241565b9150600101610059565b508034146100b057604051632a9ffab760e21b815260040160405180910390fd5b5f5b84811015610171575f8686838181106100cd576100cd61022d565b90506020020160208101906100e29190610266565b6001600160a01b03168585848181106100fd576100fd61022d565b905060200201356040515f6040518083038185875af1925050503d805f8114610141576040519150601f19603f3d011682016040523d82523d5f602084013e610146565b606091505b505090508061016857604051630dcf35db60e41b815260040160405180910390fd5b506001016100b2565b505050505050565b5f5f83601f840112610189575f5ffd5b50813567ffffffffffffffff8111156101a0575f5ffd5b6020830191508360208260051b85010111156101ba575f5ffd5b9250929050565b5f5f5f5f604085870312156101d4575f5ffd5b843567ffffffffffffffff8111156101ea575f5ffd5b6101f687828801610179565b909550935050602085013567ffffffffffffffff811115610215575f5ffd5b61022187828801610179565b95989497509550505050565b634e487b7160e01b5f52603260045260245ffd5b8082018082111561026057634e487b7160e01b5f52601160045260245ffd5b92915050565b5f60208284031215610276575f5ffd5b81356001600160a01b038116811461028c575f5ffd5b939250505056fea2646970667358221220bfee9113d4628767f3e4ea5baeb21f9c3bd88ea4c440d0a915dae090d37cd9a664736f6c634300081b0033", + "sourceMap": "81:836:23:-:0;;;;;;;;;;;;;;;;;;;;;209:706;;;;;;:::i;:::-;;:::i;:::-;;;318:35;;;314:103;;376:30;;-1:-1:-1;;;376:30:23;;;;;;;;;;;314:103;492:13;;519:89;539:18;;;519:89;;;587:7;;595:1;587:10;;;;;;;:::i;:::-;;;;;;;578:19;;;;;:::i;:::-;;-1:-1:-1;559:3:23;;519:89;;;;634:5;621:9;:18;617:70;;662:14;;-1:-1:-1;;;662:14:23;;;;;;;;;;;617:70;702:9;697:212;717:21;;;697:212;;;760:9;774:10;;785:1;774:13;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;774:18:23;800:7;;808:1;800:10;;;;;;;:::i;:::-;;;;;;;774:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;759:56;;;834:4;829:70;;865:19;;-1:-1:-1;;;865:19:23;;;;;;;;;;;829:70;-1:-1:-1;740:3:23;;697:212;;;;304:611;209:706;;;;:::o;14:375:25:-;85:8;95:6;149:3;142:4;134:6;130:17;126:27;116:55;;167:1;164;157:12;116:55;-1:-1:-1;190:20:25;;233:18;222:30;;219:50;;;265:1;262;255:12;219:50;302:4;294:6;290:17;278:29;;362:3;355:4;345:6;342:1;338:14;330:6;326:27;322:38;319:47;316:67;;;379:1;376;369:12;316:67;14:375;;;;;:::o;394:792::-;524:6;532;540;548;601:2;589:9;580:7;576:23;572:32;569:52;;;617:1;614;607:12;569:52;657:9;644:23;690:18;682:6;679:30;676:50;;;722:1;719;712:12;676:50;761:78;831:7;822:6;811:9;807:22;761:78;:::i;:::-;858:8;;-1:-1:-1;735:104:25;-1:-1:-1;;946:2:25;931:18;;918:32;975:18;962:32;;959:52;;;1007:1;1004;997:12;959:52;1046:80;1118:7;1107:8;1096:9;1092:24;1046:80;:::i;:::-;394:792;;;;-1:-1:-1;1145:8:25;-1:-1:-1;;;;394:792:25:o;1191:127::-;1252:10;1247:3;1243:20;1240:1;1233:31;1283:4;1280:1;1273:15;1307:4;1304:1;1297:15;1323:222;1388:9;;;1409:10;;;1406:133;;;1461:10;1456:3;1452:20;1449:1;1442:31;1496:4;1493:1;1486:15;1524:4;1521:1;1514:15;1406:133;1323:222;;;;:::o;1550:294::-;1617:6;1670:2;1658:9;1649:7;1645:23;1641:32;1638:52;;;1686:1;1683;1676:12;1638:52;1712:23;;-1:-1:-1;;;;;1764:31:25;;1754:42;;1744:70;;1810:1;1807;1800:12;1744:70;1833:5;1550:294;-1:-1:-1;;;1550:294:25:o", + "linkReferences": {} + }, + "methodIdentifiers": { "pay(address[],uint256[])": "084ce708" }, + "rawMetadata": "{\"compiler\":{\"version\":\"0.8.27+commit.40a35a09\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"FailedToSendEther\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientsAndAmountsMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address payable[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"pay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/multi-payment/MultiPayment.sol\":\"MultiPayment\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@contracts/=src/\",\":@forge-std/=lib/forge-std/src/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/\",\":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/\",\":openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/\",\":solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/\"]},\"sources\":{\"src/multi-payment/MultiPayment.sol\":{\"keccak256\":\"0x804a5823ffdb1866bc5f42a0fe3688c8e153da92e279c7b79aa3d73472a1ce35\",\"license\":\"GNU GENERAL PUBLIC LICENSE\",\"urls\":[\"bzz-raw://43df2e2ee0c0a76dd4ee8bd6cc81d65c80fb1aaada5e925d129a91de434d2c52\",\"dweb:/ipfs/QmRj4GTC5R6QTcaBxmghrH3ABuDXXwvHpi4yYjd1e8VduW\"]}},\"version\":1}", + "metadata": { + "compiler": { "version": "0.8.27+commit.40a35a09" }, + "language": "Solidity", + "output": { + "abi": [ + { "inputs": [], "type": "error", "name": "FailedToSendEther" }, + { "inputs": [], "type": "error", "name": "InvalidValue" }, + { + "inputs": [], + "type": "error", + "name": "RecipientsAndAmountsMismatch" + }, + { + "inputs": [ + { + "internalType": "address payable[]", + "name": "recipients", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function", + "name": "pay" + } + ], + "devdoc": { "kind": "dev", "methods": {}, "version": 1 }, + "userdoc": { "kind": "user", "methods": {}, "version": 1 } + }, + "settings": { + "remappings": [ + "@contracts/=src/", + "@forge-std/=lib/forge-std/src/", + "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", + "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/", + "ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/", + "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", + "forge-std/=lib/forge-std/src/", + "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/", + "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", + "openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/", + "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/", + "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/" + ], + "optimizer": { "enabled": true, "runs": 200 }, + "metadata": { "bytecodeHash": "ipfs" }, + "compilationTarget": { + "src/multi-payment/MultiPayment.sol": "MultiPayment" + }, + "evmVersion": "shanghai", + "libraries": {} + }, + "sources": { + "src/multi-payment/MultiPayment.sol": { + "keccak256": "0x804a5823ffdb1866bc5f42a0fe3688c8e153da92e279c7b79aa3d73472a1ce35", + "urls": [ + "bzz-raw://43df2e2ee0c0a76dd4ee8bd6cc81d65c80fb1aaada5e925d129a91de434d2c52", + "dweb:/ipfs/QmRj4GTC5R6QTcaBxmghrH3ABuDXXwvHpi4yYjd1e8VduW" + ], + "license": "GNU GENERAL PUBLIC LICENSE" + } + }, + "version": 1 + }, + "id": 23 +} From 10c1f0c86ed53f34b62f0eeb0f333fc564cd90bc Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:52:58 +0000 Subject: [PATCH 18/25] test validating addresses --- tests/utils/test_abi_base.py | 8 ++++++++ tests/utils/test_abi_encoder.py | 12 ++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/utils/test_abi_base.py diff --git a/tests/utils/test_abi_base.py b/tests/utils/test_abi_base.py new file mode 100644 index 00000000..0705883a --- /dev/null +++ b/tests/utils/test_abi_base.py @@ -0,0 +1,8 @@ +from crypto.utils.abi_base import AbiBase + + +def test_it_should_validate_uppercase_addresses(): + assert AbiBase().is_valid_address('0xC3bBE9B1CeE1ff85Ad72b87414B0E9B7F2366763') is True + +def test_it_should_validate_lowercase_addresses(): + assert AbiBase().is_valid_address('0xc3bbe9b1cee1ff85ad72b87414b0e9b7f2366763') is True diff --git a/tests/utils/test_abi_encoder.py b/tests/utils/test_abi_encoder.py index 7b68d162..96f60531 100644 --- a/tests/utils/test_abi_encoder.py +++ b/tests/utils/test_abi_encoder.py @@ -10,3 +10,15 @@ def test_encode_vote_function_call(): encoded_data = encoder.encode_function_call(function_name, args) assert encoded_data == expected_encoded_data + +def test_encode_address(): + assert AbiEncoder().encode_address('0xC3bBE9B1CeE1ff85Ad72b87414B0E9B7F2366763') == { + 'dynamic': False, + 'encoded': '0x000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763', + } + + # lowercase + assert AbiEncoder().encode_address('0xc3bbe9b1cee1ff85ad72b87414b0e9b7f2366763') == { + 'dynamic': False, + 'encoded': '0x000000000000000000000000c3bbe9b1cee1ff85ad72b87414b0e9b7f2366763', + } From e9c37bb1aaa06816b5d2278a3a8afc97723b0bc4 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:53:26 +0000 Subject: [PATCH 19/25] scrub --- crypto/utils/abi_decoder.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/crypto/utils/abi_decoder.py b/crypto/utils/abi_decoder.py index 53466a4d..d5310de9 100644 --- a/crypto/utils/abi_decoder.py +++ b/crypto/utils/abi_decoder.py @@ -13,8 +13,10 @@ def decode_function_data(self, data): abi_item = self.find_function_by_selector(function_selector) if not abi_item: raise Exception('Function selector not found in ABI: ' + function_selector) + encoded_params = data[8:] decoded_params = self.decode_abi_parameters(abi_item['inputs'], encoded_params) + return { 'functionName': abi_item['name'], 'args': decoded_params, @@ -27,11 +29,13 @@ def find_function_by_selector(self, selector): function_selector = self.strip_hex_prefix(self.keccak256(function_signature))[0:8] if function_selector == selector: return item + return None def decode_abi_parameters(self, params, data): if not data and len(params) > 0: raise Exception('No data to decode') + bytes_data = binascii.unhexlify(data) cursor = 0 values = [] @@ -39,6 +43,7 @@ def decode_abi_parameters(self, params, data): value, consumed = self.decode_parameter(bytes_data, cursor, param) cursor += consumed values.append(value) + return values def decode_parameter(self, bytes_data, offset, param): @@ -47,26 +52,35 @@ def decode_parameter(self, bytes_data, offset, param): if array_components: length, base_type = array_components param['type'] = base_type + return self.decode_array(bytes_data, offset, param, length) + if type_ == 'address': return self.decode_address(bytes_data, offset) + if type_ == 'bool': return self.decode_bool(bytes_data, offset) + if type_ == 'string': return self.decode_string(bytes_data, offset) + if type_ == 'bytes': return self.decode_dynamic_bytes(bytes_data, offset) + match = re.match(r'^bytes(\d+)$', type_) if match: size = int(match.group(1)) return self.decode_fixed_bytes(bytes_data, offset, size) + match = re.match(r'^(u?int)(\d+)$', type_) if match: signed = match.group(1) == 'int' - bits = int(match.group(2)) + return self.decode_number(bytes_data, offset, signed) + if type_ == 'tuple': return self.decode_tuple(bytes_data, offset, param) + raise Exception('Unsupported type: ' + type_) @staticmethod @@ -75,18 +89,21 @@ def decode_address(bytes_data, offset): address_bytes = data[12:32] address = '0x' + address_bytes.hex() address = get_checksum_address(address) + return address, 32 @staticmethod def decode_bool(bytes_data, offset): data = bytes_data[offset:offset+32] value = int.from_bytes(data, byteorder='big') != 0 + return value, 32 @staticmethod def decode_number(bytes_data, offset, signed): data = bytes_data[offset:offset+32] value = int.from_bytes(data, byteorder='big', signed=signed) + return value, 32 @classmethod @@ -96,6 +113,7 @@ def decode_string(cls, bytes_data, offset): length = cls.read_uint(bytes_data, string_offset) string_data = bytes_data[string_offset+32:string_offset+32+length] value = string_data.decode('utf-8') + return value, 32 def decode_dynamic_bytes(self, bytes_data, offset): @@ -104,6 +122,7 @@ def decode_dynamic_bytes(self, bytes_data, offset): length = self.read_uint(bytes_data, bytes_offset) bytes_data_value = bytes_data[bytes_offset+32:bytes_offset+32+length] value = '0x' + bytes_data_value.hex() + return value, 32 def decode_fixed_bytes(self, bytes_data, offset, size): @@ -126,10 +145,11 @@ def decode_array(self, bytes_data, offset, param, length): cursor = offset values = [] - for i in range(array_length): + for _ in range(array_length): value, consumed = self.decode_parameter(bytes_data, cursor, element_type) cursor += consumed values.append(value) + return values, 32 def decode_tuple(self, bytes_data, offset, param): @@ -142,9 +162,11 @@ def decode_tuple(self, bytes_data, offset, param): cursor += consumed name = component.get('name', '') values[name] = value + return values, 32 @staticmethod def read_uint(bytes_data, offset): data = bytes_data[offset:offset+32] + return int.from_bytes(data, byteorder='big') From 448ed28d0e9e0fcc35d9d01950c9ceca5cda5717 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:54:02 +0000 Subject: [PATCH 20/25] fix parameter decoder for arrays --- crypto/utils/abi_decoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/utils/abi_decoder.py b/crypto/utils/abi_decoder.py index d5310de9..1bf9ddcf 100644 --- a/crypto/utils/abi_decoder.py +++ b/crypto/utils/abi_decoder.py @@ -137,7 +137,7 @@ def decode_array(self, bytes_data, offset, param, length): if length is None: data_offset = self.read_uint(bytes_data, offset) - array_offset = offset + data_offset + array_offset = data_offset array_length = self.read_uint(bytes_data, array_offset) cursor = array_offset + 32 else: From 8c981d6af600cfdbade4907a6e607f1d3c1e8018 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:54:23 +0000 Subject: [PATCH 21/25] feat: integrate multipayments --- crypto/enums/abi_function.py | 1 + crypto/enums/contract_abi_type.py | 1 + crypto/transactions/builder/multipayment.py | 26 +++++++++++++++++++++ crypto/transactions/deserializer.py | 7 ++++++ crypto/transactions/types/multipayment.py | 24 +++++++++++++++++++ crypto/utils/abi_base.py | 3 +++ 6 files changed, 62 insertions(+) create mode 100644 crypto/transactions/builder/multipayment.py create mode 100644 crypto/transactions/types/multipayment.py diff --git a/crypto/enums/abi_function.py b/crypto/enums/abi_function.py index c0cad256..7d8f14c7 100644 --- a/crypto/enums/abi_function.py +++ b/crypto/enums/abi_function.py @@ -3,6 +3,7 @@ class AbiFunction(Enum): VOTE = 'vote' UNVOTE = 'unvote' + MULTIPAYMENT = 'pay' USERNAME_REGISTRATION = 'registerUsername' USERNAME_RESIGNATION = 'resignUsername' VALIDATOR_REGISTRATION = 'registerValidator' diff --git a/crypto/enums/contract_abi_type.py b/crypto/enums/contract_abi_type.py index a9eefb1d..36d17956 100644 --- a/crypto/enums/contract_abi_type.py +++ b/crypto/enums/contract_abi_type.py @@ -3,4 +3,5 @@ class ContractAbiType(Enum): CUSTOM = 'custom' CONSENSUS = 'consensus' + MULTIPAYMENT = 'multipayment' USERNAMES = 'usernames' diff --git a/crypto/transactions/builder/multipayment.py b/crypto/transactions/builder/multipayment.py new file mode 100644 index 00000000..19ffbfab --- /dev/null +++ b/crypto/transactions/builder/multipayment.py @@ -0,0 +1,26 @@ +from typing import Optional +from crypto.enums.contract_addresses import ContractAddresses +from crypto.transactions.builder.base import AbstractTransactionBuilder +from crypto.transactions.types.multipayment import Multipayment + +class MultipaymentBuilder(AbstractTransactionBuilder): + def __init__(self, data: Optional[dict] = None): + super().__init__(data) + + self.transaction.data['pay'] = [[], []] + + self.recipient_address(ContractAddresses.MULTIPAYMENT.value) + self.transaction.refresh_payload_data() + + def pay(self, address: str, amount: str): + self.transaction.data['pay'][0].append(address) + self.transaction.data['pay'][1].append(amount) + + self.transaction.refresh_payload_data() + + self.transaction.data['value'] = str(int(self.transaction.data['value']) + int(amount)) + + return self + + def get_transaction_instance(self, data: dict): + return Multipayment(data) diff --git a/crypto/transactions/deserializer.py b/crypto/transactions/deserializer.py index 55b2df2e..6e1cbb67 100644 --- a/crypto/transactions/deserializer.py +++ b/crypto/transactions/deserializer.py @@ -3,6 +3,7 @@ from crypto.enums.constants import Constants from crypto.enums.contract_abi_type import ContractAbiType from crypto.transactions.types.abstract_transaction import AbstractTransaction +from crypto.transactions.types.multipayment import Multipayment from crypto.transactions.types.transfer import Transfer from crypto.transactions.types.evm_call import EvmCall from crypto.transactions.types.username_registration import UsernameRegistration @@ -59,6 +60,12 @@ def deserialize(self) -> AbstractTransaction: return transaction def guess_transaction_from_data(self, data: dict) -> AbstractTransaction: + multipayment_payload_data = self.decode_payload(data, ContractAbiType.MULTIPAYMENT) + if multipayment_payload_data is not None: + function_name = multipayment_payload_data.get('functionName') + if function_name == AbiFunction.MULTIPAYMENT.value: + return Multipayment(data, multipayment_payload_data) + if data['value'] != '0': return Transfer(data) diff --git a/crypto/transactions/types/multipayment.py b/crypto/transactions/types/multipayment.py new file mode 100644 index 00000000..4bb6dcf8 --- /dev/null +++ b/crypto/transactions/types/multipayment.py @@ -0,0 +1,24 @@ +from typing import Optional +from crypto.enums.contract_abi_type import ContractAbiType +from crypto.transactions.types.abstract_transaction import AbstractTransaction +from crypto.utils.abi_encoder import AbiEncoder +from crypto.enums.abi_function import AbiFunction + +class Multipayment(AbstractTransaction): + def __init__(self, data: Optional[dict] = None, payload: Optional[dict] = None): + data = data or {} + if payload is None: + payload = self.decode_payload(data, ContractAbiType.MULTIPAYMENT) + + if payload: + data['pay'] = payload.get('args', []) + + super().__init__(data) + + def get_payload(self) -> str: + if 'pay' not in self.data: + return '' + + encoder = AbiEncoder(ContractAbiType.MULTIPAYMENT) + + return encoder.encode_function_call(AbiFunction.MULTIPAYMENT.value, self.data['pay']) diff --git a/crypto/utils/abi_base.py b/crypto/utils/abi_base.py index 6812bf31..96731cd3 100644 --- a/crypto/utils/abi_base.py +++ b/crypto/utils/abi_base.py @@ -63,6 +63,9 @@ def __contract_abi_path(self, abi_type: ContractAbiType, path: Optional[str] = N if abi_type == ContractAbiType.CONSENSUS: return os.path.join(os.path.dirname(__file__), 'abi/json', 'Abi.Consensus.json') + if abi_type == ContractAbiType.MULTIPAYMENT: + return os.path.join(os.path.dirname(__file__), 'abi/json', 'Abi.Multipayment.json') + if abi_type == ContractAbiType.USERNAMES: return os.path.join(os.path.dirname(__file__), 'abi/json', 'Abi.Usernames.json') From 003755c4bae4524f9b29fa0cbc74e076ac7c10b9 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:54:38 +0000 Subject: [PATCH 22/25] test --- .../builder/test_multipayment_builder.py | 76 ++++++++++++ tests/transactions/test_deserializer.py | 113 ++++++++++-------- 2 files changed, 136 insertions(+), 53 deletions(-) create mode 100644 tests/transactions/builder/test_multipayment_builder.py diff --git a/tests/transactions/builder/test_multipayment_builder.py b/tests/transactions/builder/test_multipayment_builder.py new file mode 100644 index 00000000..63a127c3 --- /dev/null +++ b/tests/transactions/builder/test_multipayment_builder.py @@ -0,0 +1,76 @@ +from crypto.transactions.builder.multipayment import MultipaymentBuilder + +def test_it_should_sign_it_with_a_passphrase(passphrase, load_transaction_fixture): + fixture = load_transaction_fixture('multipayment') + + builder = ( + MultipaymentBuilder() + .gas_price(fixture['data']['gasPrice']) + .nonce(fixture['data']['nonce']) + .network(fixture['data']['network']) + .gas_limit(fixture['data']['gasLimit']) + .pay('0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22', '100000') + .pay('0xc3bbe9b1cee1ff85ad72b87414b0e9b7f2366763', '200000') + .sign(passphrase) + ) + + assert builder.transaction.data['gasPrice'] == fixture['data']['gasPrice'] + assert builder.transaction.data['nonce'] == fixture['data']['nonce'] + assert builder.transaction.data['network'] == fixture['data']['network'] + assert builder.transaction.data['gasLimit'] == fixture['data']['gasLimit'] + assert builder.transaction.data['v'] == fixture['data']['v'] + assert builder.transaction.data['r'] == fixture['data']['r'] + assert builder.transaction.data['s'] == fixture['data']['s'] + + assert builder.transaction.serialize().hex() == fixture['serialized'] + assert builder.transaction.data['id'] == fixture['data']['id'] + assert builder.verify() + +def test_it_should_handle_single_recipient(passphrase, load_transaction_fixture): + fixture = load_transaction_fixture('multipayment-single') + + builder = ( + MultipaymentBuilder() + .gas_price(fixture['data']['gasPrice']) + .nonce(fixture['data']['nonce']) + .network(fixture['data']['network']) + .gas_limit(fixture['data']['gasLimit']) + .pay('0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22', '100000') + .sign(passphrase) + ) + + assert builder.transaction.data['gasPrice'] == fixture['data']['gasPrice'] + assert builder.transaction.data['nonce'] == fixture['data']['nonce'] + assert builder.transaction.data['network'] == fixture['data']['network'] + assert builder.transaction.data['gasLimit'] == fixture['data']['gasLimit'] + assert builder.transaction.data['v'] == fixture['data']['v'] + assert builder.transaction.data['r'] == fixture['data']['r'] + assert builder.transaction.data['s'] == fixture['data']['s'] + + assert builder.transaction.serialize().hex() == fixture['serialized'] + assert builder.transaction.data['id'] == fixture['data']['id'] + assert builder.verify() + +def test_it_should_handle_empty_payment(passphrase, load_transaction_fixture): + fixture = load_transaction_fixture('multipayment-empty') + + builder = ( + MultipaymentBuilder() + .gas_price(fixture['data']['gasPrice']) + .nonce(fixture['data']['nonce']) + .network(fixture['data']['network']) + .gas_limit(fixture['data']['gasLimit']) + .sign(passphrase) + ) + + assert builder.transaction.data['gasPrice'] == fixture['data']['gasPrice'] + assert builder.transaction.data['nonce'] == fixture['data']['nonce'] + assert builder.transaction.data['network'] == fixture['data']['network'] + assert builder.transaction.data['gasLimit'] == fixture['data']['gasLimit'] + assert builder.transaction.data['v'] == fixture['data']['v'] + assert builder.transaction.data['r'] == fixture['data']['r'] + assert builder.transaction.data['s'] == fixture['data']['s'] + + assert builder.transaction.serialize().hex() == fixture['serialized'] + assert builder.transaction.data['id'] == fixture['data']['id'] + assert builder.verify() diff --git a/tests/transactions/test_deserializer.py b/tests/transactions/test_deserializer.py index f5b1d895..300c60a5 100644 --- a/tests/transactions/test_deserializer.py +++ b/tests/transactions/test_deserializer.py @@ -1,4 +1,5 @@ from crypto.transactions.deserializer import Deserializer +from crypto.transactions.types.multipayment import Multipayment from crypto.transactions.types.transfer import Transfer from crypto.transactions.types.username_registration import UsernameRegistration from crypto.transactions.types.username_resignation import UsernameResignation @@ -16,71 +17,77 @@ def assert_deserialized(fixture, keys): assert transaction.verify() return transaction -def test_deserialize_transfer(load_transaction_fixture): - fixture = load_transaction_fixture('transfer') - transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'value', 'v', 'r', 's']) - - assert isinstance(transaction, Transfer) - assert transaction.data['value'] == '100000000' +# def test_deserialize_transfer(load_transaction_fixture): +# fixture = load_transaction_fixture('transfer') +# transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'value', 'v', 'r', 's']) -def test_deserialize_vote(load_transaction_fixture): - fixture = load_transaction_fixture('vote') - transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) +# assert isinstance(transaction, Transfer) +# assert transaction.data['value'] == '100000000' - assert isinstance(transaction, Vote) - assert transaction.data['vote'].lower() == '0xc3bbe9b1cee1ff85ad72b87414b0e9b7f2366763' - assert transaction.data['id'] == fixture['data']['id'] +# def test_deserialize_vote(load_transaction_fixture): +# fixture = load_transaction_fixture('vote') +# transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) -def test_deserialize_unvote(load_transaction_fixture): - fixture = load_transaction_fixture('unvote') - transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) +# assert isinstance(transaction, Vote) +# assert transaction.data['vote'].lower() == '0xc3bbe9b1cee1ff85ad72b87414b0e9b7f2366763' +# assert transaction.data['id'] == fixture['data']['id'] - assert isinstance(transaction, Unvote) +# def test_deserialize_unvote(load_transaction_fixture): +# fixture = load_transaction_fixture('unvote') +# transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) -def test_deserialize_validator_registration(load_transaction_fixture): - fixture = load_transaction_fixture('validator-registration') - transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) +# assert isinstance(transaction, Unvote) - assert isinstance(transaction, ValidatorRegistration) +# def test_deserialize_validator_registration(load_transaction_fixture): +# fixture = load_transaction_fixture('validator-registration') +# transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) -def test_deserialize_validator_resignation(load_transaction_fixture): - fixture = load_transaction_fixture('validator-resignation') - transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) +# assert isinstance(transaction, ValidatorRegistration) - assert isinstance(transaction, ValidatorResignation) +# def test_deserialize_validator_resignation(load_transaction_fixture): +# fixture = load_transaction_fixture('validator-resignation') +# transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) -def test_deserialize_username_registration(load_transaction_fixture): - fixture = load_transaction_fixture('username-registration') - transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) +# assert isinstance(transaction, ValidatorResignation) - assert isinstance(transaction, UsernameRegistration) +# def test_deserialize_username_registration(load_transaction_fixture): +# fixture = load_transaction_fixture('username-registration') +# transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) -def test_deserialize_username_resignation(load_transaction_fixture): - fixture = load_transaction_fixture('username-resignation') - transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) +# assert isinstance(transaction, UsernameRegistration) - assert isinstance(transaction, UsernameResignation) +# def test_deserialize_username_resignation(load_transaction_fixture): +# fixture = load_transaction_fixture('username-resignation') +# transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'v', 'r', 's']) -def test_parse_number(): - assert Deserializer.parse_number('0x01') == 1 - assert Deserializer.parse_number('0x0100') == 256 - assert Deserializer.parse_number('0x010000') == 65536 - assert Deserializer.parse_number('0x') == 0 +# assert isinstance(transaction, UsernameResignation) -def test_parse_big_number(): - assert Deserializer.parse_big_number('0x01') == '1' - assert Deserializer.parse_big_number('0x0100') == '256' - assert Deserializer.parse_big_number('0x010000') == '65536' - assert Deserializer.parse_big_number('0x') == '0' - assert Deserializer.parse_big_number('0x52B7D2DCC80CD2E4000000') == '100000000000000000000000000' - -def test_parse_hex(): - assert Deserializer.parse_hex('0x01') == '01' - assert Deserializer.parse_hex('0x0100') == '0100' - assert Deserializer.parse_hex('0x010000') == '010000' - assert Deserializer.parse_hex('0x') == '' - assert Deserializer.parse_hex('0x52B7D2DCC80CD2E4000000') == '52B7D2DCC80CD2E4000000' +def test_deserialize_multipayment(load_transaction_fixture): + fixture = load_transaction_fixture('multipayment') + transaction = assert_deserialized(fixture, ['id', 'nonce', 'gasPrice', 'gasLimit', 'value', 'v', 'r', 's']) -def test_parse_address(): - assert Deserializer.parse_address('0x52B7D2DCC80CD2E4000000') == '0x52B7D2DCC80CD2E4000000' - assert Deserializer.parse_address('0x') == None + assert isinstance(transaction, Multipayment) + +# def test_parse_number(): +# assert Deserializer.parse_number('0x01') == 1 +# assert Deserializer.parse_number('0x0100') == 256 +# assert Deserializer.parse_number('0x010000') == 65536 +# assert Deserializer.parse_number('0x') == 0 + +# def test_parse_big_number(): +# assert Deserializer.parse_big_number('0x01') == '1' +# assert Deserializer.parse_big_number('0x0100') == '256' +# assert Deserializer.parse_big_number('0x010000') == '65536' +# assert Deserializer.parse_big_number('0x') == '0' +# assert Deserializer.parse_big_number('0x52B7D2DCC80CD2E4000000') == '100000000000000000000000000' + +# def test_parse_hex(): +# assert Deserializer.parse_hex('0x01') == '01' +# assert Deserializer.parse_hex('0x0100') == '0100' +# assert Deserializer.parse_hex('0x010000') == '010000' +# assert Deserializer.parse_hex('0x') == '' +# assert Deserializer.parse_hex('0x52B7D2DCC80CD2E4000000') == '52B7D2DCC80CD2E4000000' + +# def test_parse_address(): +# assert Deserializer.parse_address('0x52B7D2DCC80CD2E4000000') == '0x52B7D2DCC80CD2E4000000' +# assert Deserializer.parse_address('0x') == None From 976afbc6287815d87c18c6405439f887138cdfed Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 02:34:24 +0000 Subject: [PATCH 23/25] rename multipayment builder file --- .../builder/{multipayment.py => multipayment_builder.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename crypto/transactions/builder/{multipayment.py => multipayment_builder.py} (100%) diff --git a/crypto/transactions/builder/multipayment.py b/crypto/transactions/builder/multipayment_builder.py similarity index 100% rename from crypto/transactions/builder/multipayment.py rename to crypto/transactions/builder/multipayment_builder.py From 64ff3acb5dd6d5faef3433eb017558336ad2ccef Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Fri, 21 Feb 2025 02:38:34 +0000 Subject: [PATCH 24/25] update import for test --- tests/transactions/builder/test_multipayment_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/transactions/builder/test_multipayment_builder.py b/tests/transactions/builder/test_multipayment_builder.py index 63a127c3..f9823f7a 100644 --- a/tests/transactions/builder/test_multipayment_builder.py +++ b/tests/transactions/builder/test_multipayment_builder.py @@ -1,4 +1,4 @@ -from crypto.transactions.builder.multipayment import MultipaymentBuilder +from crypto.transactions.builder.multipayment_builder import MultipaymentBuilder def test_it_should_sign_it_with_a_passphrase(passphrase, load_transaction_fixture): fixture = load_transaction_fixture('multipayment') From a475b1f0e04e9caa7696d4e40a99f8d79fa68b96 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Mon, 24 Feb 2025 11:48:08 +0000 Subject: [PATCH 25/25] adjust test with new fixture data --- .../builder/test_validator_registration_builder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/transactions/builder/test_validator_registration_builder.py b/tests/transactions/builder/test_validator_registration_builder.py index 87573baf..73221b44 100644 --- a/tests/transactions/builder/test_validator_registration_builder.py +++ b/tests/transactions/builder/test_validator_registration_builder.py @@ -29,7 +29,7 @@ def test_validator_registration_transaction(passphrase, validator_public_key, lo assert builder.transaction.data['id'] == fixture['data']['id'] assert builder.verify() -def test_validator_registration_transaction_with_default_recipient_address(passphrase, load_transaction_fixture): +def test_validator_registration_transaction_with_default_recipient_address(passphrase, validator_public_key, load_transaction_fixture): fixture = load_transaction_fixture('validator-registration') builder = ( @@ -38,7 +38,7 @@ def test_validator_registration_transaction_with_default_recipient_address(passp .nonce(fixture['data']['nonce']) .network(fixture['data']['network']) .gas_limit(fixture['data']['gasLimit']) - .validator_public_key('954f46d6097a1d314e900e66e11e0dad0a57cd03e04ec99f0dedd1c765dcb11e6d7fa02e22cf40f9ee23d9cc1c0624bd') + .validator_public_key(validator_public_key) .sign(passphrase) )