Skip to content

Commit

Permalink
Add logging for debugging, update paymaster data handling, remove obs…
Browse files Browse the repository at this point in the history
…olete JSON test data, and enhance test assertions in KintoInflator and SponsorPaymaster contracts.
  • Loading branch information
ylv-io committed Dec 19, 2024
1 parent b350952 commit 1294f44
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 105 deletions.
28 changes: 21 additions & 7 deletions src/inflators/KintoInflator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@solady/utils/LibZip.sol";

import "forge-std/console2.sol";

/// @notice Inflator contract for Kinto user operations
/// @dev This contract is responsible for inflating and compressing (off-chain) user operations
/// For further compression, consider: (1) using assembly for encoding/decoding,
Expand Down Expand Up @@ -78,6 +80,7 @@ contract KintoInflator is IOpInflator, OwnableUpgradeable, UUPSUpgradeable {
function _inflate(bytes calldata decompressed) public view returns (PackedUserOperation memory op) {
uint256 cursor = 0; // keep track of the current position in the decompressed data

console2.logBytes(decompressed);
// extract flags
uint8 flags = uint8(decompressed[cursor]);
cursor += 1;
Expand Down Expand Up @@ -119,14 +122,17 @@ contract KintoInflator is IOpInflator, OwnableUpgradeable, UUPSUpgradeable {

// Extract paymasterAndData if the flag is set
if (flags & 0x02 == 0x02) {
op.paymasterAndData = abi.encodePacked(kintoContracts["SP"]);
op.paymasterAndData = abi.encodePacked(kintoContracts["SP"], decompressed[cursor:cursor + 32]);
cursor += 32;
}

// Decode signature length and content
uint32 signatureLength = uint32(bytes4(decompressed[cursor:cursor + 4]));
console2.log("signatureLength:", signatureLength);
cursor += 4;
require(cursor + signatureLength <= decompressed.length, "Invalid signature length");
op.signature = decompressed[cursor:cursor + signatureLength];
console2.logBytes(op.signature);

return op;
}
Expand All @@ -136,20 +142,18 @@ contract KintoInflator is IOpInflator, OwnableUpgradeable, UUPSUpgradeable {
* @param op The PackedUserOperation to compress
* @return compressed The compressed PackedUserOperation as bytes
*/
function compress(PackedUserOperation memory op) external view returns (bytes memory compressed) {
// initialize a dynamic bytes array for the pre-compressed data
bytes memory buffer = new bytes(1024); // arbitrary size of 1024 bytes (resized later)
uint256 cursor = 0;

function compress(PackedUserOperation calldata op) external view returns (bytes memory compressed) {
// decode `callData` (selector, target, value, bytesOp)
bytes4 selector = bytes4(_slice(op.callData, 0, 4));
bytes memory callData = _slice(op.callData, 4, op.callData.length - 4);

// set flags based on conditions
buffer = abi.encodePacked(buffer, bytes1(_flags(selector, op, callData)));
uint8 flags = _flags(selector, op, callData);
bytes memory buffer = abi.encodePacked(flags);

// encode `sender`, `nonce` and `initCode`
buffer = abi.encodePacked(buffer, op.sender, uint32(op.nonce), uint32(op.initCode.length), op.initCode);
console2.logBytes(buffer);

// encode `callData` depending on the selector
if (selector == IKintoWallet.execute.selector) {
Expand All @@ -165,10 +169,20 @@ contract KintoInflator is IOpInflator, OwnableUpgradeable, UUPSUpgradeable {

// encode gas params
buffer = abi.encodePacked(buffer, op.accountGasLimits, op.gasFees, uint32(op.preVerificationGas));
console2.logBytes(buffer);

// if there is a paymaster, then encode it's gas settings
if (flags & 0x02 == 0x02) {
buffer = abi.encodePacked(buffer, op.paymasterAndData[20:52]);
}

console2.log("op.signature.length:", op.signature.length);
console2.logBytes(op.signature);
// encode `signature` content
buffer = abi.encodePacked(buffer, uint32(op.signature.length), op.signature);

console2.logBytes(buffer);

return LibZip.flzCompress(buffer);
}

Expand Down
4 changes: 2 additions & 2 deletions src/paymasters/SponsorPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,8 @@ contract SponsorPaymaster is Initializable, BasePaymaster, UUPSUpgradeable, Reen
returns (bytes memory context, uint256 validationData)
{
(userOpHash);
if (userOp.preVerificationGas > MAX_COST_OF_PREVERIFICATION) revert GasTooHighForVerification();
if (userOp.paymasterAndData.length != 52) revert PaymasterAndDataLengthInvalid();

uint256 postOpGasLimit = userOp.unpackPostOpGasLimit();
uint256 verificationGasLimit = userOp.unpackVerificationGasLimit();
Expand All @@ -365,8 +367,6 @@ contract SponsorPaymaster is Initializable, BasePaymaster, UUPSUpgradeable, Reen
if (postOpGasLimit < COST_OF_POST || verificationGasLimit > MAX_COST_OF_VERIFICATION) {
revert GasOutsideRangeForPostOp();
}
if (userOp.preVerificationGas > MAX_COST_OF_PREVERIFICATION) revert GasTooHighForVerification();
if (userOp.paymasterAndData.length != 20) revert PaymasterAndDataLengthInvalid();

// use maxFeePerGas for conservative estimation of gas cost
uint256 ethMaxCost = (maxCost + COST_OF_POST * maxFeePerGas);
Expand Down
86 changes: 0 additions & 86 deletions test/data/swap-weth-to-usdm-arb.json
Original file line number Diff line number Diff line change
@@ -1,86 +0,0 @@
{
"blockNumber": "21408912",
"buyAmount": "3895183627890566214383",
"buyToken": "0x59d9356e565ab3a36dd77763fc0d87feaf85508c",
"fees": {
"integratorFee": null,
"zeroExFee": null,
"gasFee": null
},
"issues": {
"allowance": {
"actual": "83217",
"spender": "0x0000000000001ff3684f28c67538d4d072c22734"
},
"balance": {
"token": "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
"actual": "67412",
"expected": "1000000000000000000"
},
"simulationIncomplete": false,
"invalidSourcesPassed": []
},
"liquidityAvailable": true,
"minBuyAmount": "3856231791611660547900",
"route": {
"fills": [
{
"from": "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
"to": "0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f",
"source": "Uniswap_V3",
"proportionBps": "10000"
},
{
"from": "0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f",
"to": "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
"source": "WOOFi_V2",
"proportionBps": "10000"
},
{
"from": "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
"to": "0x59d9356e565ab3a36dd77763fc0d87feaf85508c",
"source": "Curve",
"proportionBps": "10000"
}
],
"tokens": [
{
"address": "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
"symbol": "WETH"
},
{
"address": "0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f",
"symbol": "WBTC"
},
{
"address": "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
"symbol": "USDC"
},
{
"address": "0x59d9356e565ab3a36dd77763fc0d87feaf85508c",
"symbol": "USDM"
}
]
},
"sellAmount": "1000000000000000000",
"sellToken": "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
"tokenMetadata": {
"buyToken": {
"buyTaxBps": "0",
"sellTaxBps": "0"
},
"sellToken": {
"buyTaxBps": "0",
"sellTaxBps": "0"
}
},
"totalNetworkFee": "14007900000000",
"transaction": {
"to": "0x0000000000001ff3684f28c67538d4d072c22734",
"data": "0x2213bc0b000000000000000000000000f3e01012ce60bb95ae294d5b24a9fc3af245b53b00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000f3e01012ce60bb95ae294d5b24a9fc3af245b53b00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000006641fff991f000000000000000000000000b7dfe09cf3950141dfb7db8abca90ddef8d06ec000000000000000000000000059d9356e565ab3a36dd77763fc0d87feaf85508c0000000000000000000000000000000000000000000000d10bf76f477531373c00000000000000000000000000000000000000000000000000000000000000a0d948b97cdacfe9371a1f156100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000018422ce6ede000000000000000000000000f3e01012ce60bb95ae294d5b24a9fc3af245b53b000000000000000000000000000000000000000000000000000000000000010000000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000675efb7f00000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c82af49447d8a07e3bd95bd0d56f35241523fbab1000001f42f2a2543b76a4166549f7aab2e75bef0aefc5b0f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a438c9c1470000000000000000000000002f2a2543b76a4166549f7aab2e75bef0aefc5b0f00000000000000000000000000000000000000000000000000000000000027100000000000000000000000004c4af8dbc524681930a27b2f1af5bcc8062e6fb7000000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c47dc203820000000000000000000000002f2a2543b76a4166549f7aab2e75bef0aefc5b0f000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583100000000000000000000000000000000000000000000000000000000003a1d060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f3e01012ce60bb95ae294d5b24a9fc3af245b53b0000000000000000000000005e01d320e95133d80dd59a2191c95728fa69036d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016438c9c147000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583100000000000000000000000000000000000000000000000000000000000027100000000000000000000000004bd135524897333bec344e50ddd85126554e58b4000000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000843df021240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gas": "1400790",
"gasPrice": "10000000",
"value": "0"
},
"zid": "0xd948b97cdacfe9371a1f1561"
}
8 changes: 7 additions & 1 deletion test/helpers/UserOp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {ECDSAUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/crypto

import {KintoWallet} from "@kinto-core/wallet/KintoWallet.sol";
import {KintoWalletFactory} from "@kinto-core/wallet/KintoWalletFactory.sol";

import {SignerHelper} from "@kinto-core-test/helpers/SignerHelper.sol";

import "forge-std/Vm.sol";
Expand All @@ -36,6 +37,9 @@ abstract contract UserOp is Test, SignerHelper {
uint256 constant MAX_FEE_PER_GAS = 1;
uint256 constant MAX_PRIORITY_FEE_PER_GAS = 1e9;

uint256 public constant MAX_COST_OF_VERIFICATION = 530_000;
uint256 public constant COST_OF_POST = 200_000;

struct OperationParamsBatch {
address[] targets;
uint256[] values;
Expand Down Expand Up @@ -85,7 +89,9 @@ abstract contract UserOp is Test, SignerHelper {
preVerificationGas: 21_000, // should also cover calldata cost.
accountGasLimits: packAccountGasLimits(210_000, gasLimits[0]),
gasFees: packAccountGasLimits(gasLimits[2], gasLimits[1]),
paymasterAndData: abi.encodePacked(paymaster),
paymasterAndData: paymaster != address(0)
? packPaymasterData(paymaster, MAX_COST_OF_VERIFICATION, COST_OF_POST, bytes(""))
: bytes(""),
signature: bytes("")
});

Expand Down
23 changes: 14 additions & 9 deletions test/unit/inflate/Inflator.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ contract InflatorTest is SharedSetup {

// 3. decompress (inflate) user op
PackedUserOperation memory decompressed = _inflator.inflate(compressed);

// assert that the decompressed user op is the same as the original
assertUserOperation(op, decompressed);
}

function testInflate_WhenDeployContract() public {
Expand Down Expand Up @@ -179,9 +182,11 @@ contract InflatorTest is SharedSetup {

// 2. compress user op
bytes memory compressed = _inflator.compress(op);
console2.logBytes(compressed);

// 3. decompress (inflate) user op
PackedUserOperation memory decompressed = _inflator.inflate(compressed);
console2.log("decompressed.sender:", decompressed.sender);

// assert that the decompressed user op is the same as the original
assertUserOperation(op, decompressed);
Expand Down Expand Up @@ -212,14 +217,14 @@ contract InflatorTest is SharedSetup {
}

function assertUserOperation(PackedUserOperation memory op, PackedUserOperation memory decompressed) internal {
assertEq(decompressed.sender, op.sender);
assertEq(decompressed.nonce, op.nonce);
assertEq(decompressed.initCode, op.initCode);
assertEq(decompressed.callData, op.callData);
assertEq(decompressed.accountGasLimits, op.accountGasLimits);
assertEq(decompressed.gasFees, op.gasFees);
assertEq(decompressed.preVerificationGas, op.preVerificationGas);
assertEq(decompressed.paymasterAndData, op.paymasterAndData);
assertEq(decompressed.signature, op.signature);
assertEq(decompressed.sender, op.sender, "Invalid sender");
assertEq(decompressed.nonce, op.nonce, "Invalid nonce");
assertEq(decompressed.initCode, op.initCode, "Invalid initCode");
assertEq(decompressed.callData, op.callData, "Invalid callData");
assertEq(decompressed.accountGasLimits, op.accountGasLimits, "Invalid accountGasLimits");
assertEq(decompressed.gasFees, op.gasFees, "Invalid gasFees");
assertEq(decompressed.preVerificationGas, op.preVerificationGas, "Invalid preVerificationGas");
assertEq(decompressed.paymasterAndData, op.paymasterAndData, "Invalid paymasterAndData");
assertEq(decompressed.signature, op.signature, "Invalid signature");
}
}

0 comments on commit 1294f44

Please sign in to comment.