-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #119 from sablier-labs/feat/precompiles
feat: precompiles
- Loading branch information
Showing
9 changed files
with
238 additions
and
8 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 |
---|---|---|
|
@@ -8,3 +8,4 @@ | |
forge-std/=lib/forge-std/src/ | ||
permit2/=lib/permit2/src/ | ||
permit2-test/=lib/permit2/test/ | ||
solady/=lib/solady/src/ |
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,31 @@ | ||
#!/usr/bin/env bash | ||
|
||
# Pre-requisites: | ||
# - foundry (https://getfoundry.sh) | ||
# - jq (https://stedolan.github.io/jq) | ||
# - sd (https://github.com/chmln/sd) | ||
|
||
# Strict mode: https://gist.github.com/vncsna/64825d5609c146e80de8b1fd623011ca | ||
set -euo pipefail | ||
|
||
# Compile the contracts with Forge | ||
FOUNDRY_PROFILE=optimized forge build | ||
|
||
# Retrieve the raw bytecodes, removing the "0x" prefix | ||
archive=$(cat out-optimized/SablierV2Archive.sol/SablierV2Archive.json | jq -r '.bytecode.object' | cut -c 3-) | ||
proxy_plugin=$(cat out-optimized/SablierV2ProxyPlugin.sol/SablierV2ProxyPlugin.json | jq -r '.bytecode.object' | cut -c 3-) | ||
proxy_target=$(cat out-optimized/SablierV2ProxyTarget.sol/SablierV2ProxyTarget.json | jq -r '.bytecode.object' | cut -c 3-) | ||
|
||
precompiles_path="test/utils/Precompiles.sol" | ||
if [ ! -f $precompiles_path ]; then | ||
echo "Precompiles file does not exist" | ||
exit 1 | ||
fi | ||
|
||
# Replace the current bytecodes | ||
sd "(BYTECODE_ARCHIVE =)[^;]+;" "\$1 hex\"$archive\";" $precompiles_path | ||
sd "(BYTECODE_PROXY_PLUGIN =)[^;]+;" "\$1 hex\"$proxy_plugin\";" $precompiles_path | ||
sd "(BYTECODE_PROXY_TARGET =)[^;]+;" "\$1 hex\"$proxy_target\";" $precompiles_path | ||
|
||
# Reformat the code with Forge | ||
forge fmt $precompiles_path |
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
Large diffs are not rendered by default.
Oops, something went wrong.
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,91 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.8.19 <=0.9.0; | ||
|
||
import { IAllowanceTransfer } from "permit2/interfaces/IAllowanceTransfer.sol"; | ||
import { DeployPermit2 } from "permit2-test/utils/DeployPermit2.sol"; | ||
import { LibString } from "solady/utils/LibString.sol"; | ||
|
||
import { ISablierV2Archive } from "../../src/interfaces/ISablierV2Archive.sol"; | ||
import { ISablierV2ProxyPlugin } from "../../src/interfaces/ISablierV2ProxyPlugin.sol"; | ||
import { ISablierV2ProxyTarget } from "../../src/interfaces/ISablierV2ProxyTarget.sol"; | ||
|
||
import { Base_Test } from "../Base.t.sol"; | ||
import { Precompiles } from "./Precompiles.sol"; | ||
|
||
contract Precompiles_Test is Base_Test { | ||
using LibString for address; | ||
using LibString for string; | ||
|
||
Precompiles internal precompiles = new Precompiles(); | ||
|
||
modifier onlyTestOptimizedProfile() { | ||
if (isTestOptimizedProfile()) { | ||
_; | ||
} | ||
} | ||
|
||
function test_DeployArchive() external onlyTestOptimizedProfile { | ||
address actualArchive = address(precompiles.deployArchive(users.admin.addr)); | ||
address expectedArchive = address(deployPrecompiledArchive(users.admin.addr)); | ||
assertEq(actualArchive.code, expectedArchive.code, "bytecodes mismatch"); | ||
} | ||
|
||
function test_DeployProxyPlugin() external onlyTestOptimizedProfile { | ||
ISablierV2Archive archive = deployPrecompiledArchive(users.admin.addr); | ||
address actualProxyPlugin = address(precompiles.deployProxyPlugin(archive)); | ||
address expectedProxyPlugin = address(deployPrecompiledProxyPlugin(archive)); | ||
bytes memory expectedProxyPluginCode = | ||
adjustBytecode(expectedProxyPlugin.code, expectedProxyPlugin, actualProxyPlugin); | ||
assertEq(actualProxyPlugin.code, expectedProxyPluginCode, "bytecodes mismatch"); | ||
} | ||
|
||
function test_DeployProxyTarget() external onlyTestOptimizedProfile { | ||
IAllowanceTransfer permit2 = IAllowanceTransfer(new DeployPermit2().run()); | ||
address actualProxyTarget = address(precompiles.deployProxyTarget(permit2)); | ||
address expectedProxyTarget = address(deployPrecompiledProxyTarget(permit2)); | ||
bytes memory expectedProxyTargetCode = | ||
adjustBytecode(expectedProxyTarget.code, expectedProxyTarget, actualProxyTarget); | ||
assertEq(actualProxyTarget.code, expectedProxyTargetCode, "bytecodes mismatch"); | ||
} | ||
|
||
function test_DeployPeriphery() external onlyTestOptimizedProfile { | ||
IAllowanceTransfer permit2 = IAllowanceTransfer(new DeployPermit2().run()); | ||
( | ||
ISablierV2Archive actualArchive, | ||
ISablierV2ProxyPlugin actualProxyPlugin, | ||
ISablierV2ProxyTarget actualProxyTarget | ||
) = precompiles.deployPeriphery(users.admin.addr, permit2); | ||
|
||
address expectedArchive = address(deployPrecompiledArchive(users.admin.addr)); | ||
assertEq(address(actualArchive).code, expectedArchive.code, "bytecodes mismatch"); | ||
|
||
address expectedProxyPlugin = address(deployPrecompiledProxyPlugin(actualArchive)); | ||
bytes memory expectedLockupDynamicCode = | ||
adjustBytecode(expectedProxyPlugin.code, expectedProxyPlugin, address(actualProxyPlugin)); | ||
assertEq(address(actualProxyPlugin).code, expectedLockupDynamicCode, "bytecodes mismatch"); | ||
|
||
address expectedProxyTarget = address(deployPrecompiledProxyTarget(permit2)); | ||
bytes memory expectedProxyTargetCode = | ||
adjustBytecode(expectedProxyTarget.code, expectedProxyTarget, address(actualProxyTarget)); | ||
assertEq(address(actualProxyTarget).code, expectedProxyTargetCode, "bytecodes mismatch"); | ||
} | ||
|
||
/// @dev The expected bytecode has to be adjusted because some contracts inherit from {OnlyDelegateCall}, which | ||
/// saves the contract's own address in storage. | ||
function adjustBytecode( | ||
bytes memory bytecode, | ||
address expectedAddress, | ||
address actualAddress | ||
) | ||
internal | ||
pure | ||
returns (bytes memory) | ||
{ | ||
return vm.parseBytes( | ||
vm.toString(bytecode).replace({ | ||
search: expectedAddress.toHexStringNoPrefix(), | ||
replacement: actualAddress.toHexStringNoPrefix() | ||
}) | ||
); | ||
} | ||
} |