From 766dbb63180b6fc89c449d46e6b94a509386b13c Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Thu, 4 Jan 2024 19:26:55 +0100 Subject: [PATCH 01/10] Some hacks on forge --- src/forge/Wrapper.sol | 59 +++++++++++++++++++++++++++++++++++++++++++ test/Transactions.sol | 17 +++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/forge/Wrapper.sol diff --git a/src/forge/Wrapper.sol b/src/forge/Wrapper.sol new file mode 100644 index 0000000..da91144 --- /dev/null +++ b/src/forge/Wrapper.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.8; + +import "forge-std/console.sol"; + +interface Vm { + function ffi(string[] calldata commandInput) external view returns (bytes memory result); +} + +contract Wrapper { + Vm constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + + function forgeIt(bytes memory addr, bytes memory data) internal view returns (bytes memory) { + string memory addrHex = iToHex(addr); + string memory dataHex = iToHex(data); + + string[] memory inputs = new string[](4); + inputs[0] = "suave"; + inputs[1] = "forge"; + inputs[2] = addrHex; + inputs[3] = dataHex; + + bytes memory res = vm.ffi(inputs); + return res; + } + + function iToHex(bytes memory buffer) public pure returns (string memory) { + bytes memory converted = new bytes(buffer.length * 2); + + bytes memory _base = "0123456789abcdef"; + + for (uint256 i = 0; i < buffer.length; i++) { + converted[i * 2] = _base[uint8(buffer[i]) / _base.length]; + converted[i * 2 + 1] = _base[uint8(buffer[i]) % _base.length]; + } + + return string(abi.encodePacked("0x", converted)); + } + + fallback() external { + // bytes memory data = forgeIt(abi.encodePacked(address(this)), msg.data); + bytes memory byteArray = abi.encode("aaaaa"); + + assembly { + // Get the free memory pointer + let memPtr := mload(0x40) + + // Set the length of the byte array + mstore(byteArray, 0x20) // Set the length to 32 bytes (1 slot) + mstore(add(byteArray, 0x20), 0x41414141) // Set the first 4 bytes of data (example 'AAAA') + + // Update the free memory pointer + mstore(0x40, add(memPtr, 0x60)) + + // Return the byte array + return(memPtr, 0x20) + } + } +} diff --git a/test/Transactions.sol b/test/Transactions.sol index 64b8dbd..4481e82 100644 --- a/test/Transactions.sol +++ b/test/Transactions.sol @@ -2,7 +2,10 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; +import "forge-std/Vm.sol"; +import "forge-std/console.sol"; import "src/Transactions.sol"; +import "src/suavelib/Suave.sol"; contract TestTransactions is Test { using Transactions for *; @@ -34,4 +37,18 @@ contract TestTransactions is Test { bytes memory rlp1 = Transactions.encodeRLP(legacyTxn1); assertEq0(rlp1, expected); } + + address public constant ANYALLOWED = 0x1111000000000000000000000000000042100001; + + function testSomething() public { + bytes memory code = + hex"608060405234801561001057600080fd5b506004361061002b5760003560e01c8063671ff78614610074575b600060405160200161005690602080825260059082015264616161616160d81b604082015260600190565b60408051602080825263414141418183015260608401909252925081f35b610087610082366004610277565b61009d565b604051610094919061034c565b60405180910390f35b60606000825160026100af9190610395565b67ffffffffffffffff8111156100c7576100c7610261565b6040519080825280601f01601f1916602001820160405280156100f1576020820181803683370190505b5060408051808201909152601081526f181899199a1a9b1b9c1cb0b131b232b360811b602082015290915060005b84518110156102375781825186838151811061013d5761013d6103b2565b016020015161014f919060f81c6103de565b8151811061015f5761015f6103b2565b01602001516001600160f81b0319168361017a836002610395565b8151811061018a5761018a6103b2565b60200101906001600160f81b031916908160001a9053508182518683815181106101b6576101b66103b2565b01602001516101c8919060f81c6103f2565b815181106101d8576101d86103b2565b01602001516001600160f81b031916836101f3836002610395565b6101fe906001610406565b8151811061020e5761020e6103b2565b60200101906001600160f81b031916908160001a9053508061022f81610419565b91505061011f565b50816040516020016102499190610432565b60405160208183030381529060405292505050919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561028957600080fd5b813567ffffffffffffffff808211156102a157600080fd5b818401915084601f8301126102b557600080fd5b8135818111156102c7576102c7610261565b604051601f8201601f19908116603f011681019083821181831017156102ef576102ef610261565b8160405282815287602084870101111561030857600080fd5b826020860160208301376000928101602001929092525095945050505050565b60005b8381101561034357818101518382015260200161032b565b50506000910152565b602081526000825180602084015261036b816040850160208701610328565b601f01601f19169190910160400192915050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176103ac576103ac61037f565b92915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000826103ed576103ed6103c8565b500490565b600082610401576104016103c8565b500690565b808201808211156103ac576103ac61037f565b60006001820161042b5761042b61037f565b5060010190565b61060f60f31b81526000825161044f816002850160208701610328565b919091016002019291505056fea2646970667358221220308fa97990ba3aa76a873f441e6417af36f4e3900abae19398d9b6d7c5a70e5b64736f6c63430008130033"; + vm.etch(Suave.CONFIDENTIAL_INPUTS, code); + + (bool success, bytes memory data) = Suave.CONFIDENTIAL_INPUTS.staticcall(abi.encode()); + + //(bool success, bytes memory data) = ANYALLOWED.staticcall(abi.encode()); + console.log(success); + console.logBytes(data); + } } From 75de40dc637edc75380aade33bc1d41486cf2cba Mon Sep 17 00:00:00 2001 From: brock smedley <2791467+zeroXbrock@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:54:31 -0800 Subject: [PATCH 02/10] return sig-stripped calldata from fallback (#10) --- src/forge/Wrapper.sol | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/forge/Wrapper.sol b/src/forge/Wrapper.sol index da91144..96c4194 100644 --- a/src/forge/Wrapper.sol +++ b/src/forge/Wrapper.sol @@ -37,23 +37,13 @@ contract Wrapper { return string(abi.encodePacked("0x", converted)); } + /// Strips the first 4 bytes from the calldata and returns the rest. fallback() external { - // bytes memory data = forgeIt(abi.encodePacked(address(this)), msg.data); - bytes memory byteArray = abi.encode("aaaaa"); - + bytes memory msgdata = msg.data[4:]; assembly { - // Get the free memory pointer - let memPtr := mload(0x40) - - // Set the length of the byte array - mstore(byteArray, 0x20) // Set the length to 32 bytes (1 slot) - mstore(add(byteArray, 0x20), 0x41414141) // Set the first 4 bytes of data (example 'AAAA') - - // Update the free memory pointer - mstore(0x40, add(memPtr, 0x60)) - - // Return the byte array - return(memPtr, 0x20) + let location := msgdata + let length := mload(msgdata) + return(add(location, 0x20), length) } } } From 971c2bdcf8a6cf49de032776a3da02e1be6fcb2b Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Thu, 4 Jan 2024 23:41:01 +0100 Subject: [PATCH 03/10] Oh my... this really works --- src/forge/FSuave.sol | 10 +++ src/forge/Wrapper.sol | 6 +- src/forge/Wrapper2.sol | 40 +++++++++ src/suavelib/SuaveForge.sol | 167 ------------------------------------ test/Transactions.sol | 14 +-- tools/forge-gen/go.mod | 3 + tools/forge-gen/main.go | 167 ++++++++++++++++++++++++++++++++++++ 7 files changed, 225 insertions(+), 182 deletions(-) create mode 100644 src/forge/FSuave.sol create mode 100644 src/forge/Wrapper2.sol delete mode 100644 src/suavelib/SuaveForge.sol create mode 100644 tools/forge-gen/go.mod create mode 100644 tools/forge-gen/main.go diff --git a/src/forge/FSuave.sol b/src/forge/FSuave.sol new file mode 100644 index 0000000..0386bbe --- /dev/null +++ b/src/forge/FSuave.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.8; + +import "./Wrapper2.sol"; + +contract SuaveEnabled { + function setUp() public { + Suave2.enable(); + } +} diff --git a/src/forge/Wrapper.sol b/src/forge/Wrapper.sol index 96c4194..06c00b1 100644 --- a/src/forge/Wrapper.sol +++ b/src/forge/Wrapper.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.8; -import "forge-std/console.sol"; - interface Vm { function ffi(string[] calldata commandInput) external view returns (bytes memory result); } @@ -37,9 +35,9 @@ contract Wrapper { return string(abi.encodePacked("0x", converted)); } - /// Strips the first 4 bytes from the calldata and returns the rest. fallback() external { - bytes memory msgdata = msg.data[4:]; + bytes memory msgdata = forgeIt(abi.encodePacked(address(this)), msg.data); + assembly { let location := msgdata let length := mload(msgdata) diff --git a/src/forge/Wrapper2.sol b/src/forge/Wrapper2.sol new file mode 100644 index 0000000..ecdd1de --- /dev/null +++ b/src/forge/Wrapper2.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.8; + +import "../suavelib/Suave.sol"; + +interface Vm3 { + function etch(address, bytes calldata) external; +} + +library Suave2 { + Vm3 constant vm = Vm3(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + + function enableLib(address addr) public { + // code for Wrapper + bytes memory code = + hex"608060405234801561001057600080fd5b506004361061002b5760003560e01c8063671ff786146100a1575b6040516bffffffffffffffffffffffff193060601b1660208201526000906100959060340160408051808303601f19018152602036601f8101829004820285018201909352828452909291600091819084018382808284376000920191909152506100ca92505050565b90508081518060208301f35b6100b46100af36600461048c565b610259565b6040516100c1919061055c565b60405180910390f35b606060006100d784610259565b905060006100e484610259565b60408051600480825260a0820190925291925060009190816020015b606081526020019060019003908161010057905050905060405180604001604052806005815260200164737561766560d81b8152508160008151811061014857610148610576565b602002602001018190525060405180604001604052806005815260200164666f72676560d81b8152508160018151811061018457610184610576565b602002602001018190525082816002815181106101a3576101a3610576565b602002602001018190525081816003815181106101c2576101c2610576565b6020908102919091010152604051638916046760e01b8152600090737109709ecfa91a80626ff3989d68f67f5b1dd12d9063891604679061020790859060040161058c565b600060405180830381865afa158015610224573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261024c91908101906105ee565b9450505050505b92915050565b606060008251600261026b919061067b565b67ffffffffffffffff8111156102835761028361041d565b6040519080825280601f01601f1916602001820160405280156102ad576020820181803683370190505b5060408051808201909152601081526f181899199a1a9b1b9c1cb0b131b232b360811b602082015290915060005b84518110156103f3578182518683815181106102f9576102f9610576565b016020015161030b919060f81c6106a8565b8151811061031b5761031b610576565b01602001516001600160f81b0319168361033683600261067b565b8151811061034657610346610576565b60200101906001600160f81b031916908160001a90535081825186838151811061037257610372610576565b0160200151610384919060f81c6106bc565b8151811061039457610394610576565b01602001516001600160f81b031916836103af83600261067b565b6103ba9060016106d0565b815181106103ca576103ca610576565b60200101906001600160f81b031916908160001a905350806103eb816106e3565b9150506102db565b508160405160200161040591906106fc565b60405160208183030381529060405292505050919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561045c5761045c61041d565b604052919050565b600067ffffffffffffffff82111561047e5761047e61041d565b50601f01601f191660200190565b60006020828403121561049e57600080fd5b813567ffffffffffffffff8111156104b557600080fd5b8201601f810184136104c657600080fd5b80356104d96104d482610464565b610433565b8181528560208385010111156104ee57600080fd5b81602084016020830137600091810160200191909152949350505050565b60005b8381101561052757818101518382015260200161050f565b50506000910152565b6000815180845261054881602086016020860161050c565b601f01601f19169290920160200192915050565b60208152600061056f6020830184610530565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156105e157603f198886030184526105cf858351610530565b945092850192908501906001016105b3565b5092979650505050505050565b60006020828403121561060057600080fd5b815167ffffffffffffffff81111561061757600080fd5b8201601f8101841361062857600080fd5b80516106366104d482610464565b81815285602083850101111561064b57600080fd5b61065c82602083016020860161050c565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761025357610253610665565b634e487b7160e01b600052601260045260246000fd5b6000826106b7576106b7610692565b500490565b6000826106cb576106cb610692565b500690565b8082018082111561025357610253610665565b6000600182016106f5576106f5610665565b5060010190565b61060f60f31b81526000825161071981600285016020870161050c565b919091016002019291505056fea26469706673582212209bbb283ef2f98f0ca98f84404dd44e5f6535bd506f84ca977fbe4432d16d966d64736f6c63430008130033"; + vm.etch(addr, code); + } + + function enable() public { + enableLib(Suave.IS_CONFIDENTIAL_ADDR); + enableLib(Suave.BUILD_ETH_BLOCK); + enableLib(Suave.CONFIDENTIAL_INPUTS); + enableLib(Suave.CONFIDENTIAL_RETRIEVE); + enableLib(Suave.CONFIDENTIAL_STORE); + enableLib(Suave.DO_HTTPREQUEST); + enableLib(Suave.ETHCALL); + enableLib(Suave.EXTRACT_HINT); + enableLib(Suave.FETCH_DATA_RECORDS); + enableLib(Suave.FILL_MEV_SHARE_BUNDLE); + enableLib(Suave.NEW_BUILDER); + enableLib(Suave.NEW_DATA_RECORD); + enableLib(Suave.SIGN_ETH_TRANSACTION); + enableLib(Suave.SIGN_MESSAGE); + enableLib(Suave.SIMULATE_BUNDLE); + enableLib(Suave.SIMULATE_TRANSACTION); + enableLib(Suave.SUBMIT_BUNDLE_JSON_RPC); + enableLib(Suave.SUBMIT_ETH_BLOCK_TO_RELAY); + } +} diff --git a/src/suavelib/SuaveForge.sol b/src/suavelib/SuaveForge.sol deleted file mode 100644 index e42d6c8..0000000 --- a/src/suavelib/SuaveForge.sol +++ /dev/null @@ -1,167 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.8; - -import "./Suave.sol"; - -interface Vm { - function ffi(string[] calldata commandInput) external view returns (bytes memory result); -} - -library SuaveForge { - Vm constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - - function forgeIt(string memory addr, bytes memory data) internal view returns (bytes memory) { - string memory dataHex = iToHex(data); - - string[] memory inputs = new string[](4); - inputs[0] = "suave"; - inputs[1] = "forge"; - inputs[2] = addr; - inputs[3] = dataHex; - - bytes memory res = vm.ffi(inputs); - return res; - } - - function iToHex(bytes memory buffer) public pure returns (string memory) { - bytes memory converted = new bytes(buffer.length * 2); - - bytes memory _base = "0123456789abcdef"; - - for (uint256 i = 0; i < buffer.length; i++) { - converted[i * 2] = _base[uint8(buffer[i]) / _base.length]; - converted[i * 2 + 1] = _base[uint8(buffer[i]) % _base.length]; - } - - return string(abi.encodePacked("0x", converted)); - } - - function buildEthBlock(Suave.BuildBlockArgs memory blockArgs, Suave.DataId dataId, string memory namespace) - internal - view - returns (bytes memory, bytes memory) - { - bytes memory data = - forgeIt("0x0000000000000000000000000000000042100001", abi.encode(blockArgs, dataId, namespace)); - - return abi.decode(data, (bytes, bytes)); - } - - function confidentialInputs() internal view returns (bytes memory) { - bytes memory data = forgeIt("0x0000000000000000000000000000000042010001", abi.encode()); - - return data; - } - - function confidentialRetrieve(Suave.DataId dataId, string memory key) internal view returns (bytes memory) { - bytes memory data = forgeIt("0x0000000000000000000000000000000042020001", abi.encode(dataId, key)); - - return data; - } - - function confidentialStore(Suave.DataId dataId, string memory key, bytes memory data1) internal view { - bytes memory data = forgeIt("0x0000000000000000000000000000000042020000", abi.encode(dataId, key, data1)); - } - - function doHTTPRequest(Suave.HttpRequest memory request) internal view returns (bytes memory) { - bytes memory data = forgeIt("0x0000000000000000000000000000000043200002", abi.encode(request)); - - return abi.decode(data, (bytes)); - } - - function ethcall(address contractAddr, bytes memory input1) internal view returns (bytes memory) { - bytes memory data = forgeIt("0x0000000000000000000000000000000042100003", abi.encode(contractAddr, input1)); - - return abi.decode(data, (bytes)); - } - - function extractHint(bytes memory bundleData) internal view returns (bytes memory) { - bytes memory data = forgeIt("0x0000000000000000000000000000000042100037", abi.encode(bundleData)); - - return data; - } - - function fetchDataRecords(uint64 cond, string memory namespace) internal view returns (Suave.DataRecord[] memory) { - bytes memory data = forgeIt("0x0000000000000000000000000000000042030001", abi.encode(cond, namespace)); - - return abi.decode(data, (Suave.DataRecord[])); - } - - function fillMevShareBundle(Suave.DataId dataId) internal view returns (bytes memory) { - bytes memory data = forgeIt("0x0000000000000000000000000000000043200001", abi.encode(dataId)); - - return data; - } - - function newBuilder() internal view returns (string memory) { - bytes memory data = forgeIt("0x0000000000000000000000000000000053200001", abi.encode()); - - return abi.decode(data, (string)); - } - - function newDataRecord( - uint64 decryptionCondition, - address[] memory allowedPeekers, - address[] memory allowedStores, - string memory dataType - ) internal view returns (Suave.DataRecord memory) { - bytes memory data = forgeIt( - "0x0000000000000000000000000000000042030000", - abi.encode(decryptionCondition, allowedPeekers, allowedStores, dataType) - ); - - return abi.decode(data, (Suave.DataRecord)); - } - - function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey) - internal - view - returns (bytes memory) - { - bytes memory data = forgeIt("0x0000000000000000000000000000000040100001", abi.encode(txn, chainId, signingKey)); - - return abi.decode(data, (bytes)); - } - - function signMessage(bytes memory digest, string memory signingKey) internal view returns (bytes memory) { - bytes memory data = forgeIt("0x0000000000000000000000000000000040100003", abi.encode(digest, signingKey)); - - return abi.decode(data, (bytes)); - } - - function simulateBundle(bytes memory bundleData) internal view returns (uint64) { - bytes memory data = forgeIt("0x0000000000000000000000000000000042100000", abi.encode(bundleData)); - - return abi.decode(data, (uint64)); - } - - function simulateTransaction(string memory session, bytes memory txn) - internal - view - returns (Suave.SimulateTransactionResult memory) - { - bytes memory data = forgeIt("0x0000000000000000000000000000000053200002", abi.encode(session, txn)); - - return abi.decode(data, (Suave.SimulateTransactionResult)); - } - - function submitBundleJsonRPC(string memory url, string memory method, bytes memory params) - internal - view - returns (bytes memory) - { - bytes memory data = forgeIt("0x0000000000000000000000000000000043000001", abi.encode(url, method, params)); - - return data; - } - - function submitEthBlockToRelay(string memory relayUrl, bytes memory builderBid) - internal - view - returns (bytes memory) - { - bytes memory data = forgeIt("0x0000000000000000000000000000000042100002", abi.encode(relayUrl, builderBid)); - - return data; - } -} diff --git a/test/Transactions.sol b/test/Transactions.sol index 4481e82..c99c3fe 100644 --- a/test/Transactions.sol +++ b/test/Transactions.sol @@ -6,8 +6,9 @@ import "forge-std/Vm.sol"; import "forge-std/console.sol"; import "src/Transactions.sol"; import "src/suavelib/Suave.sol"; +import "src/forge/FSuave.sol"; -contract TestTransactions is Test { +contract TestTransactions is Test, SuaveEnabled { using Transactions for *; function testLegacyTransactionRLPEncoding() public { @@ -38,17 +39,8 @@ contract TestTransactions is Test { assertEq0(rlp1, expected); } - address public constant ANYALLOWED = 0x1111000000000000000000000000000042100001; - function testSomething() public { - bytes memory code = - hex"608060405234801561001057600080fd5b506004361061002b5760003560e01c8063671ff78614610074575b600060405160200161005690602080825260059082015264616161616160d81b604082015260600190565b60408051602080825263414141418183015260608401909252925081f35b610087610082366004610277565b61009d565b604051610094919061034c565b60405180910390f35b60606000825160026100af9190610395565b67ffffffffffffffff8111156100c7576100c7610261565b6040519080825280601f01601f1916602001820160405280156100f1576020820181803683370190505b5060408051808201909152601081526f181899199a1a9b1b9c1cb0b131b232b360811b602082015290915060005b84518110156102375781825186838151811061013d5761013d6103b2565b016020015161014f919060f81c6103de565b8151811061015f5761015f6103b2565b01602001516001600160f81b0319168361017a836002610395565b8151811061018a5761018a6103b2565b60200101906001600160f81b031916908160001a9053508182518683815181106101b6576101b66103b2565b01602001516101c8919060f81c6103f2565b815181106101d8576101d86103b2565b01602001516001600160f81b031916836101f3836002610395565b6101fe906001610406565b8151811061020e5761020e6103b2565b60200101906001600160f81b031916908160001a9053508061022f81610419565b91505061011f565b50816040516020016102499190610432565b60405160208183030381529060405292505050919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561028957600080fd5b813567ffffffffffffffff808211156102a157600080fd5b818401915084601f8301126102b557600080fd5b8135818111156102c7576102c7610261565b604051601f8201601f19908116603f011681019083821181831017156102ef576102ef610261565b8160405282815287602084870101111561030857600080fd5b826020860160208301376000928101602001929092525095945050505050565b60005b8381101561034357818101518382015260200161032b565b50506000910152565b602081526000825180602084015261036b816040850160208701610328565b601f01601f19169190910160400192915050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176103ac576103ac61037f565b92915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000826103ed576103ed6103c8565b500490565b600082610401576104016103c8565b500690565b808201808211156103ac576103ac61037f565b60006001820161042b5761042b61037f565b5060010190565b61060f60f31b81526000825161044f816002850160208701610328565b919091016002019291505056fea2646970667358221220308fa97990ba3aa76a873f441e6417af36f4e3900abae19398d9b6d7c5a70e5b64736f6c63430008130033"; - vm.etch(Suave.CONFIDENTIAL_INPUTS, code); - - (bool success, bytes memory data) = Suave.CONFIDENTIAL_INPUTS.staticcall(abi.encode()); - - //(bool success, bytes memory data) = ANYALLOWED.staticcall(abi.encode()); - console.log(success); + bytes memory data = Suave.confidentialInputs(); console.logBytes(data); } } diff --git a/tools/forge-gen/go.mod b/tools/forge-gen/go.mod new file mode 100644 index 0000000..8250b74 --- /dev/null +++ b/tools/forge-gen/go.mod @@ -0,0 +1,3 @@ +module github.com/flashbots/suave-std/tools/forge-gen + +go 1.21.0 diff --git a/tools/forge-gen/main.go b/tools/forge-gen/main.go new file mode 100644 index 0000000..828dbd7 --- /dev/null +++ b/tools/forge-gen/main.go @@ -0,0 +1,167 @@ +package main + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "html/template" + "os" + "os/exec" + "regexp" + "strings" +) + +var applyFlag bool + +func main() { + flag.BoolVar(&applyFlag, "apply", false, "write to file") + flag.Parse() + + bytecode, err := getForgeWrapperBytecode() + if err != nil { + fmt.Printf("failed to get forge wrapper bytecode: %v\n", err) + os.Exit(1) + } + + precompileNames, err := getPrecompileNames() + if err != nil { + fmt.Printf("failed to get precompile names: %v\n", err) + os.Exit(1) + } + + if err := applyTemplate(bytecode, precompileNames); err != nil { + fmt.Printf("failed to apply template: %v\n", err) + os.Exit(1) + } +} + +var templateFile = `// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.8; + +import "../suavelib/Suave.sol"; + +interface Vm3 { + function etch(address, bytes calldata) external; +} + +library Suave2 { + Vm3 constant vm = Vm3(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + + function enableLib(address addr) public { + // code for Wrapper + bytes memory code = + hex"{{.Bytecode}}"; + vm.etch(addr, code); + } + + function enable() public { + {{range .PrecompileNames}} + enableLib(Suave.{{.}}); + {{- end}} + } +}` + +func applyTemplate(bytecode string, precompileNames []string) error { + t, err := template.New("template").Parse(templateFile) + if err != nil { + return err + } + + input := map[string]interface{}{ + "Bytecode": bytecode, + "PrecompileNames": precompileNames, + } + + var outputRaw bytes.Buffer + if err = t.Execute(&outputRaw, input); err != nil { + return err + } + + str := outputRaw.String() + if str, err = formatSolidity(str); err != nil { + return err + } + + if applyFlag { + if err := os.WriteFile("./src/forge/Wrapper2.sol", []byte(str), 0644); err != nil { + return err + } + } else { + fmt.Println(str) + } + return nil +} + +func getForgeWrapperBytecode() (string, error) { + abiContent, err := os.ReadFile("./out/Wrapper.sol/Wrapper.json") + if err != nil { + return "", err + } + + var abiArtifact struct { + DeployedBytecode struct { + Object string + } + } + if err := json.Unmarshal(abiContent, &abiArtifact); err != nil { + return "", err + } + + bytecode := abiArtifact.DeployedBytecode.Object[2:] + return bytecode, nil +} + +func getPrecompileNames() ([]string, error) { + content, err := os.ReadFile("./src/suavelib/Suave.sol") + if err != nil { + return nil, err + } + + addrRegexp := regexp.MustCompile(`constant\s+([A-Za-z_]\w*)\s+=`) + + matches := addrRegexp.FindAllStringSubmatch(string(content), -1) + + names := []string{} + for _, match := range matches { + if len(match) > 1 { + name := strings.TrimSpace(match[1]) + if name == "ANYALLOWED" { + continue + } + names = append(names, name) + } + } + + return names, nil +} + +func formatSolidity(code string) (string, error) { + // Check if "forge" command is available in PATH + _, err := exec.LookPath("forge") + if err != nil { + return "", fmt.Errorf("forge command not found in PATH: %v", err) + } + + // Command and arguments for forge fmt + command := "forge" + args := []string{"fmt", "--raw", "-"} + + // Create a command to run the forge fmt command + cmd := exec.Command(command, args...) + + // Set up input from stdin + cmd.Stdin = bytes.NewBufferString(code) + + // Set up output buffer + var outBuf, errBuf bytes.Buffer + cmd.Stdout = &outBuf + cmd.Stderr = &errBuf + + // Run the command + if err = cmd.Run(); err != nil { + return "", fmt.Errorf("error running command: %v", err) + } + + return outBuf.String(), nil +} From 886ed227ee4b98a42cdd487bd44bb6ac22a185a7 Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Fri, 5 Jan 2024 09:47:54 +0100 Subject: [PATCH 04/10] Do not mirror SuaveForge.sol anymore --- .github/workflows/suave-lib-sync.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/suave-lib-sync.yml b/.github/workflows/suave-lib-sync.yml index 09552e7..cc581d5 100644 --- a/.github/workflows/suave-lib-sync.yml +++ b/.github/workflows/suave-lib-sync.yml @@ -36,9 +36,7 @@ jobs: - name: Mirror run: | cp suave-geth/suave/sol/libraries/Suave.sol ./src/suavelib/Suave.sol - cp suave-geth/suave/sol/libraries/SuaveForge.sol ./src/suavelib/SuaveForge.sol git add ./src/suavelib/Suave.sol - git add ./src/suavelib/SuaveForge.sol rm -rf suave-geth - name: Create Pull Request From 5de1b6a82157d721ce35a67501a1668b7ae2904d Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Fri, 5 Jan 2024 11:40:25 +0100 Subject: [PATCH 05/10] More updates --- .github/workflows/ci.yml | 21 +++++++++++++++++++++ src/Test.sol | 15 +++++++++++++++ src/forge/{Wrapper.sol => Connector.sol} | 6 +++--- src/forge/FSuave.sol | 10 ---------- src/forge/{Wrapper2.sol => Registry.sol} | 8 ++++---- test/Forge.t.sol | 20 ++++++++++++++++++++ test/Transactions.sol | 11 +---------- tools/forge-gen/main.go | 14 +++++++------- 8 files changed, 71 insertions(+), 34 deletions(-) create mode 100644 src/Test.sol rename src/forge/{Wrapper.sol => Connector.sol} (90%) delete mode 100644 src/forge/FSuave.sol rename src/forge/{Wrapper2.sol => Registry.sol} (94%) create mode 100644 test/Forge.t.sol diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb7f9dc..1bc8505 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,27 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Checkout suave-geth repo + uses: actions/checkout@v4 + with: + repository: flashbots/suave-geth + path: suave-geth + persist-credentials: false + fetch-depth: 0 + + - name: Build suave + run: | + cd suave-geth + make suave + + - name: Include the binary on $PATH + run: | + echo "::add-path::$(pwd)/suave-geth/build/bin" + + - name: Run suave + run: | + ./suave-geth/build/bin/suave --suave.dev & + - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: diff --git a/src/Test.sol b/src/Test.sol new file mode 100644 index 0000000..9a78e0f --- /dev/null +++ b/src/Test.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.8; + +import "./forge/Registry.sol"; + +contract SuaveEnabled { + function setUp() public { + // TODO: Add checks to validate that: + // - User is running the test with ffi. Since vm.ffi is deployed as a contract, the error if ffi is not active + // is reported as a Suave.PeekerReverted error and it is not clear what the problem is. + // - Suave binary is on $PATH and Suave is running. This could be done with ffi calls to the suave binary. + // Put this logic inside `enable` itself. + Registry.enable(); + } +} diff --git a/src/forge/Wrapper.sol b/src/forge/Connector.sol similarity index 90% rename from src/forge/Wrapper.sol rename to src/forge/Connector.sol index 06c00b1..2e2f4fd 100644 --- a/src/forge/Wrapper.sol +++ b/src/forge/Connector.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.8; -interface Vm { +interface connectorVM { function ffi(string[] calldata commandInput) external view returns (bytes memory result); } -contract Wrapper { - Vm constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); +contract Connector { + connectorVM constant vm = connectorVM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); function forgeIt(bytes memory addr, bytes memory data) internal view returns (bytes memory) { string memory addrHex = iToHex(addr); diff --git a/src/forge/FSuave.sol b/src/forge/FSuave.sol deleted file mode 100644 index 0386bbe..0000000 --- a/src/forge/FSuave.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.8; - -import "./Wrapper2.sol"; - -contract SuaveEnabled { - function setUp() public { - Suave2.enable(); - } -} diff --git a/src/forge/Wrapper2.sol b/src/forge/Registry.sol similarity index 94% rename from src/forge/Wrapper2.sol rename to src/forge/Registry.sol index ecdd1de..526181d 100644 --- a/src/forge/Wrapper2.sol +++ b/src/forge/Registry.sol @@ -3,17 +3,17 @@ pragma solidity ^0.8.8; import "../suavelib/Suave.sol"; -interface Vm3 { +interface registryVM { function etch(address, bytes calldata) external; } -library Suave2 { - Vm3 constant vm = Vm3(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); +library Registry { + registryVM constant vm = registryVM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); function enableLib(address addr) public { // code for Wrapper bytes memory code = - hex"608060405234801561001057600080fd5b506004361061002b5760003560e01c8063671ff786146100a1575b6040516bffffffffffffffffffffffff193060601b1660208201526000906100959060340160408051808303601f19018152602036601f8101829004820285018201909352828452909291600091819084018382808284376000920191909152506100ca92505050565b90508081518060208301f35b6100b46100af36600461048c565b610259565b6040516100c1919061055c565b60405180910390f35b606060006100d784610259565b905060006100e484610259565b60408051600480825260a0820190925291925060009190816020015b606081526020019060019003908161010057905050905060405180604001604052806005815260200164737561766560d81b8152508160008151811061014857610148610576565b602002602001018190525060405180604001604052806005815260200164666f72676560d81b8152508160018151811061018457610184610576565b602002602001018190525082816002815181106101a3576101a3610576565b602002602001018190525081816003815181106101c2576101c2610576565b6020908102919091010152604051638916046760e01b8152600090737109709ecfa91a80626ff3989d68f67f5b1dd12d9063891604679061020790859060040161058c565b600060405180830381865afa158015610224573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261024c91908101906105ee565b9450505050505b92915050565b606060008251600261026b919061067b565b67ffffffffffffffff8111156102835761028361041d565b6040519080825280601f01601f1916602001820160405280156102ad576020820181803683370190505b5060408051808201909152601081526f181899199a1a9b1b9c1cb0b131b232b360811b602082015290915060005b84518110156103f3578182518683815181106102f9576102f9610576565b016020015161030b919060f81c6106a8565b8151811061031b5761031b610576565b01602001516001600160f81b0319168361033683600261067b565b8151811061034657610346610576565b60200101906001600160f81b031916908160001a90535081825186838151811061037257610372610576565b0160200151610384919060f81c6106bc565b8151811061039457610394610576565b01602001516001600160f81b031916836103af83600261067b565b6103ba9060016106d0565b815181106103ca576103ca610576565b60200101906001600160f81b031916908160001a905350806103eb816106e3565b9150506102db565b508160405160200161040591906106fc565b60405160208183030381529060405292505050919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561045c5761045c61041d565b604052919050565b600067ffffffffffffffff82111561047e5761047e61041d565b50601f01601f191660200190565b60006020828403121561049e57600080fd5b813567ffffffffffffffff8111156104b557600080fd5b8201601f810184136104c657600080fd5b80356104d96104d482610464565b610433565b8181528560208385010111156104ee57600080fd5b81602084016020830137600091810160200191909152949350505050565b60005b8381101561052757818101518382015260200161050f565b50506000910152565b6000815180845261054881602086016020860161050c565b601f01601f19169290920160200192915050565b60208152600061056f6020830184610530565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156105e157603f198886030184526105cf858351610530565b945092850192908501906001016105b3565b5092979650505050505050565b60006020828403121561060057600080fd5b815167ffffffffffffffff81111561061757600080fd5b8201601f8101841361062857600080fd5b80516106366104d482610464565b81815285602083850101111561064b57600080fd5b61065c82602083016020860161050c565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761025357610253610665565b634e487b7160e01b600052601260045260246000fd5b6000826106b7576106b7610692565b500490565b6000826106cb576106cb610692565b500690565b8082018082111561025357610253610665565b6000600182016106f5576106f5610665565b5060010190565b61060f60f31b81526000825161071981600285016020870161050c565b919091016002019291505056fea26469706673582212209bbb283ef2f98f0ca98f84404dd44e5f6535bd506f84ca977fbe4432d16d966d64736f6c63430008130033"; + hex"608060405234801561001057600080fd5b506004361061002b5760003560e01c8063671ff786146100a1575b6040516bffffffffffffffffffffffff193060601b1660208201526000906100959060340160408051808303601f19018152602036601f8101829004820285018201909352828452909291600091819084018382808284376000920191909152506100ca92505050565b90508081518060208301f35b6100b46100af36600461048c565b610259565b6040516100c1919061055c565b60405180910390f35b606060006100d784610259565b905060006100e484610259565b60408051600480825260a0820190925291925060009190816020015b606081526020019060019003908161010057905050905060405180604001604052806005815260200164737561766560d81b8152508160008151811061014857610148610576565b602002602001018190525060405180604001604052806005815260200164666f72676560d81b8152508160018151811061018457610184610576565b602002602001018190525082816002815181106101a3576101a3610576565b602002602001018190525081816003815181106101c2576101c2610576565b6020908102919091010152604051638916046760e01b8152600090737109709ecfa91a80626ff3989d68f67f5b1dd12d9063891604679061020790859060040161058c565b600060405180830381865afa158015610224573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261024c91908101906105ee565b9450505050505b92915050565b606060008251600261026b919061067b565b67ffffffffffffffff8111156102835761028361041d565b6040519080825280601f01601f1916602001820160405280156102ad576020820181803683370190505b5060408051808201909152601081526f181899199a1a9b1b9c1cb0b131b232b360811b602082015290915060005b84518110156103f3578182518683815181106102f9576102f9610576565b016020015161030b919060f81c6106a8565b8151811061031b5761031b610576565b01602001516001600160f81b0319168361033683600261067b565b8151811061034657610346610576565b60200101906001600160f81b031916908160001a90535081825186838151811061037257610372610576565b0160200151610384919060f81c6106bc565b8151811061039457610394610576565b01602001516001600160f81b031916836103af83600261067b565b6103ba9060016106d0565b815181106103ca576103ca610576565b60200101906001600160f81b031916908160001a905350806103eb816106e3565b9150506102db565b508160405160200161040591906106fc565b60405160208183030381529060405292505050919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561045c5761045c61041d565b604052919050565b600067ffffffffffffffff82111561047e5761047e61041d565b50601f01601f191660200190565b60006020828403121561049e57600080fd5b813567ffffffffffffffff8111156104b557600080fd5b8201601f810184136104c657600080fd5b80356104d96104d482610464565b610433565b8181528560208385010111156104ee57600080fd5b81602084016020830137600091810160200191909152949350505050565b60005b8381101561052757818101518382015260200161050f565b50506000910152565b6000815180845261054881602086016020860161050c565b601f01601f19169290920160200192915050565b60208152600061056f6020830184610530565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156105e157603f198886030184526105cf858351610530565b945092850192908501906001016105b3565b5092979650505050505050565b60006020828403121561060057600080fd5b815167ffffffffffffffff81111561061757600080fd5b8201601f8101841361062857600080fd5b80516106366104d482610464565b81815285602083850101111561064b57600080fd5b61065c82602083016020860161050c565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761025357610253610665565b634e487b7160e01b600052601260045260246000fd5b6000826106b7576106b7610692565b500490565b6000826106cb576106cb610692565b500690565b8082018082111561025357610253610665565b6000600182016106f5576106f5610665565b5060010190565b61060f60f31b81526000825161071981600285016020870161050c565b919091016002019291505056fea2646970667358221220e66d500bc9a9ca9c0748086adfc51de57c85b7c9f66cc760e823099f0439820b64736f6c63430008130033"; vm.etch(addr, code); } diff --git a/test/Forge.t.sol b/test/Forge.t.sol new file mode 100644 index 0000000..b0840db --- /dev/null +++ b/test/Forge.t.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import "src/Test.sol"; +import "src/suavelib/Suave.sol"; + +contract TestForge is Test, SuaveEnabled { + address[] public addressList = [0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829]; + + function testConfidentialStore() public { + Suave.DataRecord memory record = Suave.newDataRecord(0, addressList, addressList, "namespace"); + + bytes memory value = abi.encode("suave works with forge!"); + Suave.confidentialStore(record.id, "key1", value); + + bytes memory found = Suave.confidentialRetrieve(record.id, "key1"); + assertEq(keccak256(found), keccak256(value)); + } +} diff --git a/test/Transactions.sol b/test/Transactions.sol index c99c3fe..64b8dbd 100644 --- a/test/Transactions.sol +++ b/test/Transactions.sol @@ -2,13 +2,9 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; -import "forge-std/Vm.sol"; -import "forge-std/console.sol"; import "src/Transactions.sol"; -import "src/suavelib/Suave.sol"; -import "src/forge/FSuave.sol"; -contract TestTransactions is Test, SuaveEnabled { +contract TestTransactions is Test { using Transactions for *; function testLegacyTransactionRLPEncoding() public { @@ -38,9 +34,4 @@ contract TestTransactions is Test, SuaveEnabled { bytes memory rlp1 = Transactions.encodeRLP(legacyTxn1); assertEq0(rlp1, expected); } - - function testSomething() public { - bytes memory data = Suave.confidentialInputs(); - console.logBytes(data); - } } diff --git a/tools/forge-gen/main.go b/tools/forge-gen/main.go index 828dbd7..a6b6793 100644 --- a/tools/forge-gen/main.go +++ b/tools/forge-gen/main.go @@ -18,7 +18,7 @@ func main() { flag.BoolVar(&applyFlag, "apply", false, "write to file") flag.Parse() - bytecode, err := getForgeWrapperBytecode() + bytecode, err := getForgeConnectorBytecode() if err != nil { fmt.Printf("failed to get forge wrapper bytecode: %v\n", err) os.Exit(1) @@ -41,12 +41,12 @@ pragma solidity ^0.8.8; import "../suavelib/Suave.sol"; -interface Vm3 { +interface registryVM { function etch(address, bytes calldata) external; } -library Suave2 { - Vm3 constant vm = Vm3(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); +library Registry { + registryVM constant vm = registryVM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); function enableLib(address addr) public { // code for Wrapper @@ -84,7 +84,7 @@ func applyTemplate(bytecode string, precompileNames []string) error { } if applyFlag { - if err := os.WriteFile("./src/forge/Wrapper2.sol", []byte(str), 0644); err != nil { + if err := os.WriteFile("./src/forge/Registry.sol", []byte(str), 0644); err != nil { return err } } else { @@ -93,8 +93,8 @@ func applyTemplate(bytecode string, precompileNames []string) error { return nil } -func getForgeWrapperBytecode() (string, error) { - abiContent, err := os.ReadFile("./out/Wrapper.sol/Wrapper.json") +func getForgeConnectorBytecode() (string, error) { + abiContent, err := os.ReadFile("./out/Connector.sol/Connector.json") if err != nil { return "", err } From 352de9ad5de6b42a4fbc6fbb9b01a54173607955 Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Fri, 5 Jan 2024 12:02:32 +0100 Subject: [PATCH 06/10] Write comment --- tools/forge-gen/README.md | 13 +++++++++++++ tools/forge-gen/main.go | 1 + 2 files changed, 14 insertions(+) create mode 100644 tools/forge-gen/README.md diff --git a/tools/forge-gen/README.md b/tools/forge-gen/README.md new file mode 100644 index 0000000..3e8f186 --- /dev/null +++ b/tools/forge-gen/README.md @@ -0,0 +1,13 @@ +# Forge-gen command + +In the `forge` integration, a `forge/Connector.sol` contract is deployed for each of the `Suave` precompiles. The contract uses the fallback function to make an `vm.ffi` call to the `suave forge` command to peform the logic request. + +The `forge-gen` command creates the `forge/Registry.sol` contract which deploys the `Connector.sol` contract in all the precompile addresses using the `vm.etch` function. + +## Usage + +```bash +$ go run tools/forge-gen/main.go --apply +``` + +Use the `apply` flag to write the contract. Otherwise, it prints the contract on the standard output. diff --git a/tools/forge-gen/main.go b/tools/forge-gen/main.go index a6b6793..80fefff 100644 --- a/tools/forge-gen/main.go +++ b/tools/forge-gen/main.go @@ -37,6 +37,7 @@ func main() { } var templateFile = `// SPDX-License-Identifier: UNLICENSED +// DO NOT edit this file. Code generated by forge-gen. pragma solidity ^0.8.8; import "../suavelib/Suave.sol"; From 6f9f209c3584efc80190b60aedc389a7b53bfe9e Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Fri, 5 Jan 2024 12:10:12 +0100 Subject: [PATCH 07/10] Fix CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1bc8505..4ccbcfa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - name: Include the binary on $PATH run: | - echo "::add-path::$(pwd)/suave-geth/build/bin" + echo "$(pwd)/suave-geth/build/bin" >> $GITHUB_PATH - name: Run suave run: | From 1d5be8f65d0894bcabaa5f5ec20187b7cc8705b7 Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Fri, 5 Jan 2024 12:12:39 +0100 Subject: [PATCH 08/10] Enable ffi on ci test --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ccbcfa..88886fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,4 +44,4 @@ jobs: run: forge install - name: Run tests - run: forge test + run: forge test --ffi From 2354ebdbf5b41e11521b59d5b85a46c6aee2ef7a Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Fri, 5 Jan 2024 12:18:37 +0100 Subject: [PATCH 09/10] Add REAMDE --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index 27c171a..9276939 100644 --- a/README.md +++ b/README.md @@ -39,3 +39,38 @@ contract Example { } } ``` + +## Forge integration + +In order to use `forge`, you need to have a running `Suave` node and the `suave` binary in your path. + +To run `Suave` in development mode, use the following command: + +```bash +$ suave --suave.dev +``` + +Then, your `forge` scripts/test must import the `SuaveEnabled` contract from the `suave-std/Test.sol` file. + +``` +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import "suave-std/Test.sol"; +import "suave-std/Suave.sol"; + +contract TestForge is Test, SuaveEnabled { + address[] public addressList = [0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829]; + + function testConfidentialStore() public { + Suave.DataRecord memory record = Suave.newDataRecord(0, addressList, addressList, "namespace"); + + bytes memory value = abi.encode("suave works with forge!"); + Suave.confidentialStore(record.id, "key1", value); + + bytes memory found = Suave.confidentialRetrieve(record.id, "key1"); + assertEq(keccak256(found), keccak256(value)); + } +} +``` From 48c99af08ab212a8a000aaa35acc938874a0bb95 Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Fri, 5 Jan 2024 12:35:07 +0100 Subject: [PATCH 10/10] Add lang to readme code --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9276939..144eebd 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ $ suave --suave.dev Then, your `forge` scripts/test must import the `SuaveEnabled` contract from the `suave-std/Test.sol` file. -``` +```solidity // SPDX-License-Identifier: Unlicense pragma solidity ^0.8.13;