Skip to content

sprites0/hl-multisig-api-contract

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

One-Time API Wallet using Nick's Method

Overview

This implementation creates a "one-time API wallet" using Nick's Method for keyless execution. The wallet can only execute ONE specific pre-authorized action, providing a secure way to delegate limited permissions without maintaining a private key.

How It Works

Nick's Method Basics

Nick's Method enables "keyless execution" by:

  1. Creating a phantom signature: Using fixed signature components (v, r, s) - they don't need to be random
  2. Recovering the phantom address: Using ecrecover(messageHash, v, r, s) to find the address that would "sign" that message
  3. Single-use execution: Since no one controls the private key, the signature only works for ONE specific message

One-Time API Wallet Application

┌─────────────────────────────────────────────────────────┐
│  Step 1: Define the specific action to authorize       │
│  (e.g., send 100 tokens to Alice)                       │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Step 2: Hash the action data                           │
│  actionHash = keccak256(actionData)                      │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Step 3: Use fixed signature values (v, r, s)           │
│  v = 27 (pre-EIP155)                                     │
│  r, s = fixed values (e.g., 1)                           │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Step 4: Recover phantom wallet address                 │
│  phantomWallet = ecrecover(actionHash, v, r, s)          │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Step 5: Add phantom wallet as API wallet                │
│  This gives it permission to execute core actions        │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Result: Phantom wallet can ONLY execute the ONE         │
│  action that matches actionHash with signature (v,r,s)   │
└─────────────────────────────────────────────────────────┘

Key Properties

  1. Single-use: The wallet can only execute the ONE specific action that was hashed
  2. Keyless: No private key exists - the address is deterministically generated
  3. Non-replayable: After execution, the action cannot be replayed (system tracks executed actions)
  4. Trustless: No centralized key holder required

Usage Example

Solidity

import {CoreWriterLib} from "./CoreWriterLib.sol";

contract MyContract {
    using CoreWriterLib for *;

    function createOneTimeSpotSend() external {
        // 1. Define the specific action
        address recipient = 0x1234...;
        uint64 token = 0;
        uint64 amount = 1000;

        bytes memory actionData = abi.encodePacked(
            uint8(1),
            SPOT_SEND_ACTION,
            abi.encode(recipient, token, amount)
        );

        // 2. Hash the action
        bytes32 actionHash = CoreWriterLib.computeActionHash(actionData);

        // 3. Create the one-time API wallet (uses fixed signature values internally)
        address phantomWallet = CoreWriterLib.addOneTimeApiWallet(
            actionHash,
            "OneTime-SpotSend"
        );

        // Now phantomWallet can ONLY execute the specific spot send action
    }
}

Note on Signature Values

The signature values (v, r, s) do not need to be random. The library uses fixed values internally:

  • v = 27 (pre-EIP155)
  • r = 0x0000000000000000000000000000000000000000000000000000000000000001
  • s = 0x0000000000000000000000000000000000000000000000000000000000000001

These fixed values simply derive a deterministic phantom address via ecrecover. The security comes from the fact that:

  1. No one has the private key to the phantom address
  2. The signature only works for the specific action hash
  3. Each unique action hash produces a different phantom address

Security Considerations

Why This Is Secure

  1. Collision resistance: The probability of someone else controlling the phantom address is ~2^-160 (extremely low)
  2. Action-specific: The signature only validates for the exact action that was hashed
  3. Single execution: Once executed, the system marks it as processed (implementation-dependent)

Limitations

  1. Action must be deterministic: The action data must be exactly as specified
  2. Pre-EIP155: Uses v=27 for cross-chain compatibility, no replay protection
  3. Requires coordination: The action data must be known in advance

Comparison with Regular API Wallet

Feature Regular API Wallet One-Time API Wallet
Actions Unlimited Only ONE specific action
Private Key Required None (keyless)
Revocation Can be revoked Self-destructing after use
Use Case Long-term delegation Single authorized transaction

Use Cases

  1. Pre-authorized trading: Allow a bot to execute ONE specific trade
  2. Scheduled transfers: Set up a future transfer without maintaining keys
  3. Conditional execution: Create an action that can only happen once
  4. Trustless delegation: Give temporary permission without key sharing

Implementation Details

Files

  • src/CoreWriterLib.sol - Main implementation (lines 178-216)
  • src/examples/OneTimeApiWalletExample.sol - Usage examples
  • scripts/generate_one_time_wallet.py - Python helper script

Functions

function addOneTimeApiWallet(
    bytes32 actionHash,
    string memory name
) internal returns (address phantomWallet)

Parameters:

  • actionHash: keccak256 hash of the specific action to authorize
  • name: Human-readable name for the wallet

For advanced use cases requiring custom signature values:

function _addOneTimeApiWalletWithSignature(
    bytes32 actionHash,
    uint8 v,
    bytes32 r,
    bytes32 s,
    string memory name
) internal returns (address phantomWallet)

Returns:

  • phantomWallet: The deterministically generated address

References

License

MIT

About

One-time HyperCore action approval from HyperEVM contract

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors