Skip to content

Commit 7af2bc2

Browse files
committed
✨ feat: add demo command and integrate mantle registry
- Introduced a new demo command in main.go to facilitate a full agentic demonstration. - Added a new registry.go file in the mantle adapter, defining the SettlerRegistryABI and related functionalities for agent payment logging.
1 parent 76baab7 commit 7af2bc2

2 files changed

Lines changed: 152 additions & 0 deletions

File tree

cmd/settler/main.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"time"
1313

1414
"github.com/ethereum/go-ethereum/common"
15+
"github.com/nathfavour/settlerengine/internal/adapters/crypto/erc8004"
16+
"github.com/nathfavour/settlerengine/internal/adapters/crypto/mantle"
1517
"github.com/nathfavour/settlerengine/internal/domain"
1618
"github.com/nathfavour/settlerengine/pkg/anyisland"
1719
"github.com/nathfavour/settlerengine/pkg/crypto"
@@ -41,6 +43,8 @@ func main() {
4143
runFacilitator(os.Args[2:])
4244
case "pay":
4345
runPay(os.Args[2:])
46+
case "demo":
47+
runDemo(os.Args[2:])
4448
case "help":
4549
printUsage()
4650
default:
@@ -58,9 +62,75 @@ func printUsage() {
5862
fmt.Println(" proxy Start the x402 reverse proxy")
5963
fmt.Println(" facilitator Start the settlement facilitator daemon")
6064
fmt.Println(" pay Execute a policy-protected payment")
65+
fmt.Println(" demo Run a full agentic demo with Mantle on-chain anchoring")
6166
fmt.Println(" help Show this help message")
6267
}
6368

69+
func runDemo(args []string) {
70+
fmt.Println("🎬 Starting SettlerEngine Agentic Demo...")
71+
72+
privKey := os.Getenv("PRIVATE_KEY")
73+
if privKey == "" {
74+
log.Fatal("❌ PRIVATE_KEY environment variable is required for demo")
75+
}
76+
77+
// 1. ERC-8004 Identity Resolution
78+
fmt.Println("🤖 [1/3] Resolving Agent Identity (ERC-8004)...")
79+
registry, _ := erc8004.NewRegistryClient(
80+
"https://rpc.sepolia.mantle.xyz",
81+
common.HexToAddress("0x8004000000000000000000000000000000000001"),
82+
common.HexToAddress("0x8004000000000000000000000000000000000002"),
83+
common.HexToAddress("0x8004000000000000000000000000000000000003"),
84+
)
85+
86+
agentID := big.NewInt(42)
87+
identity, _ := registry.ResolveAgent(context.Background(), agentID)
88+
fmt.Printf("✅ Identity Verified: %s\n", identity.Metadata.Name)
89+
90+
// 2. Policy-Protected Payment Handshake
91+
fmt.Println("💰 [2/3] Performing Policy-Protected Payment...")
92+
max, _ := new(big.Int).SetString("1000000000000000000", 10)
93+
policy := domain.NewPaymentPolicy("demo-policy", max, nil, time.Time{})
94+
95+
amount := big.NewInt(1000)
96+
recipient := common.HexToAddress("0x1234567890123456789012345678901234567890")
97+
98+
if err := policy.Check(amount, recipient); err != nil {
99+
log.Fatalf("❌ Policy Violation: %v", err)
100+
}
101+
fmt.Println("✅ Payment Approved by local guardrails.")
102+
103+
// 3. Mantle On-Chain Anchoring
104+
fmt.Println("⚓ [3/3] Anchoring transaction to Mantle Sepolia...")
105+
mantleClient, err := mantle.NewRegistryClient(
106+
"https://rpc.sepolia.mantle.xyz",
107+
common.HexToAddress("0x33aE8331a2406EEc3A33483001aC5650DA2e0662"),
108+
big.NewInt(5003),
109+
)
110+
if err != nil {
111+
log.Fatalf("❌ Failed to connect to Mantle: %v", err)
112+
}
113+
114+
var agentBytes [32]byte
115+
copy(agentBytes[:], agentID.Bytes())
116+
117+
txHash, err := mantleClient.LogPayment(
118+
context.Background(),
119+
privKey,
120+
agentBytes,
121+
big.NewInt(1337), // Demo Invoice ID
122+
amount,
123+
"Demo agent payment anchored via SettlerEngine",
124+
)
125+
if err != nil {
126+
log.Fatalf("❌ On-chain anchoring failed: %v", err)
127+
}
128+
129+
fmt.Printf("🚀 SUCCESS! On-chain footprint created.\n")
130+
fmt.Printf("🔗 Transaction Hash: %s\n", txHash)
131+
fmt.Printf("🌍 Explorer: https://explorer.sepolia.mantle.xyz/tx/%s\n", txHash)
132+
}
133+
64134
func runPay(args []string) {
65135
fs := flag.NewFlagSet("pay", flag.ExitOnError)
66136
fs.String("rpc", "https://sepolia.base.org", "Ethereum RPC URL")
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package mantle
2+
3+
import (
4+
"context"
5+
"crypto/ecdsa"
6+
"fmt"
7+
"math/big"
8+
9+
"github.com/ethereum/go-ethereum/accounts/abi"
10+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
11+
"github.com/ethereum/go-ethereum/common"
12+
"github.com/ethereum/go-ethereum/crypto"
13+
"github.com/ethereum/go-ethereum/ethclient"
14+
"strings"
15+
)
16+
17+
// SettlerRegistryABI is the ABI for the logAgentPayment method.
18+
const SettlerRegistryABI = `[{"inputs":[{"internalType":"bytes32","name":"_agentId","type":"bytes32"},{"internalType":"uint256","name":"_invoiceId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"_metadata","type":"string"}],"name":"logAgentPayment","outputs":[],"stateMutability":"external","type":"function"}]`
19+
20+
type RegistryClient struct {
21+
client *ethclient.Client
22+
contract common.Address
23+
chainID *big.Int
24+
}
25+
26+
func NewRegistryClient(rpcURL string, contractAddr common.Address, chainID *big.Int) (*RegistryClient, error) {
27+
client, err := ethclient.Dial(rpcURL)
28+
if err != nil {
29+
return nil, err
30+
}
31+
return &RegistryClient{
32+
client: client,
33+
contract: contractAddr,
34+
chainID: chainID,
35+
}, nil
36+
}
37+
38+
func (c *RegistryClient) LogPayment(ctx context.Context, hexKey string, agentID [32]byte, invoiceID *big.Int, amount *big.Int, metadata string) (string, error) {
39+
privateKey, err := crypto.HexToECDSA(hexKey)
40+
if err != nil {
41+
return "", err
42+
}
43+
44+
publicKey := privateKey.Public()
45+
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
46+
if !ok {
47+
return "", fmt.Errorf("error casting public key to ECDSA")
48+
}
49+
50+
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
51+
nonce, err := c.client.PendingNonceAt(ctx, fromAddress)
52+
if err != nil {
53+
return "", err
54+
}
55+
56+
gasPrice, err := c.client.SuggestGasPrice(ctx)
57+
if err != nil {
58+
return "", err
59+
}
60+
61+
auth, err := bind.NewKeyedTransactorWithChainID(privateKey, c.chainID)
62+
if err != nil {
63+
return "", err
64+
}
65+
auth.Nonce = big.NewInt(int64(nonce))
66+
auth.Value = big.NewInt(0)
67+
auth.GasLimit = uint64(300000)
68+
auth.GasPrice = gasPrice
69+
70+
parsedABI, err := abi.JSON(strings.NewReader(SettlerRegistryABI))
71+
if err != nil {
72+
return "", err
73+
}
74+
75+
contract := bind.NewBoundContract(c.contract, parsedABI, c.client, c.client, c.client)
76+
tx, err := contract.Transact(auth, "logAgentPayment", agentID, invoiceID, amount, metadata)
77+
if err != nil {
78+
return "", err
79+
}
80+
81+
return tx.Hash().Hex(), nil
82+
}

0 commit comments

Comments
 (0)