Set of solidity utilities to ease deployment and usage of applications on AlphaNet.
Functions to allow calling each of the BLS precompiles defined in EIP-2537 without the low level details.
For example, this is how the library can be used from a solidity smart contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {BLS} from "/path/to/forge-alphanet/src/sign/BLS.sol";
contract BLSExample {
event OperationResult(bool success, bytes result);
// Function to perform a BLS12-381 G1 addition with error handling
function performG1Add(bytes memory input) public {
(bool success, bytes memory output) = BLS.G1Add(input);
if (!success) {
emit OperationResult(false, "");
} else {
emit OperationResult(true, output);
}
}
}
Provides functionality to call the P256VERIFY
precompile defined in EIP-7212
to verify Secp256r1 signatures.
It can be used in a solidity smart contract like this:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {Secp256r1} from "/path/to/forge-alphanet/src/sign/Secp256r1.sol";
contract Secp256r1Example {
event OperationResult(bool success);
// Function to perform a Secp256r1 signature verification with error handling
function performP256Verify(bytes memory input) public {
bool result = Secp256r1.verify(input);
emit OperationResult(result);
}
}
NOTE These invokers temporarily only work with the docker image from
foundry-alphanet which contains patched versions of solc and forge compatible with
EIP-3074 instructions. You can pull Foundry Alphanet using docker pull ghcr.io/paradigmxyz/foundry-alphanet:latest
, see the README on how to operate it.
The GasSponsorInvoker is a smart contract designed to utilize EIP-3074 auth and authcall operations, allowing transactions to be sponsored in terms of gas fees. This contract enables an external account (EOA) to authorize the invoker to execute specific actions on its behalf without requiring the EOA to provide gas for these transactions.
- Compile the Contract: you can use the following command:
$ make build
- Deploy the contract to AlphaNet:
$ forge create GasSponsorInvoker --private-key <your-private-key> --rpc-url <alphanet-rpc-url>
Take note of GasSponsorInvoker address.
- Define target contract
Imagine a simple contract Greeter that stores
msg.sender
in a variable:
contract Greeter {
address public greeter;
function setGreeter() public {
greeter = msg.sender;
}
}
- Authorizing a transaction To authorize a transaction, the authorizer signs a digest of the transaction details. This process is streamlined by our invoker interface:
- Create the authorizer account and note its private key and address:
$ cast wallet new
- Deploy
Greeter
and note its address. - Get the
setGreeter
method calldata:
$ cast calldata "setGreeter()"
- Generate the digest:
$ cast call <GasSponsorInvoker-address> "getDigest(address,bytes)" <Greeter-address> <setGreeter-calldata> --rpc-url <alphanet-rpc-url>
- Sign the digest
$ cast sign <digest> --private-key <authorizer-private-key>
This gives the v
, r
and s
values of the signature.
- Interacting with
GasSponsorInvoker
Now you can send a transaction to be executed as if by the authorizer account with the gas paid by a different account:
- Send the transaction to
GasSponsorInvoker
from an gas sponsor account ( different from the authorizer and with funds in AlphaNet):
$ cast send <GasSponsorInvoker-address> \
"sponsorCall(address,bytes32,uint8,bytes32,bytes32,address,bytes,uint256,uint256)" \
<authorizer-address> \
<signature-v> \
<signature-r> \
<signature-v> \
<Greeter-address> \
<Greeter-calldata> \
0 \
0 \
--rpc-url <alphanet-rpc-url> \
--private-key <sponsor-private-key>
- Now you can check that the Greeter smart contract register as
msg.sender
the authorizer account:
$ cast call <Greeter-address> "greeter()" --rpc-url <alphanet-rpc-url>