-
Notifications
You must be signed in to change notification settings - Fork 311
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
<!--- Please provide a general summary of your changes in the title above --> <!-- Give an estimate of the time you spent on this PR in terms of work days. Did you spend 0.5 days on this PR or rather 2 days? --> Time spent on this PR: ## Pull request type <!-- Please try to limit your pull request to one type, submit multiple pull requests if needed. --> Please check the type of change your PR introduces: - [ ] Bugfix - [ ] Feature - [ ] Code style update (formatting, renaming) - [ ] Refactoring (no functional changes, no api changes) - [ ] Build related changes - [ ] Documentation content changes - [ ] Other (please describe): ## What is the current behavior? <!-- Please describe the current behavior that you are modifying, or link to a relevant issue. --> Resolves #1127 Resolves #1125 Closes #1128 ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - - - <!-- Reviewable:start --> - - - This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/kkrt-labs/kakarot/1129) <!-- Reviewable:end -->
- Loading branch information
Showing
18 changed files
with
233 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[profile.default] | ||
src = 'src' | ||
test = 'tests' | ||
out = '../solidity_contracts/build' | ||
libs = ['../lib'] | ||
|
||
[rpc_endpoints] | ||
anvil = "http://127.0.0.1:8545" | ||
kakarot = "http://127.0.0.1:3030" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.23; | ||
|
||
/// @title BaseAuth | ||
/// @author Anna Carroll <https://github.com/anna-carroll/3074> | ||
abstract contract BaseAuth { | ||
/// @notice magic byte to disambiguate EIP-3074 signature payloads | ||
uint8 constant MAGIC = 0x04; | ||
|
||
/// @notice produce a digest for the authorizer to sign | ||
/// @param commit - any 32-byte value used to commit to transaction validity conditions | ||
/// @param nonce - signer's current nonce | ||
/// @return digest - sign the `digest` to authorize the invoker to execute the `calls` | ||
/// @dev signing `digest` authorizes this contact to execute code on behalf of the signer | ||
/// the logic of the inheriting contract should encode rules which respect the information within `commit` | ||
/// @dev the authorizer includes `commit` in their signature to ensure the authorized contract will only execute intended actions(s). | ||
/// the Invoker logic MUST implement constraints on the contract execution based on information in the `commit`; | ||
/// otherwise, any EOA that signs an AUTH for the Invoker will be compromised | ||
/// @dev per EIP-3074, digest = keccak256(MAGIC || paddedChainId || paddedNonce || paddedInvokerAddress || commit) | ||
function getDigest(bytes32 commit, uint256 nonce) public view returns (bytes32 digest) { | ||
digest = | ||
keccak256(abi.encodePacked(MAGIC, bytes32(block.chainid), bytes32(nonce), bytes32(uint256(uint160(address(this)))), commit)); | ||
} | ||
|
||
function authSimple(address authority, bytes32 commit, uint8 v, bytes32 r, bytes32 s) | ||
internal | ||
pure | ||
returns (bool success) | ||
{ | ||
bytes memory authArgs = abi.encodePacked(yParity(v), r, s, commit); | ||
assembly { | ||
success := auth(authority, add(authArgs, 0x20), mload(authArgs)) | ||
} | ||
} | ||
|
||
function authCallSimple(address to, bytes memory data, uint256 value, uint256 gasLimit) | ||
internal | ||
returns (bool success) | ||
{ | ||
assembly { | ||
success := authcall(gasLimit, to, value, add(data, 0x20), mload(data), 0, 0) | ||
} | ||
} | ||
|
||
/// @dev Internal helper to convert `v` to `yParity` for `AUTH` | ||
function yParity(uint8 v) private pure returns (uint8 yParity_) { | ||
assembly { | ||
switch lt(v, 35) | ||
case true { yParity_ := eq(v, 28) } | ||
default { yParity_ := mod(sub(v, 35), 2) } | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.23; | ||
|
||
import { BaseAuth } from "./BaseAuth.sol"; | ||
|
||
/// @title Gas Sponsor Invoker | ||
/// @notice Invoker contract using EIP-3074 to sponsor gas for authorized transactions | ||
contract GasSponsorInvoker is BaseAuth { | ||
/// @notice Executes a call authorized by an external account (EOA) | ||
/// @param authority The address of the authorizing external account | ||
/// @param commit A 32-byte value committing to transaction validity conditions | ||
/// @param v The recovery byte of the signature | ||
/// @param r Half of the ECDSA signature pair | ||
/// @param s Half of the ECDSA signature pair | ||
/// @param to The target contract address to call | ||
/// @param data The data payload for the call | ||
/// @return success True if the call was successful | ||
function sponsorCall( | ||
address authority, | ||
bytes32 commit, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s, | ||
address to, | ||
bytes calldata data | ||
) external returns (bool success) { | ||
// Ensure the transaction is authorized by the signer | ||
require(authSimple(authority, commit, v, r, s), "Authorization failed"); | ||
|
||
// Execute the call as authorized by the signer | ||
success = authCallSimple(to, data, 0, 0); | ||
require(success, "Call execution failed"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.23; | ||
|
||
contract SenderRecorder { | ||
address public lastSender; | ||
|
||
function recordSender() external { | ||
lastSender = msg.sender; | ||
} | ||
|
||
function reset() external { | ||
lastSender = address(0); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import pytest_asyncio | ||
|
||
|
||
@pytest_asyncio.fixture(scope="package") | ||
async def gas_sponsor_invoker(deploy_contract, owner): | ||
return await deploy_contract( | ||
"EIP3074", | ||
"GasSponsorInvoker", | ||
caller_eoa=owner.starknet_contract, | ||
) | ||
|
||
|
||
@pytest_asyncio.fixture(scope="package") | ||
async def sender_recorder(deploy_contract, owner): | ||
return await deploy_contract( | ||
"EIP3074", | ||
"SenderRecorder", | ||
caller_eoa=owner.starknet_contract, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import pytest | ||
from eth_utils import keccak | ||
|
||
from tests.utils.helpers import ec_sign | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
def commit(): | ||
return keccak(b"Some unique commit data") | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
async def cleanup(sender_recorder): | ||
yield | ||
await sender_recorder.reset() | ||
|
||
|
||
@pytest.mark.asyncio(scope="package") | ||
@pytest.mark.EIP3074 | ||
class TestEIP3074: | ||
class TestEIP3074Integration: | ||
async def test_should_execute_authorized_call( | ||
self, gas_sponsor_invoker, sender_recorder, other, commit | ||
): | ||
initial_sender = await sender_recorder.lastSender() | ||
assert int(initial_sender, 16) == 0 | ||
signer_nonce = await other.starknet_contract.get_nonce() | ||
digest = await gas_sponsor_invoker.getDigest(commit, signer_nonce) | ||
v, r_, s_ = ec_sign(digest, other.private_key) | ||
|
||
calldata = sender_recorder.get_function_by_name( | ||
"recordSender" | ||
)()._encode_transaction_data() | ||
|
||
await gas_sponsor_invoker.sponsorCall( | ||
other.address, commit, v, r_, s_, sender_recorder.address, calldata | ||
) | ||
last_sender = await sender_recorder.lastSender() | ||
assert last_sender == other.address |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.