From e3b4cca39d46eccbfbba16340b6c2ca72e7d9096 Mon Sep 17 00:00:00 2001 From: Marco Castignoli Date: Mon, 26 Jan 2026 11:40:44 +0100 Subject: [PATCH 1/7] Allow 'delete' type in CBOR auxdata transformations and update validation functions --- .../verified_contracts-transformations.json | 12 ++++++++--- ...ow_delete_cbor_auxdata_transformations.sql | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql diff --git a/json-schemas/verified_contracts-transformations.json b/json-schemas/verified_contracts-transformations.json index a6b2718..4e71882 100644 --- a/json-schemas/verified_contracts-transformations.json +++ b/json-schemas/verified_contracts-transformations.json @@ -32,14 +32,16 @@ "required": [ "type", "reason", - "offset", - "id" + "offset" ], "additionalProperties": false, "properties": { "type": { "type": "string", - "value": "replace" + "enum": [ + "replace", + "delete" + ] }, "reason": { "type": "string", @@ -54,6 +56,10 @@ "id": { "type": "string", "minLength": 1 + }, + "length": { + "type": "number", + "minimum": 0 } } }, diff --git a/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql b/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql new file mode 100644 index 0000000..9883afc --- /dev/null +++ b/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql @@ -0,0 +1,21 @@ +-- migrate:up +CREATE OR REPLACE FUNCTION validate_transformations_cbor_auxdata(object jsonb) + RETURNS boolean AS +$$ +BEGIN + RETURN ( + validate_transformation_key_type(object, 'replace') + OR validate_transformation_key_type(object, 'delete') + ) AND validate_transformation_key_offset(object); +END; +$$ LANGUAGE plpgsql; + +-- migrate:down +CREATE OR REPLACE FUNCTION validate_transformations_cbor_auxdata(object jsonb) + RETURNS boolean AS +$$ +BEGIN + RETURN validate_transformation_key_type(object, 'replace') AND validate_transformation_key_offset(object) + AND validate_transformation_key_id(object); +END; +$$ LANGUAGE plpgsql; From 835b8c4387c773921e2335cba9f46f9b3dcb4d76 Mon Sep 17 00:00:00 2001 From: Marco Castignoli Date: Tue, 27 Jan 2026 09:49:10 +0100 Subject: [PATCH 2/7] Address PR comments --- database.sql | 24 +++++++++++++++++-- json-schemas/README.md | 9 +++++++ ...ow_delete_cbor_auxdata_transformations.sql | 21 +++++++++++++--- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/database.sql b/database.sql index 6e26571..8a43024 100644 --- a/database.sql +++ b/database.sql @@ -614,6 +614,19 @@ END; $$; +-- +-- Name: validate_transformation_key_length(jsonb); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.validate_transformation_key_length(object jsonb) RETURNS boolean + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN object ? 'length' AND is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer >= 0; +END; +$$; + + -- -- Name: validate_transformation_key_type(jsonb, text); Type: FUNCTION; Schema: public; Owner: - -- @@ -691,8 +704,15 @@ CREATE FUNCTION public.validate_transformations_cbor_auxdata(object jsonb) RETUR LANGUAGE plpgsql AS $$ BEGIN - RETURN validate_transformation_key_type(object, 'replace') AND validate_transformation_key_offset(object) - AND validate_transformation_key_id(object); + RETURN ( + validate_transformation_key_type(object, 'replace') + AND validate_transformation_key_offset(object) + AND validate_transformation_key_id(object) + ) OR ( + validate_transformation_key_type(object, 'delete') + AND validate_transformation_key_offset(object) + AND validate_transformation_key_length(object) + ); END; $$; diff --git a/json-schemas/README.md b/json-schemas/README.md index c36bfb3..a337c62 100644 --- a/json-schemas/README.md +++ b/json-schemas/README.md @@ -26,6 +26,7 @@ Apart from the specifications in each section below, the following rules apply t - All hexadecimal value strings must be prefixed with `0x` such as addresses, constructor arguments etc. - `offset` values correspond to bytes in the bytecode and not string indexes. So `offset: 1` for the bytecode "0xab46fd" is the first byte in the bytecode corresponds to start from `46` +- `length` values (for delete transformations) are in bytes. ## Transformations @@ -83,6 +84,7 @@ The creation transformation can only contain these as `"reason"`s and `"type"`s: - `{ "reason": "constructorArguments", "type": "insert", "offset": 999 }` - `{ "reason": "cborAuxdata", "type": "replace", "offset": 123, id: "0" }` Needs an `id` since there can be multiple auxdata transformations e.g. factories. +- `{ "reason": "cborAuxdata", "type": "delete", "offset": 123, "length": 45 }` - `{ "reason": "library", "type": "replace", "offset": 123, id: "sources/lib/MyLib.sol:MyLib" }` Example: @@ -101,6 +103,12 @@ Example: "offset": 1269, "reason": "cborAuxdata" }, + { + "type": "delete", + "offset": 1295, + "length": 47, + "reason": "cborAuxdata" + }, { "type": "insert", "offset": 1322, @@ -134,6 +142,7 @@ Similar to `creation_transformation`. But runtime code does not contain construc The runtime transformations can only contain these as `"reason"`s and `"type"`s: - `{ "reason": "cborAuxdata", "type": "replace", "offset": 123, id: "0" }` Needs an `id` since there can be multiple auxdata transformations e.g. factories. +- `{ "reason": "cborAuxdata", "type": "delete", "offset": 123, "length": 45 }` - `{ "reason": "library", "type": "replace", "offset": 123, id: "contracts/order/OrderUtils.sol:OrderUtilsLib" }` - `{ "reason": "immutable", "type": "replace", "offset": 999, id: "2473" }` Needs an `id` for referencing multiple times and there can be multiple immutable transformations. Solidity contracts have `"replace"` type, while Vyper ones have `"insert"` because they are appended to the runtime bytecode. - `{ "reason": "callProtection", "type": "replace", "offset": 1 }` diff --git a/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql b/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql index 9883afc..7a16ee8 100644 --- a/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql +++ b/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql @@ -1,16 +1,31 @@ -- migrate:up +CREATE OR REPLACE FUNCTION validate_transformation_key_length(object jsonb) + RETURNS boolean AS +$$ +BEGIN + RETURN object ? 'length' AND is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer >= 0; +END; +$$ LANGUAGE plpgsql; + CREATE OR REPLACE FUNCTION validate_transformations_cbor_auxdata(object jsonb) RETURNS boolean AS $$ BEGIN RETURN ( - validate_transformation_key_type(object, 'replace') - OR validate_transformation_key_type(object, 'delete') - ) AND validate_transformation_key_offset(object); + validate_transformation_key_type(object, 'replace') + AND validate_transformation_key_offset(object) + AND validate_transformation_key_id(object) + ) OR ( + validate_transformation_key_type(object, 'delete') + AND validate_transformation_key_offset(object) + AND validate_transformation_key_length(object) + ); END; $$ LANGUAGE plpgsql; -- migrate:down +DROP FUNCTION IF EXISTS validate_transformation_key_length(jsonb); + CREATE OR REPLACE FUNCTION validate_transformations_cbor_auxdata(object jsonb) RETURNS boolean AS $$ From e800ed3d7a8c7e67de27bdc04be886da887970a9 Mon Sep 17 00:00:00 2001 From: Marco Castignoli Date: Tue, 27 Jan 2026 14:56:11 +0100 Subject: [PATCH 3/7] Address PR comments --- database.sql | 16 +++++++++++++++- json-schemas/README.md | 4 ++-- ...allow_delete_cbor_auxdata_transformations.sql | 13 ++++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/database.sql b/database.sql index 8a43024..0853235 100644 --- a/database.sql +++ b/database.sql @@ -622,7 +622,20 @@ CREATE FUNCTION public.validate_transformation_key_length(object jsonb) RETURNS LANGUAGE plpgsql AS $$ BEGIN - RETURN object ? 'length' AND is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer >= 0; + RETURN object ? 'length' AND is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer > 0; +END; +$$; + +-- +-- Name: validate_transformation_key_length_optional(jsonb); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.validate_transformation_key_length_optional(object jsonb) RETURNS boolean + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN NOT object ? 'length' + OR (is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer >= 0); END; $$; @@ -707,6 +720,7 @@ BEGIN RETURN ( validate_transformation_key_type(object, 'replace') AND validate_transformation_key_offset(object) + AND validate_transformation_key_length_optional(object) AND validate_transformation_key_id(object) ) OR ( validate_transformation_key_type(object, 'delete') diff --git a/json-schemas/README.md b/json-schemas/README.md index a337c62..2946ee6 100644 --- a/json-schemas/README.md +++ b/json-schemas/README.md @@ -26,7 +26,7 @@ Apart from the specifications in each section below, the following rules apply t - All hexadecimal value strings must be prefixed with `0x` such as addresses, constructor arguments etc. - `offset` values correspond to bytes in the bytecode and not string indexes. So `offset: 1` for the bytecode "0xab46fd" is the first byte in the bytecode corresponds to start from `46` -- `length` values (for delete transformations) are in bytes. +- `length` values (for delete transformations) are in number of bytes. ## Transformations @@ -83,7 +83,7 @@ This object contains the transformation that will be applied to the creation byt The creation transformation can only contain these as `"reason"`s and `"type"`s: - `{ "reason": "constructorArguments", "type": "insert", "offset": 999 }` -- `{ "reason": "cborAuxdata", "type": "replace", "offset": 123, id: "0" }` Needs an `id` since there can be multiple auxdata transformations e.g. factories. +- `{ "reason": "cborAuxdata", "type": "replace", "offset": 123, id: "0" }` Needs an `id` since there can be multiple auxdata transformations e.g. factories. Can also include optional `"length"`, if included it must be used instead of the length of the auxdata in the transformations. - `{ "reason": "cborAuxdata", "type": "delete", "offset": 123, "length": 45 }` - `{ "reason": "library", "type": "replace", "offset": 123, id: "sources/lib/MyLib.sol:MyLib" }` diff --git a/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql b/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql index 7a16ee8..2d42109 100644 --- a/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql +++ b/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql @@ -3,7 +3,16 @@ CREATE OR REPLACE FUNCTION validate_transformation_key_length(object jsonb) RETURNS boolean AS $$ BEGIN - RETURN object ? 'length' AND is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer >= 0; + RETURN object ? 'length' AND is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer > 0; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_transformation_key_length_optional(object jsonb) + RETURNS boolean AS +$$ +BEGIN + RETURN NOT object ? 'length' + OR (is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer >= 0); END; $$ LANGUAGE plpgsql; @@ -14,6 +23,7 @@ BEGIN RETURN ( validate_transformation_key_type(object, 'replace') AND validate_transformation_key_offset(object) + AND validate_transformation_key_length_optional(object) AND validate_transformation_key_id(object) ) OR ( validate_transformation_key_type(object, 'delete') @@ -24,6 +34,7 @@ END; $$ LANGUAGE plpgsql; -- migrate:down +DROP FUNCTION IF EXISTS validate_transformation_key_length_optional(jsonb); DROP FUNCTION IF EXISTS validate_transformation_key_length(jsonb); CREATE OR REPLACE FUNCTION validate_transformations_cbor_auxdata(object jsonb) From 89662bbd10bce889f826be912af2351b627f36a5 Mon Sep 17 00:00:00 2001 From: Marco Castignoli Date: Thu, 29 Jan 2026 14:57:06 +0100 Subject: [PATCH 4/7] Length in auxdata transformation should always be greater than 0 --- database.sql | 2 +- ...20260126113330_allow_delete_cbor_auxdata_transformations.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database.sql b/database.sql index 0853235..533f5f5 100644 --- a/database.sql +++ b/database.sql @@ -635,7 +635,7 @@ CREATE FUNCTION public.validate_transformation_key_length_optional(object jsonb) AS $$ BEGIN RETURN NOT object ? 'length' - OR (is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer >= 0); + OR (is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer > 0); END; $$; diff --git a/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql b/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql index 2d42109..c1d7276 100644 --- a/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql +++ b/migrations/20260126113330_allow_delete_cbor_auxdata_transformations.sql @@ -12,7 +12,7 @@ CREATE OR REPLACE FUNCTION validate_transformation_key_length_optional(object js $$ BEGIN RETURN NOT object ? 'length' - OR (is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer >= 0); + OR (is_jsonb_number(object -> 'length') AND (object ->> 'length')::integer > 0); END; $$ LANGUAGE plpgsql; From e23f061f821d7da5f8b4690ee364f87294e3f7cd Mon Sep 17 00:00:00 2001 From: Marco Castignoli Date: Thu, 29 Jan 2026 14:58:12 +0100 Subject: [PATCH 5/7] Add "optional length" comment also in runtime transformations --- json-schemas/README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/json-schemas/README.md b/json-schemas/README.md index 2946ee6..d0af940 100644 --- a/json-schemas/README.md +++ b/json-schemas/README.md @@ -141,7 +141,7 @@ Similar to `creation_transformation`. But runtime code does not contain construc The runtime transformations can only contain these as `"reason"`s and `"type"`s: -- `{ "reason": "cborAuxdata", "type": "replace", "offset": 123, id: "0" }` Needs an `id` since there can be multiple auxdata transformations e.g. factories. +- `{ "reason": "cborAuxdata", "type": "replace", "offset": 123, id: "0" }` Needs an `id` since there can be multiple auxdata transformations e.g. factories. Can also include optional `"length"`, if included it must be used instead of the length of the auxdata in the transformations. - `{ "reason": "cborAuxdata", "type": "delete", "offset": 123, "length": 45 }` - `{ "reason": "library", "type": "replace", "offset": 123, id: "contracts/order/OrderUtils.sol:OrderUtilsLib" }` - `{ "reason": "immutable", "type": "replace", "offset": 999, id: "2473" }` Needs an `id` for referencing multiple times and there can be multiple immutable transformations. Solidity contracts have `"replace"` type, while Vyper ones have `"insert"` because they are appended to the runtime bytecode. @@ -229,7 +229,14 @@ Compiler settings as passed to the compiler in JSON format }, "outputSelection": { "*": { - "*": ["evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi"] + "*": [ + "evm.bytecode", + "evm.deployedBytecode", + "devdoc", + "userdoc", + "metadata", + "abi" + ] }, "contracts/order/OrderUtils.sol": { "OrderUtils": ["*"] From 3077a6546c39a8fb2a4a406ff56c0902a636a6f9 Mon Sep 17 00:00:00 2001 From: Marco Castignoli Date: Thu, 29 Jan 2026 15:52:42 +0100 Subject: [PATCH 6/7] Add tests for new auxdata delete type and length property --- ...nt_creation_transformations_json_schema.py | 56 ++++++++++++++++++- ...int_runtime_transformations_json_schema.py | 54 ++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/tests/test_constraint_creation_transformations_json_schema.py b/tests/test_constraint_creation_transformations_json_schema.py index e9f9e26..53980c0 100644 --- a/tests/test_constraint_creation_transformations_json_schema.py +++ b/tests/test_constraint_creation_transformations_json_schema.py @@ -22,7 +22,8 @@ def test_expected_type_values(self, connection, dummy_code, dummy_contract, dumm {"reason": "constructorArguments", "type": "insert", "offset": 0}, {"reason": "library", "type": "replace", "offset": 0, "id": "file1:lib1"}, - {"reason": "cborAuxdata", "type": "replace", "offset": 0, "id": "0"} + {"reason": "cborAuxdata", "type": "replace", "offset": 0, "id": "0"}, + {"reason": "cborAuxdata", "type": "delete", "offset": 2, "length": 4} ] dummy_verified_contract.insert( connection, dummy_contract_deployment.id, dummy_compiled_contract.id) @@ -267,6 +268,20 @@ def test_valid_value(self, connection, dummy_code, dummy_contract, dummy_contrac dummy_verified_contract.insert( connection, dummy_contract_deployment.id, dummy_compiled_contract.id) + def test_valid_value_with_length(self, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.creation_transformations = [ + {"reason": "cborAuxdata", "type": "replace", "offset": 6, "id": "0", "length": 12} + ] + dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id) + + def test_valid_value_delete(self, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.creation_transformations = [ + {"reason": "cborAuxdata", "type": "delete", "offset": 6, "length": 12} + ] + dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id) + def test_missing_key_type_fails(self, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): dummy_verified_contract.creation_transformations = [ {"reason": "cborAuxdata", "offset": 0, "id": "0"} @@ -325,6 +340,45 @@ def test_invalid_key_offset_value_fails(self, connection, dummy_code, dummy_cont connection, dummy_contract_deployment.id, dummy_compiled_contract.id), "creation_transformations_json_schema") + def test_missing_key_length_for_delete_fails(self, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.creation_transformations = [ + {"reason": "cborAuxdata", "type": "delete", "offset": 6} + ] + check_constraint_fails( + lambda: dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id), + "creation_transformations_json_schema") + + @pytest.mark.parametrize("value", [None, "", [], dict()], ids=["null", "string", "array", "object"]) + def test_invalid_key_length_type_fails(self, value, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.creation_transformations = [ + {"reason": "cborAuxdata", "type": "replace", "offset": 6, "id": "0", "length": value} + ] + check_constraint_fails( + lambda: dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id), + "creation_transformations_json_schema") + + @pytest.mark.parametrize("value", [None, "", [], dict()], ids=["null", "string", "array", "object"]) + def test_invalid_key_length_type_for_delete_fails(self, value, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.creation_transformations = [ + {"reason": "cborAuxdata", "type": "delete", "offset": 0, "length": value} + ] + check_constraint_fails( + lambda: dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id), + "creation_transformations_json_schema") + + @pytest.mark.parametrize("value", [0, -1], ids=["zero", "negative"]) + def test_invalid_key_length_value_fails(self, value, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.creation_transformations = [ + {"reason": "cborAuxdata", "type": "delete", "offset": 6, "length": value} + ] + check_constraint_fails( + lambda: dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id), + "creation_transformations_json_schema") + def test_missing_key_id_fails(self, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): dummy_verified_contract.creation_transformations = [ {"reason": "cborAuxdata", "type": "replace", "offset": 0} diff --git a/tests/test_constraint_runtime_transformations_json_schema.py b/tests/test_constraint_runtime_transformations_json_schema.py index 56892a6..196f78f 100644 --- a/tests/test_constraint_runtime_transformations_json_schema.py +++ b/tests/test_constraint_runtime_transformations_json_schema.py @@ -23,6 +23,7 @@ def test_expected_type_values(self, connection, dummy_code, dummy_contract, dumm "offset": 0, "id": "file1:lib1"}, {"reason": "immutable", "type": "replace", "offset": 0, "id": "0"}, {"reason": "cborAuxdata", "type": "replace", "offset": 0, "id": "0"}, + {"reason": "cborAuxdata", "type": "delete", "offset": 1, "length": 2}, {"reason": "callProtection", "type": "replace", "offset": 0} ] dummy_verified_contract.insert( @@ -287,6 +288,20 @@ def test_valid_value(self, connection, dummy_code, dummy_contract, dummy_contrac dummy_verified_contract.insert( connection, dummy_contract_deployment.id, dummy_compiled_contract.id) + def test_valid_value_with_length(self, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.runtime_transformations = [ + {"reason": "cborAuxdata", "type": "replace", "offset": 0, "id": "0", "length": 12} + ] + dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id) + + def test_valid_value_delete(self, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.runtime_transformations = [ + {"reason": "cborAuxdata", "type": "delete", "offset": 0, "length": 12} + ] + dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id) + def test_missing_key_type_fails(self, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): dummy_verified_contract.runtime_transformations = [ {"reason": "cborAuxdata", "offset": 0, "id": "0"} @@ -345,6 +360,45 @@ def test_invalid_key_offset_value_fails(self, connection, dummy_code, dummy_cont connection, dummy_contract_deployment.id, dummy_compiled_contract.id), "runtime_transformations_json_schema") + def test_missing_key_length_for_delete_fails(self, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.runtime_transformations = [ + {"reason": "cborAuxdata", "type": "delete", "offset": 0} + ] + check_constraint_fails( + lambda: dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id), + "runtime_transformations_json_schema") + + @pytest.mark.parametrize("value", [None, "", [], dict()], ids=["null", "string", "array", "object"]) + def test_invalid_key_length_type_fails(self, value, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.runtime_transformations = [ + {"reason": "cborAuxdata", "type": "replace", "offset": 0, "id": "0", "length": value} + ] + check_constraint_fails( + lambda: dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id), + "runtime_transformations_json_schema") + + @pytest.mark.parametrize("value", [None, "", [], dict()], ids=["null", "string", "array", "object"]) + def test_invalid_key_length_type_for_delete_fails(self, value, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.runtime_transformations = [ + {"reason": "cborAuxdata", "type": "delete", "offset": 0, "length": value} + ] + check_constraint_fails( + lambda: dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id), + "runtime_transformations_json_schema") + + @pytest.mark.parametrize("value", [0, -1], ids=["zero", "negative"]) + def test_invalid_key_length_value_fails(self, value, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): + dummy_verified_contract.runtime_transformations = [ + {"reason": "cborAuxdata", "type": "delete", "offset": 0, "length": value} + ] + check_constraint_fails( + lambda: dummy_verified_contract.insert( + connection, dummy_contract_deployment.id, dummy_compiled_contract.id), + "runtime_transformations_json_schema") + def test_missing_key_id_fails(self, connection, dummy_code, dummy_contract, dummy_contract_deployment, dummy_compiled_contract, dummy_verified_contract): dummy_verified_contract.runtime_transformations = [ {"reason": "cborAuxdata", "type": "replace", "offset": 0} From 997a1f5d4fb1447761c5f76466d2d325a3e62a61 Mon Sep 17 00:00:00 2001 From: Marco Castignoli Date: Mon, 2 Feb 2026 09:24:58 +0100 Subject: [PATCH 7/7] Address comments in PR --- json-schemas/README.md | 4 ++-- json-schemas/verified_contracts-transformations.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/json-schemas/README.md b/json-schemas/README.md index d0af940..04d24cc 100644 --- a/json-schemas/README.md +++ b/json-schemas/README.md @@ -84,7 +84,7 @@ The creation transformation can only contain these as `"reason"`s and `"type"`s: - `{ "reason": "constructorArguments", "type": "insert", "offset": 999 }` - `{ "reason": "cborAuxdata", "type": "replace", "offset": 123, id: "0" }` Needs an `id` since there can be multiple auxdata transformations e.g. factories. Can also include optional `"length"`, if included it must be used instead of the length of the auxdata in the transformations. -- `{ "reason": "cborAuxdata", "type": "delete", "offset": 123, "length": 45 }` +- `{ "reason": "cborAuxdata", "type": "delete", "offset": 123, "length": 45 }` Can also have `"type": "delete"` which means the onchain bytecode does not have the cborAuxdata while the recompiled bytecode has it. - `{ "reason": "library", "type": "replace", "offset": 123, id: "sources/lib/MyLib.sol:MyLib" }` Example: @@ -142,7 +142,7 @@ Similar to `creation_transformation`. But runtime code does not contain construc The runtime transformations can only contain these as `"reason"`s and `"type"`s: - `{ "reason": "cborAuxdata", "type": "replace", "offset": 123, id: "0" }` Needs an `id` since there can be multiple auxdata transformations e.g. factories. Can also include optional `"length"`, if included it must be used instead of the length of the auxdata in the transformations. -- `{ "reason": "cborAuxdata", "type": "delete", "offset": 123, "length": 45 }` +- `{ "reason": "cborAuxdata", "type": "delete", "offset": 123, "length": 45 }` Can also have `"type": "delete"` which means the onchain bytecode does not have the cborAuxdata while the recompiled bytecode has it. - `{ "reason": "library", "type": "replace", "offset": 123, id: "contracts/order/OrderUtils.sol:OrderUtilsLib" }` - `{ "reason": "immutable", "type": "replace", "offset": 999, id: "2473" }` Needs an `id` for referencing multiple times and there can be multiple immutable transformations. Solidity contracts have `"replace"` type, while Vyper ones have `"insert"` because they are appended to the runtime bytecode. - `{ "reason": "callProtection", "type": "replace", "offset": 1 }` diff --git a/json-schemas/verified_contracts-transformations.json b/json-schemas/verified_contracts-transformations.json index 4e71882..c95c7b3 100644 --- a/json-schemas/verified_contracts-transformations.json +++ b/json-schemas/verified_contracts-transformations.json @@ -59,7 +59,7 @@ }, "length": { "type": "number", - "minimum": 0 + "minimum": 1 } } },