Skip to content

Commit

Permalink
feat: Restructure HCHelper to be deployed with an upgradeable proxy.
Browse files Browse the repository at this point in the history
Add a maxCredit limit to the payment mechanism.

 Changes to be committed:
	new file:   crates/types/contracts/hc_scripts/CoreDeploy_v7.s.sol
	modified:   crates/types/contracts/hc_scripts/LocalDeploy_v7.s.sol
	modified:   crates/types/contracts/src/hc0_7/HCHelper.sol
	modified:   hybrid-compute/deploy-local.py
mmontour1306 committed Dec 17, 2024
1 parent 930b8bd commit a9a1195
Showing 4 changed files with 129 additions and 14 deletions.
74 changes: 74 additions & 0 deletions crates/types/contracts/hc_scripts/CoreDeploy_v7.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: UNLICENSED
// forge script --json --broadcast --via-ir --rpc-url <url> --contracts src/hc0_7 \
// --remappings @openzeppelin/=lib/openzeppelin-contracts-versions/v5_0
// --verifier-url <vfy> \
// hc_scripts/CoreDeploy_v7.sol

pragma solidity ^0.8.23;

import "forge-std/Script.sol";
import "lib/account-abstraction-versions/v0_7/contracts/core/EntryPoint.sol";
import "src/hc0_7/HCHelper.sol";
import "src/hc0_7/HybridAccountFactory.sol";

import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

contract CoreDeploy is Script {
function run() external
returns (address[4] memory) {
address deployAddr = vm.envAddress("DEPLOY_ADDR");
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address hcSysOwner = vm.envAddress("HC_SYS_OWNER");
uint256 deploySalt = vm.envUint("DEPLOY_SALT");

EntryPoint ept;
HCHelper helper;
HybridAccountFactory haf;
HybridAccount ha0;

bytes32 salt_val = bytes32(deploySalt);
uint112 min_deposit = 0.001 ether;

vm.startBroadcast(deployerPrivateKey);

// EntryPointAddr is hard-coded for the v0.7 implementation
ept = EntryPoint(payable(0x0000000071727De22E5E9d8BAf0edAc6f37da032));

HCHelper helperImpl = new HCHelper{salt: salt_val}(address(ept));

TransparentUpgradeableProxy hProxy = new TransparentUpgradeableProxy{salt: salt_val}(
address(helperImpl),
hcSysOwner,
abi.encodeCall(HCHelper.initialize, (deployAddr))
);
helper = HCHelper(address(hProxy));

{
address hafAddr = vm.envOr("HA_FACTORY_ADDR", 0x0000000000000000000000000000000000000000);
if (hafAddr != address(0) && hafAddr.code.length > 0) {
haf = HybridAccountFactory(hafAddr);
} else {
haf = new HybridAccountFactory{salt: salt_val}(ept, address(helper));
}
}
{
address ha0Addr = vm.envOr("HC_SYS_ACCOUNT", 0x0000000000000000000000000000000000000000);
if (ha0Addr != address(0) && ha0Addr.code.length > 0) {
ha0 = HybridAccount(payable(ha0Addr));
} else {
ha0 = haf.createAccount(hcSysOwner,0);
}
}
if (helper.systemAccount() != address(ha0)) {
helper.SetSystemAccount(address(ha0));
}

// Previous version deposited to EntryPoint, here we fund the acct directly
if (address(ha0).balance < min_deposit) {
payable(address(ha0)).transfer(min_deposit - address(ha0).balance);
}

vm.stopBroadcast();
return [address(ept),address(helper), address(haf), address(ha0)];
}
}
10 changes: 9 additions & 1 deletion crates/types/contracts/hc_scripts/LocalDeploy_v7.s.sol
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ import "lib/account-abstraction-versions/v0_7/contracts/core/EntryPoint.sol";
import "src/hc0_7/HCHelper.sol";
import "src/hc0_7/HybridAccountFactory.sol";
import "lib/account-abstraction-versions/v0_7/contracts/samples/SimpleAccountFactory.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

contract LocalDeploy is Script {
function run() external
@@ -37,7 +38,14 @@ contract LocalDeploy is Script {
if (helperAddr != address(0) && helperAddr.code.length > 0) {
helper = HCHelper(helperAddr);
} else {
helper = new HCHelper{salt: salt_val}(address(ept), bobaAddr, deployAddr);
HCHelper helperImpl = new HCHelper{salt: salt_val}(address(ept));

TransparentUpgradeableProxy hProxy = new TransparentUpgradeableProxy(
address(helperImpl),
hcSysOwner,
abi.encodeCall(HCHelper.initialize, (deployAddr))
);
helper = HCHelper(address(hProxy));
}
}
{
57 changes: 45 additions & 12 deletions crates/types/contracts/src/hc0_7/HCHelper.sol
Original file line number Diff line number Diff line change
@@ -4,9 +4,10 @@ pragma solidity ^0.8.12;
import "account-abstraction/v0_7/interfaces/INonceManager.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";

contract HCHelper is ReentrancyGuard, Ownable {
contract HCHelper is ReentrancyGuard, UUPSUpgradeable, Initializable {
using SafeERC20 for IERC20;

event SystemAccountSet(address oldAccount, address newAccount);
@@ -16,15 +17,26 @@ contract HCHelper is ReentrancyGuard, Ownable {
// Response data is stored here by PutResponse() and then consumed by TryCallOffchain().
mapping(bytes32=>bytes) ResponseCache;

// AA EntryPoint
address public immutable entryPoint;

// Owner
address public owner;

// Account which is used to insert system error responses. Currently a single
// address but could be extended to a list of authorized accounts if needed.
address public systemAccount;

// BOBA token address
address public tokenAddr;

// Token amount required to purchase each prepaid credit (may be 0 for testing)
uint256 public pricePerCall;

// Account which is used to insert system error responses. Currently a single
// address but could be extended to a list of authorized accounts if needed.
address public systemAccount;
// Limit on the maximum credit balance which an account may hold, enforced
// when purchasing credits. This allows system testing or temporary promotions
// with a low or zero credit price.
uint64 public maxCredits;

// Data stored per RegisteredCaller
struct callerInfo {
@@ -36,13 +48,29 @@ contract HCHelper is ReentrancyGuard, Ownable {
// Contracts which are allowed to use Hybrid Compute.
mapping(address=>callerInfo) public RegisteredCallers;

// AA EntryPoint
address immutable entryPoint;

modifier onlyOwner() {
_onlyOwner();
_;
}
function _onlyOwner() internal view {
require(msg.sender == owner || msg.sender == address(this), "only owner");
}

// Constructor
constructor(address _entryPoint, address _tokenAddr, address _owner) Ownable(_owner) {
constructor(address _entryPoint) {
entryPoint = _entryPoint;
tokenAddr = _tokenAddr;
}

// Set the initial owner
function initialize(address _owner) public virtual initializer {
owner = _owner;
}

// Allow upgrade through UUPSUpgradeable
function _authorizeUpgrade(address newImplementation) internal view override {
(newImplementation);
_onlyOwner();
}

// Change the SystemAccount address (used for error responses)
@@ -59,17 +87,22 @@ contract HCHelper is ReentrancyGuard, Ownable {
emit RegisteredUrl(contract_addr, url);
}

// Set or change the per-call token price (0 is allowed). Does not affect
// existing credit balances, only applies to new AddCredit() calls.
function SetPrice(uint256 _pricePerCall) public onlyOwner {
// Set or change the per-call token price (0 is allowed), token,
// and maximum credit balance. Does not affect existing balances,
// only new AddCredit() purchases.
function SetPaymentInfo(address _tokenAddr, uint256 _pricePerCall, uint64 _maxCredits) public onlyOwner {
tokenAddr = _tokenAddr;
pricePerCall = _pricePerCall;
maxCredits = _maxCredits;
}

// Purchase credits allowing the specified contract to perform HC calls.
// The token cost is (pricePerCall() * numCredits) and is non-refundable
function AddCredit(address contract_addr, uint256 numCredits) public nonReentrant {
require(tokenAddr != address(0), "Payment info not initialized");
uint256 tokenPrice = numCredits * pricePerCall;
RegisteredCallers[contract_addr].credits += numCredits;
require(RegisteredCallers[contract_addr].credits <= maxCredits, "Purchase exceeds maxCredits limit");
IERC20(tokenAddr).safeTransferFrom(msg.sender, address(this), tokenPrice);
}

2 changes: 1 addition & 1 deletion hybrid-compute/deploy-local.py
Original file line number Diff line number Diff line change
@@ -389,7 +389,7 @@ def boba_balance(addr):
HH = load_contract(w3, 'HCHelper', OUT_PREFIX + "HCHelper.sol/HCHelper.json", hh_addr)
l2_util.approve_token(boba_token, HH.address, deploy_addr, deploy_key)

tx = HH.functions.SetPrice(Web3.to_wei(0.1,'ether')). build_transaction({
tx = HH.functions.SetPaymentInfo(boba_token, Web3.to_wei(0.1,'ether'), 1000000). build_transaction({
'from': deploy_addr,
})
l2_util.sign_and_submit(tx, deploy_key)

0 comments on commit a9a1195

Please sign in to comment.