Skip to content

Commit baacc40

Browse files
committed
fix: restructure to match monorepo layout with Apache 2.0 headers and tests
1 parent 795b67a commit baacc40

9 files changed

Lines changed: 274 additions & 47 deletions

File tree

File renamed without changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Sardis payment tools for Google ADK - policy-controlled AI agent payments."""
16+
17+
from .sardis_tools import sardis_check_balance
18+
from .sardis_tools import sardis_check_policy
19+
from .sardis_tools import sardis_pay
20+
21+
__all__ = [
22+
"sardis_pay",
23+
"sardis_check_balance",
24+
"sardis_check_policy",
25+
]
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Sardis payment tools for Google Agent Development Kit.
16+
17+
These tools enable ADK agents to make policy-controlled payments through
18+
Sardis non-custodial MPC wallets.
19+
20+
Installation:
21+
pip install google-adk-community sardis-adk
22+
23+
Usage:
24+
from google.adk.agents import Agent
25+
from google.adk_community.tools.sardis import sardis_pay, sardis_check_balance
26+
27+
agent = Agent(
28+
model="gemini-2.0-flash",
29+
name="payment_agent",
30+
tools=[sardis_pay, sardis_check_balance],
31+
)
32+
"""
33+
34+
from __future__ import annotations
35+
36+
import logging
37+
import os
38+
from typing import Optional
39+
40+
logger = logging.getLogger("google_adk." + __name__)
41+
42+
43+
def sardis_pay(
44+
recipient: str,
45+
amount: str,
46+
token: str = "USDC",
47+
chain: str = "base",
48+
memo: Optional[str] = None,
49+
) -> dict:
50+
"""Execute a policy-controlled payment via Sardis.
51+
52+
Args:
53+
recipient: Destination wallet address or Sardis wallet ID.
54+
amount: Amount to send as a decimal string (e.g. "10.00").
55+
token: Token symbol (USDC, EURC, USDT, PYUSD). Default: USDC.
56+
chain: Chain to execute on (base, polygon, ethereum, arbitrum,
57+
optimism). Default: base.
58+
memo: Optional human-readable memo for the payment.
59+
60+
Returns:
61+
A dict with keys: status, transaction_id, tx_hash, amount, token, chain.
62+
"""
63+
try:
64+
from sardis import SardisClient
65+
except ImportError:
66+
return {
67+
"status": "error",
68+
"error": "sardis package required. Install with: pip install sardis",
69+
}
70+
71+
api_key = os.environ.get("SARDIS_API_KEY")
72+
wallet_id = os.environ.get("SARDIS_WALLET_ID")
73+
if not api_key:
74+
return {
75+
"status": "error",
76+
"error": "SARDIS_API_KEY environment variable not set.",
77+
}
78+
if not wallet_id:
79+
return {
80+
"status": "error",
81+
"error": "SARDIS_WALLET_ID environment variable not set.",
82+
}
83+
84+
client = SardisClient(api_key=api_key)
85+
result = client.payments.send(
86+
wallet_id, to=recipient, amount=float(amount), token=token,
87+
purpose=memo or "Payment",
88+
)
89+
return {
90+
"status": "APPROVED" if result.success else "BLOCKED",
91+
"transaction_id": getattr(result, "tx_id", ""),
92+
"message": getattr(result, "message", ""),
93+
"amount": amount,
94+
"token": token,
95+
"chain": chain,
96+
}
97+
98+
99+
def sardis_check_balance(
100+
token: str = "USDC",
101+
) -> dict:
102+
"""Check the balance of a Sardis wallet.
103+
104+
Args:
105+
token: Token symbol to check (e.g. "USDC"). Default: USDC.
106+
107+
Returns:
108+
A dict with keys: balance, remaining, token.
109+
"""
110+
try:
111+
from sardis import SardisClient
112+
except ImportError:
113+
return {"status": "error", "error": "sardis package required."}
114+
115+
api_key = os.environ.get("SARDIS_API_KEY")
116+
wallet_id = os.environ.get("SARDIS_WALLET_ID")
117+
if not api_key or not wallet_id:
118+
return {"status": "error", "error": "SARDIS_API_KEY and SARDIS_WALLET_ID required."}
119+
120+
client = SardisClient(api_key=api_key)
121+
balance = client.wallets.get_balance(wallet_id, token=token)
122+
return {
123+
"balance": str(balance.balance),
124+
"remaining": str(balance.remaining),
125+
"token": token,
126+
}
127+
128+
129+
def sardis_check_policy(
130+
amount: str,
131+
merchant: str,
132+
) -> dict:
133+
"""Check if a payment would be allowed by spending policy.
134+
135+
Args:
136+
amount: Amount to check as a decimal string (e.g. "250.00").
137+
merchant: Merchant or recipient to check against policy rules.
138+
139+
Returns:
140+
A dict with keys: allowed (bool), reason (str).
141+
"""
142+
try:
143+
from sardis import SardisClient
144+
except ImportError:
145+
return {"status": "error", "error": "sardis package required."}
146+
147+
api_key = os.environ.get("SARDIS_API_KEY")
148+
wallet_id = os.environ.get("SARDIS_WALLET_ID")
149+
if not api_key or not wallet_id:
150+
return {"status": "error", "error": "SARDIS_API_KEY and SARDIS_WALLET_ID required."}
151+
152+
client = SardisClient(api_key=api_key)
153+
balance = client.wallets.get_balance(wallet_id)
154+
amt = float(amount)
155+
if amt > balance.remaining:
156+
return {
157+
"allowed": False,
158+
"reason": f"Amount ${amt} exceeds remaining limit ${balance.remaining}",
159+
}
160+
if amt > balance.balance:
161+
return {
162+
"allowed": False,
163+
"reason": f"Amount ${amt} exceeds balance ${balance.balance}",
164+
}
165+
return {
166+
"allowed": True,
167+
"reason": f"Payment of ${amt} to {merchant} would be allowed",
168+
}

tests/unittests/tools/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Tests for Sardis payment tools."""
16+
17+
from unittest.mock import MagicMock, patch
18+
19+
from google.adk_community.tools.sardis.sardis_tools import (
20+
sardis_check_balance,
21+
sardis_check_policy,
22+
sardis_pay,
23+
)
24+
25+
26+
def test_sardis_pay_missing_api_key(monkeypatch):
27+
monkeypatch.delenv("SARDIS_API_KEY", raising=False)
28+
monkeypatch.delenv("SARDIS_WALLET_ID", raising=False)
29+
result = sardis_pay(recipient="0xABC", amount="10.00")
30+
assert result["status"] == "error"
31+
32+
33+
def test_sardis_check_balance_missing_key(monkeypatch):
34+
monkeypatch.delenv("SARDIS_API_KEY", raising=False)
35+
result = sardis_check_balance()
36+
assert result["status"] == "error"
37+
38+
39+
def test_sardis_check_policy_missing_key(monkeypatch):
40+
monkeypatch.delenv("SARDIS_API_KEY", raising=False)
41+
result = sardis_check_policy(amount="100.00", merchant="openai")
42+
assert result["status"] == "error"

tools/sardis/__init__.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

tools/sardis/sardis_tool.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)