Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions snapshots/SignatureGateway.Operations.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"borrowWithSig": "215893",
"repayWithSig": "189160",
"setSelfAsUserPositionManagerWithSig": "75402",
"setSelfAsUserPositionManagerWithSig": "74858",
"setUsingAsCollateralWithSig": "85053",
"supplyWithSig": "153205",
"updateUserDynamicConfigWithSig": "62769",
"updateUserRiskPremiumWithSig": "61579",
"withdrawWithSig": "131696"
"withdrawWithSig": "131713"
}
21 changes: 12 additions & 9 deletions src/position-manager/SignatureGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,21 @@ contract SignatureGateway is ISignatureGateway, GatewayBase, NoncesKeyed, Multic
/// @inheritdoc ISignatureGateway
function setSelfAsUserPositionManagerWithSig(
address spoke,
EIP712Types.SetUserPositionManager calldata params,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think this struct now is never used in src, can rm here or in valentin's posm pr

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to refactor the types & typehash to move them to related Interfaces, and split up the EIP712 Hashes lib for each use cases, so ig better to make a PR just for that refactor, so that this PR and other impacted by signature type rft can rebase afterwards and prevent too much conflicts

address user,
bool approve,
uint256 nonce,
uint256 deadline,
bytes calldata signature
) external onlyRegisteredSpoke(spoke) {
try
ISpoke(spoke).setUserPositionManagerWithSig(
address(this),
params.user,
params.approve,
params.nonce,
params.deadline,
signature
)
ISpoke(spoke).setUserPositionManagerWithSig({
positionManager: address(this),
user: user,
approve: approve,
nonce: nonce,
deadline: deadline,
signature: signature
})
{} catch {}
}

Expand Down
12 changes: 9 additions & 3 deletions src/position-manager/interfaces/ISignatureGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,18 @@ interface ISignatureGateway is IMulticall, INoncesKeyed, IGatewayBase {
/// with a typed signature from `user`.
/// @dev The signature is consumed on the the specified registered `spoke`.
/// @dev The given data is passed to the `spoke` for the signature to be verified.
/// @param spoke The address of the spoke.
/// @param params The structured setSelfAsUserPositionManager parameters.
/// @param spoke The address of the registered spoke.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why registered added, you mean this sig gateway is registered on the spoke, not that spoke necessarily needs to be registered on hub yes?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, that the given spoke needs to be registered as valid target by the Gateway/PosM. See onlyRegisteredSpoke modifier.

/// @param user The address of the user on whose behalf this gateway can act.
/// @param approve True to approve the gateway, false to revoke approval.
/// @param nonce The key-prefixed nonce for the signature.
/// @param deadline The deadline for the signature.
/// @param signature The signed bytes for the intent.
function setSelfAsUserPositionManagerWithSig(
address spoke,
EIP712Types.SetUserPositionManager calldata params,
address user,
bool approve,
uint256 nonce,
uint256 deadline,
bytes calldata signature
) external;

Expand Down
9 changes: 8 additions & 1 deletion tests/gas/Gateways.Operations.gas.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,14 @@ contract SignatureGateway_Gas_Tests is SignatureGatewayBaseTest {
vm.prank(alice);
spoke1.setUserPositionManager(address(gateway), false);

gateway.setSelfAsUserPositionManagerWithSig(address(spoke1), p, signature);
gateway.setSelfAsUserPositionManagerWithSig({
spoke: address(spoke1),
user: p.user,
approve: p.approve,
nonce: p.nonce,
deadline: p.deadline,
signature: signature
});
vm.snapshotGasLastCall(NAMESPACE, 'setSelfAsUserPositionManagerWithSig');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import 'tests/unit/misc/SignatureGateway/SignatureGateway.Base.t.sol';

contract SignatureGatewaySetSelfAsUserPositionManagerTest is SignatureGatewayBaseTest {
function test_setSelfAsUserPositionManagerWithSig_revertsWith_SpokeNotRegistered() public {
vm.expectRevert(IGatewayBase.SpokeNotRegistered.selector);
vm.prank(vm.randomAddress());
gateway.setSelfAsUserPositionManagerWithSig({
spoke: address(spoke2),
user: vm.randomAddress(),
approve: vm.randomBool(),
nonce: vm.randomUint(),
deadline: vm.randomUint(),
signature: vm.randomBytes(72)
});
}

function test_setSelfAsUserPositionManagerWithSig_forwards_correct_call() public {
address user = vm.randomAddress();
bool approve = vm.randomBool();
uint256 nonce = vm.randomUint();
uint256 deadline = vm.randomUint();
bytes memory signature = vm.randomBytes(72);

vm.expectCall(
address(spoke1),
abi.encodeCall(
ISpoke.setUserPositionManagerWithSig,
(address(gateway), user, approve, nonce, deadline, signature)
),
1
);
vm.prank(vm.randomAddress());
gateway.setSelfAsUserPositionManagerWithSig({
spoke: address(spoke1),
user: user,
approve: approve,
nonce: nonce,
deadline: deadline,
signature: signature
});
}

function test_setSelfAsUserPositionManagerWithSig_ignores_underlying_spoke_reverts() public {
vm.mockCallRevert(
address(spoke1),
ISpoke.setUserPositionManagerWithSig.selector,
vm.randomBytes(64)
);

vm.prank(vm.randomAddress());
gateway.setSelfAsUserPositionManagerWithSig({
spoke: address(spoke1),
user: vm.randomAddress(),
approve: vm.randomBool(),
nonce: vm.randomUint(),
deadline: vm.randomUint(),
signature: vm.randomBytes(72)
});

assertFalse(spoke1.isPositionManager(alice, address(gateway)));
}

function test_setSelfAsUserPositionManagerWithSig() public {
uint192 nonceKey = _randomNonceKey();
vm.prank(alice);
spoke1.useNonce(nonceKey);
EIP712Types.SetUserPositionManager memory p = EIP712Types.SetUserPositionManager({
positionManager: address(gateway),
user: alice,
approve: true,
nonce: spoke1.nonces(alice, nonceKey), // note: this typed sig is forwarded to spoke
deadline: _warpBeforeRandomDeadline()
});
bytes memory signature = _sign(alicePk, _getTypedDataHash(spoke1, p));

vm.prank(SPOKE_ADMIN);
spoke1.updatePositionManager(address(gateway), true);
vm.prank(alice);
spoke1.setUserPositionManager(address(gateway), false);

gateway.setSelfAsUserPositionManagerWithSig({
spoke: address(spoke1),
user: p.user,
approve: p.approve,
nonce: p.nonce,
deadline: p.deadline,
signature: signature
});

assertTrue(spoke1.isPositionManager(alice, address(gateway)));
}
}
9 changes: 8 additions & 1 deletion tests/unit/misc/SignatureGateway/SignatureGateway.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,14 @@ contract SignatureGatewayTest is SignatureGatewayBaseTest {
emit ISpoke.SetUserPositionManager(alice, address(gateway), p.approve);

vm.prank(vm.randomAddress());
gateway.setSelfAsUserPositionManagerWithSig(address(spoke1), p, signature);
gateway.setSelfAsUserPositionManagerWithSig({
spoke: address(spoke1),
user: p.user,
approve: p.approve,
nonce: p.nonce,
deadline: p.deadline,
signature: signature
});

_assertNonceIncrement(ISignatureGateway(address(spoke1)), alice, p.nonce); // note: nonce consumed on spoke
_assertGatewayHasNoBalanceOrAllowance(spoke1, gateway, alice);
Expand Down
Loading