skillware 0.3.2__tar.gz → 0.3.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {skillware-0.3.2/skillware.egg-info → skillware-0.3.5}/PKG-INFO +22 -24
- {skillware-0.3.2 → skillware-0.3.5}/README.md +20 -23
- {skillware-0.3.2 → skillware-0.3.5}/pyproject.toml +6 -1
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/pii_masker/skill.py +16 -15
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/tos_evaluator/skill.py +34 -13
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/synthetic_generator/skill.py +17 -30
- skillware-0.3.5/skills/defi/evm_tx_handler/abis.py +136 -0
- skillware-0.3.5/skills/defi/evm_tx_handler/card.json +20 -0
- skillware-0.3.5/skills/defi/evm_tx_handler/config.yaml.example +11 -0
- skillware-0.3.5/skills/defi/evm_tx_handler/data/addressbook.yaml +4 -0
- skillware-0.3.5/skills/defi/evm_tx_handler/data/chains.yaml +18 -0
- skillware-0.3.5/skills/defi/evm_tx_handler/data/tokens.yaml +25 -0
- skillware-0.3.5/skills/defi/evm_tx_handler/instructions.md +81 -0
- skillware-0.3.5/skills/defi/evm_tx_handler/manifest.yaml +63 -0
- skillware-0.3.5/skills/defi/evm_tx_handler/skill.py +1114 -0
- skillware-0.3.5/skills/defi/evm_tx_handler/test_skill.py +542 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/dev_tools/issue_resolver/card.json +1 -1
- skillware-0.3.5/skills/dev_tools/issue_resolver/instructions.md +80 -0
- skillware-0.3.5/skills/dev_tools/issue_resolver/manifest.yaml +63 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/dev_tools/issue_resolver/skill.py +96 -27
- {skillware-0.3.2 → skillware-0.3.5}/skills/dev_tools/issue_resolver/test_skill.py +62 -1
- skillware-0.3.5/skills/dev_tools/issue_resolver/workflow.py +302 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/skill.py +74 -15
- {skillware-0.3.2 → skillware-0.3.5}/skills/optimization/prompt_rewriter/skill.py +26 -9
- skillware-0.3.5/skillware/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skillware/cli.py +3 -0
- skillware-0.3.5/skillware/core/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skillware/core/loader.py +5 -1
- skillware-0.3.5/skillware/version_policy.py +63 -0
- {skillware-0.3.2 → skillware-0.3.5/skillware.egg-info}/PKG-INFO +22 -24
- {skillware-0.3.2 → skillware-0.3.5}/skillware.egg-info/SOURCES.txt +16 -1
- {skillware-0.3.2 → skillware-0.3.5}/skillware.egg-info/requires.txt +1 -0
- {skillware-0.3.2 → skillware-0.3.5}/tests/test_loader.py +27 -18
- {skillware-0.3.2 → skillware-0.3.5}/tests/test_skill_issuer.py +18 -14
- skillware-0.3.5/tests/test_version_policy.py +96 -0
- skillware-0.3.2/skills/dev_tools/issue_resolver/instructions.md +0 -104
- skillware-0.3.2/skills/dev_tools/issue_resolver/manifest.yaml +0 -56
- {skillware-0.3.2 → skillware-0.3.5}/LICENSE +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/MANIFEST.in +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/setup.cfg +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/mica_module/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/mica_module/card.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/mica_module/instructions.md +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/mica_module/manifest.yaml +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/mica_module/mica_corpus.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/mica_module/skill.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/pii_masker/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/pii_masker/card.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/pii_masker/instructions.md +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/pii_masker/manifest.yaml +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/tos_evaluator/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/tos_evaluator/card.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/tos_evaluator/instructions.md +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/tos_evaluator/manifest.yaml +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/compliance/tos_evaluator/test_skill.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/novelty_extractor/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/novelty_extractor/card.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/novelty_extractor/instructions.md +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/novelty_extractor/manifest.yaml +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/novelty_extractor/skill.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/novelty_extractor/test_skill.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/synthetic_generator/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/synthetic_generator/card.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/synthetic_generator/instructions.md +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/data_engineering/synthetic_generator/manifest.yaml +0 -0
- {skillware-0.3.2/skills/finance → skillware-0.3.5/skills/defi}/__init__.py +0 -0
- {skillware-0.3.2/skills/office → skillware-0.3.5/skills/defi/evm_tx_handler}/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/dev_tools/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/dev_tools/issue_resolver/__init__.py +0 -0
- {skillware-0.3.2/skills/office/pdf_form_filler → skillware-0.3.5/skills/finance}/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/card.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/data/entities.ftm.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/data/malicious_scs_2025.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/data/normalized_fbi_lazarus_20250722_180019.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/data/normalized_israel_nbctf_20250722_180019.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/data/normalized_uniswap_trm.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/instructions.md +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/maintenance/normalization_tool.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/maintenance/normalize_uniswap_trm.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/finance/wallet_screening/manifest.yaml +0 -0
- {skillware-0.3.2/skills/optimization → skillware-0.3.5/skills/office}/__init__.py +0 -0
- {skillware-0.3.2/skillware → skillware-0.3.5/skills/office/pdf_form_filler}/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/office/pdf_form_filler/card.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/office/pdf_form_filler/instructions.md +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/office/pdf_form_filler/manifest.yaml +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/office/pdf_form_filler/skill.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/office/pdf_form_filler/utils.py +0 -0
- {skillware-0.3.2/skillware/core → skillware-0.3.5/skills/optimization}/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/optimization/prompt_rewriter/__init__.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/optimization/prompt_rewriter/card.json +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/optimization/prompt_rewriter/instructions.md +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skills/optimization/prompt_rewriter/manifest.yaml +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skillware/core/base_skill.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skillware/core/env.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skillware.egg-info/dependency_links.txt +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skillware.egg-info/entry_points.txt +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/skillware.egg-info/top_level.txt +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/tests/test_cli.py +0 -0
- {skillware-0.3.2 → skillware-0.3.5}/tests/test_mica_module.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: skillware
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
4
4
|
Summary: A framework for modular, self-contained AI skills.
|
|
5
5
|
Author-email: ARPA Hellenic Logical Systems <skillware-os@arpacorp.net>
|
|
6
6
|
License: MIT License
|
|
@@ -37,6 +37,7 @@ Requires-Dist: requests
|
|
|
37
37
|
Requires-Dist: pyyaml
|
|
38
38
|
Requires-Dist: python-dotenv
|
|
39
39
|
Requires-Dist: beautifulsoup4
|
|
40
|
+
Requires-Dist: packaging
|
|
40
41
|
Provides-Extra: dev
|
|
41
42
|
Requires-Dist: pytest; extra == "dev"
|
|
42
43
|
Requires-Dist: pytest-mock; extra == "dev"
|
|
@@ -81,9 +82,9 @@ Dynamic: license-file
|
|
|
81
82
|
<a href="#architecture">Architecture</a> •
|
|
82
83
|
<a href="#quick-start">Quick Start</a> •
|
|
83
84
|
<a href="#documentation">Documentation</a> •
|
|
84
|
-
<a href="CHANGELOG.md">Changelog</a> •
|
|
85
85
|
<a href="#contributing">Contributing</a> •
|
|
86
86
|
<a href="#comparison">Comparison</a> •
|
|
87
|
+
<a href="CHANGELOG.md">Changelog</a> •
|
|
87
88
|
<a href="#contact">Contact</a>
|
|
88
89
|
</div>
|
|
89
90
|
|
|
@@ -95,18 +96,18 @@ Dynamic: license-file
|
|
|
95
96
|
|
|
96
97
|
## Mission
|
|
97
98
|
|
|
98
|
-
The AI ecosystem is fragmented. Developers often re-invent tool definitions, system prompts, and safety rules for every project. **Skillware** supplies a standard to package capabilities into self-contained units that work across **Gemini**, **Claude**, **Ollama**, **GPT**, and **Llama**.
|
|
99
|
+
The AI ecosystem is fragmented. Developers often re-invent tool definitions, system prompts, and safety rules for every project. **Skillware** supplies a standard to package capabilities into self-contained, installable units that work across **Gemini**, **Claude**, **Ollama**, **GPT**, and **Llama**. For the full story and roadmap, see our **[Vision](docs/vision.md)**.
|
|
99
100
|
|
|
100
101
|
A **Skill** in this framework provides everything an Agent needs to master a domain:
|
|
101
102
|
|
|
102
|
-
1.
|
|
103
|
-
2.
|
|
104
|
-
3.
|
|
105
|
-
4.
|
|
103
|
+
1. **Logic**: Executable Python so agents run real work, not guess it.
|
|
104
|
+
2. **Cognition**: System instructions and cognitive maps so any logical system uses the capability as intended.
|
|
105
|
+
3. **Governance**: Constitution, safety boundaries, and hard limits baked into the bundle.
|
|
106
|
+
4. **Interface**: Standardized tool schemas for any LLM or agent runtime.
|
|
106
107
|
|
|
107
108
|
### Skill library
|
|
108
109
|
|
|
109
|
-
Browse capabilities by category in the [Skill library](docs/skills/README.md).
|
|
110
|
+
Browse capabilities by category in the [Skill library](docs/skills/README.md) or on our <a href="https://skillware.site/skills" target="_blank" rel="noopener noreferrer">site ↗</a>.
|
|
110
111
|
|
|
111
112
|
## Architecture
|
|
112
113
|
|
|
@@ -238,30 +239,23 @@ For other providers and shared integration patterns, see the [usage guides index
|
|
|
238
239
|
|
|
239
240
|
## Documentation
|
|
240
241
|
|
|
241
|
-
| Topic |
|
|
242
|
+
| Topic | Links |
|
|
242
243
|
| :--- | :--- |
|
|
243
|
-
| Introduction | [docs/introduction.md](docs/
|
|
244
|
-
|
|
|
245
|
-
|
|
|
246
|
-
| Skill library | [docs/skills/README.md](docs/skills/README.md) |
|
|
247
|
-
| Usage guides | [index](docs/usage/README.md) — [Gemini](docs/usage/gemini.md) · [Claude](docs/usage/claude.md) · [OpenAI](docs/usage/openai.md) · [DeepSeek](docs/usage/deepseek.md) · [Ollama](docs/usage/ollama.md); [agent loops](docs/usage/agent_loops.md); [API keys](docs/usage/api_keys.md) |
|
|
248
|
-
| Examples index | [examples/README.md](examples/README.md) |
|
|
249
|
-
| CLI | [docs/usage/cli.md](docs/usage/cli.md) |
|
|
250
|
-
| Contributing | [CONTRIBUTING.md](CONTRIBUTING.md) · [agent workflow](docs/contributing/ai_native_workflow.md) |
|
|
244
|
+
| **Introduction** | [Introduction](docs/introduction.md) · [Vision](docs/vision.md) · [Comparison](COMPARISON.md) |
|
|
245
|
+
| **Usage guides** | [Skill Library](docs/skills/README.md) · [Usage Guide](docs/usage/README.md) · [Examples](examples/README.md) · [Agent Loops](docs/usage/agent_loops.md) · [API Keys](docs/usage/api_keys.md) · [CLI](docs/usage/cli.md) |
|
|
246
|
+
| **Contributing** | [Contributing](CONTRIBUTING.md) · [Agent Native Workflow](docs/contributing/ai_native_workflow.md) · [Testing](docs/TESTING.md) · [Changelog](CHANGELOG.md) |
|
|
251
247
|
|
|
252
248
|
## Contributing
|
|
253
249
|
|
|
254
|
-
We are building the "App Store" for Agents
|
|
250
|
+
We are building the "App Store" for Agents. Skills are the main contribution, but documentation, tests, and framework fixes are welcome too. Human operators and supervised agents follow the same standards: scoped PRs, deterministic behavior, and verified tests.
|
|
255
251
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
* **[TESTING.md](docs/TESTING.md)** — Local linting and pytest before you open a PR.
|
|
260
|
-
* **[Pull request template](.github/PULL_REQUEST_TEMPLATE.md)** — Checklists for skills, docs, and framework changes (complete only the sections that apply).
|
|
252
|
+
See the **Contributing** row in [Documentation](#documentation) for the full path, [Contributing](CONTRIBUTING.md) (types, skill standard, PR process), [Agent Native Workflow](docs/contributing/ai_native_workflow.md) (for autonomous and semi-autonomous agents), [Testing](docs/TESTING.md) (Black, Flake8, framework and skill pytest, pre-PR checklist), and [Changelog](CHANGELOG.md) (user-facing entries under `[Unreleased]`).
|
|
253
|
+
|
|
254
|
+
Also read the [Agent Code of Conduct](CODE_OF_CONDUCT.md). Open PRs with the [pull request template](.github/PULL_REQUEST_TEMPLATE.md) and complete only the sections that apply.
|
|
261
255
|
|
|
262
256
|
## Comparison
|
|
263
257
|
|
|
264
|
-
Skillware differs from the Model Context Protocol (MCP)
|
|
258
|
+
Skillware differs from the Model Context Protocol (MCP), and Agent Skills (SKILL.md) in several ways:
|
|
265
259
|
|
|
266
260
|
* **Model Agnostic**: Native adapters for Gemini, Claude, Ollama, and OpenAI.
|
|
267
261
|
* **Code-First**: Skills are executable Python packages, not just server specs.
|
|
@@ -274,8 +268,12 @@ Skillware differs from the Model Context Protocol (MCP) or Anthropic's Skills re
|
|
|
274
268
|
For questions, suggestions, or contributions, please open an issue or reach out to us:
|
|
275
269
|
|
|
276
270
|
* **Email**: [skillware-os@arpacorp.net](mailto:skillware-os@arpacorp.net)
|
|
271
|
+
* **Enterprise**: [skills@arpacorp.net](mailto:skills@arpacorp.net) — enterprise skills, chaining, and forward deployed engineering
|
|
272
|
+
* **Security**: [security@arpacorp.net](mailto:security@arpacorp.net) — report bugs, vulnerabilities, or other sensitive issues (see [SECURITY.md](SECURITY.md))
|
|
277
273
|
* **Issues**: [GitHub Issues](https://github.com/arpahls/skillware/issues)
|
|
278
274
|
|
|
275
|
+
For skill-specific questions or reaching a skill's maintainer, check issuer and author details on the skill card, in the repo [Skill Library](docs/skills/README.md), or on our website's <a href="https://skillware.site/skills" target="_blank" rel="noopener noreferrer">skills catalog ↗</a>.
|
|
276
|
+
|
|
279
277
|
---
|
|
280
278
|
|
|
281
279
|
<div align="center">
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
<a href="#architecture">Architecture</a> •
|
|
20
20
|
<a href="#quick-start">Quick Start</a> •
|
|
21
21
|
<a href="#documentation">Documentation</a> •
|
|
22
|
-
<a href="CHANGELOG.md">Changelog</a> •
|
|
23
22
|
<a href="#contributing">Contributing</a> •
|
|
24
23
|
<a href="#comparison">Comparison</a> •
|
|
24
|
+
<a href="CHANGELOG.md">Changelog</a> •
|
|
25
25
|
<a href="#contact">Contact</a>
|
|
26
26
|
</div>
|
|
27
27
|
|
|
@@ -33,18 +33,18 @@
|
|
|
33
33
|
|
|
34
34
|
## Mission
|
|
35
35
|
|
|
36
|
-
The AI ecosystem is fragmented. Developers often re-invent tool definitions, system prompts, and safety rules for every project. **Skillware** supplies a standard to package capabilities into self-contained units that work across **Gemini**, **Claude**, **Ollama**, **GPT**, and **Llama**.
|
|
36
|
+
The AI ecosystem is fragmented. Developers often re-invent tool definitions, system prompts, and safety rules for every project. **Skillware** supplies a standard to package capabilities into self-contained, installable units that work across **Gemini**, **Claude**, **Ollama**, **GPT**, and **Llama**. For the full story and roadmap, see our **[Vision](docs/vision.md)**.
|
|
37
37
|
|
|
38
38
|
A **Skill** in this framework provides everything an Agent needs to master a domain:
|
|
39
39
|
|
|
40
|
-
1.
|
|
41
|
-
2.
|
|
42
|
-
3.
|
|
43
|
-
4.
|
|
40
|
+
1. **Logic**: Executable Python so agents run real work, not guess it.
|
|
41
|
+
2. **Cognition**: System instructions and cognitive maps so any logical system uses the capability as intended.
|
|
42
|
+
3. **Governance**: Constitution, safety boundaries, and hard limits baked into the bundle.
|
|
43
|
+
4. **Interface**: Standardized tool schemas for any LLM or agent runtime.
|
|
44
44
|
|
|
45
45
|
### Skill library
|
|
46
46
|
|
|
47
|
-
Browse capabilities by category in the [Skill library](docs/skills/README.md).
|
|
47
|
+
Browse capabilities by category in the [Skill library](docs/skills/README.md) or on our <a href="https://skillware.site/skills" target="_blank" rel="noopener noreferrer">site ↗</a>.
|
|
48
48
|
|
|
49
49
|
## Architecture
|
|
50
50
|
|
|
@@ -176,30 +176,23 @@ For other providers and shared integration patterns, see the [usage guides index
|
|
|
176
176
|
|
|
177
177
|
## Documentation
|
|
178
178
|
|
|
179
|
-
| Topic |
|
|
179
|
+
| Topic | Links |
|
|
180
180
|
| :--- | :--- |
|
|
181
|
-
| Introduction | [docs/introduction.md](docs/
|
|
182
|
-
|
|
|
183
|
-
|
|
|
184
|
-
| Skill library | [docs/skills/README.md](docs/skills/README.md) |
|
|
185
|
-
| Usage guides | [index](docs/usage/README.md) — [Gemini](docs/usage/gemini.md) · [Claude](docs/usage/claude.md) · [OpenAI](docs/usage/openai.md) · [DeepSeek](docs/usage/deepseek.md) · [Ollama](docs/usage/ollama.md); [agent loops](docs/usage/agent_loops.md); [API keys](docs/usage/api_keys.md) |
|
|
186
|
-
| Examples index | [examples/README.md](examples/README.md) |
|
|
187
|
-
| CLI | [docs/usage/cli.md](docs/usage/cli.md) |
|
|
188
|
-
| Contributing | [CONTRIBUTING.md](CONTRIBUTING.md) · [agent workflow](docs/contributing/ai_native_workflow.md) |
|
|
181
|
+
| **Introduction** | [Introduction](docs/introduction.md) · [Vision](docs/vision.md) · [Comparison](COMPARISON.md) |
|
|
182
|
+
| **Usage guides** | [Skill Library](docs/skills/README.md) · [Usage Guide](docs/usage/README.md) · [Examples](examples/README.md) · [Agent Loops](docs/usage/agent_loops.md) · [API Keys](docs/usage/api_keys.md) · [CLI](docs/usage/cli.md) |
|
|
183
|
+
| **Contributing** | [Contributing](CONTRIBUTING.md) · [Agent Native Workflow](docs/contributing/ai_native_workflow.md) · [Testing](docs/TESTING.md) · [Changelog](CHANGELOG.md) |
|
|
189
184
|
|
|
190
185
|
## Contributing
|
|
191
186
|
|
|
192
|
-
We are building the "App Store" for Agents
|
|
187
|
+
We are building the "App Store" for Agents. Skills are the main contribution, but documentation, tests, and framework fixes are welcome too. Human operators and supervised agents follow the same standards: scoped PRs, deterministic behavior, and verified tests.
|
|
193
188
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
* **[TESTING.md](docs/TESTING.md)** — Local linting and pytest before you open a PR.
|
|
198
|
-
* **[Pull request template](.github/PULL_REQUEST_TEMPLATE.md)** — Checklists for skills, docs, and framework changes (complete only the sections that apply).
|
|
189
|
+
See the **Contributing** row in [Documentation](#documentation) for the full path, [Contributing](CONTRIBUTING.md) (types, skill standard, PR process), [Agent Native Workflow](docs/contributing/ai_native_workflow.md) (for autonomous and semi-autonomous agents), [Testing](docs/TESTING.md) (Black, Flake8, framework and skill pytest, pre-PR checklist), and [Changelog](CHANGELOG.md) (user-facing entries under `[Unreleased]`).
|
|
190
|
+
|
|
191
|
+
Also read the [Agent Code of Conduct](CODE_OF_CONDUCT.md). Open PRs with the [pull request template](.github/PULL_REQUEST_TEMPLATE.md) and complete only the sections that apply.
|
|
199
192
|
|
|
200
193
|
## Comparison
|
|
201
194
|
|
|
202
|
-
Skillware differs from the Model Context Protocol (MCP)
|
|
195
|
+
Skillware differs from the Model Context Protocol (MCP), and Agent Skills (SKILL.md) in several ways:
|
|
203
196
|
|
|
204
197
|
* **Model Agnostic**: Native adapters for Gemini, Claude, Ollama, and OpenAI.
|
|
205
198
|
* **Code-First**: Skills are executable Python packages, not just server specs.
|
|
@@ -212,8 +205,12 @@ Skillware differs from the Model Context Protocol (MCP) or Anthropic's Skills re
|
|
|
212
205
|
For questions, suggestions, or contributions, please open an issue or reach out to us:
|
|
213
206
|
|
|
214
207
|
* **Email**: [skillware-os@arpacorp.net](mailto:skillware-os@arpacorp.net)
|
|
208
|
+
* **Enterprise**: [skills@arpacorp.net](mailto:skills@arpacorp.net) — enterprise skills, chaining, and forward deployed engineering
|
|
209
|
+
* **Security**: [security@arpacorp.net](mailto:security@arpacorp.net) — report bugs, vulnerabilities, or other sensitive issues (see [SECURITY.md](SECURITY.md))
|
|
215
210
|
* **Issues**: [GitHub Issues](https://github.com/arpahls/skillware/issues)
|
|
216
211
|
|
|
212
|
+
For skill-specific questions or reaching a skill's maintainer, check issuer and author details on the skill card, in the repo [Skill Library](docs/skills/README.md), or on our website's <a href="https://skillware.site/skills" target="_blank" rel="noopener noreferrer">skills catalog ↗</a>.
|
|
213
|
+
|
|
217
214
|
---
|
|
218
215
|
|
|
219
216
|
<div align="center">
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "skillware"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.5"
|
|
8
8
|
description = "A framework for modular, self-contained AI skills."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -22,6 +22,7 @@ dependencies = [
|
|
|
22
22
|
"pyyaml",
|
|
23
23
|
"python-dotenv",
|
|
24
24
|
"beautifulsoup4",
|
|
25
|
+
"packaging",
|
|
25
26
|
]
|
|
26
27
|
requires-python = ">=3.10"
|
|
27
28
|
|
|
@@ -68,3 +69,7 @@ include = ["skillware*", "skills*"]
|
|
|
68
69
|
# and this wildcard. No per-skill entries needed when adding registry skills.
|
|
69
70
|
[tool.setuptools.package-data]
|
|
70
71
|
skills = ["**/*"]
|
|
72
|
+
|
|
73
|
+
[tool.black]
|
|
74
|
+
line-length = 88
|
|
75
|
+
target-version = ["py310"]
|
|
@@ -11,10 +11,7 @@ class PIIMaskerSkill(BaseSkill):
|
|
|
11
11
|
|
|
12
12
|
@property
|
|
13
13
|
def manifest(self) -> Dict[str, Any]:
|
|
14
|
-
return {
|
|
15
|
-
"name": "compliance/pii_masker",
|
|
16
|
-
"version": "0.1.0"
|
|
17
|
-
}
|
|
14
|
+
return {"name": "compliance/pii_masker", "version": "0.1.0"}
|
|
18
15
|
|
|
19
16
|
def execute(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
20
17
|
text = params.get("text", "")
|
|
@@ -25,7 +22,7 @@ class PIIMaskerSkill(BaseSkill):
|
|
|
25
22
|
sanitized_text = self._apply_mode(sanitized_text, mode)
|
|
26
23
|
|
|
27
24
|
# Build unique entity types list
|
|
28
|
-
entities = list(set([re.sub(r
|
|
25
|
+
entities = list(set([re.sub(r"_[0-9]+$", "", e) for e in detected_entities]))
|
|
29
26
|
|
|
30
27
|
return {
|
|
31
28
|
"sanitized_text": sanitized_text,
|
|
@@ -33,17 +30,21 @@ class PIIMaskerSkill(BaseSkill):
|
|
|
33
30
|
"detected_entities": entities,
|
|
34
31
|
"entity_count": len(detected_entities),
|
|
35
32
|
"security_level": "local-only",
|
|
36
|
-
"model": "arpacorp/micro-f1-mask"
|
|
37
|
-
}
|
|
33
|
+
"model": "arpacorp/micro-f1-mask",
|
|
34
|
+
},
|
|
38
35
|
}
|
|
39
36
|
|
|
40
37
|
def _call_ollama(self, text: str, endpoint: str) -> Tuple[str, List[str]]:
|
|
41
38
|
try:
|
|
42
|
-
response = requests.post(
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
response = requests.post(
|
|
40
|
+
f"{endpoint}/api/generate",
|
|
41
|
+
json={
|
|
42
|
+
"model": "arpacorp/micro-f1-mask",
|
|
43
|
+
"prompt": text,
|
|
44
|
+
"stream": False,
|
|
45
|
+
},
|
|
46
|
+
timeout=30,
|
|
47
|
+
)
|
|
47
48
|
if response.status_code == 200:
|
|
48
49
|
result_text = response.json().get("response", text)
|
|
49
50
|
else:
|
|
@@ -56,7 +57,7 @@ class PIIMaskerSkill(BaseSkill):
|
|
|
56
57
|
result_text = text
|
|
57
58
|
|
|
58
59
|
# Detect entities in the response
|
|
59
|
-
detected = re.findall(r
|
|
60
|
+
detected = re.findall(r"\[([A-Z_]+(?:_[0-9]+)?)\]", result_text)
|
|
60
61
|
return result_text, detected
|
|
61
62
|
|
|
62
63
|
def _apply_mode(self, text: str, mode: str) -> str:
|
|
@@ -64,14 +65,14 @@ class PIIMaskerSkill(BaseSkill):
|
|
|
64
65
|
return text
|
|
65
66
|
|
|
66
67
|
# Pattern to catch [DOCUMENT], [PERSON_1], etc.
|
|
67
|
-
pattern = r
|
|
68
|
+
pattern = r"\[[A-Z_]+(?:_[0-9]+)?\]"
|
|
68
69
|
if mode == "redact":
|
|
69
70
|
return re.sub(pattern, "XXXX", text)
|
|
70
71
|
elif mode == "remove":
|
|
71
72
|
# Replace token and any immediate preceding/following spaces safely
|
|
72
73
|
# A simple sub is sufficient. Cleaning up double spaces.
|
|
73
74
|
text = re.sub(pattern, "", text)
|
|
74
|
-
text = re.sub(r
|
|
75
|
+
text = re.sub(r"\s+", " ", text).strip()
|
|
75
76
|
return text
|
|
76
77
|
|
|
77
78
|
return text
|
|
@@ -213,7 +213,9 @@ class TOSEvaluatorSkill(BaseSkill):
|
|
|
213
213
|
try:
|
|
214
214
|
response = self.session.get(robots_url, timeout=10)
|
|
215
215
|
if response.status_code >= 400:
|
|
216
|
-
assessment["reason"] =
|
|
216
|
+
assessment["reason"] = (
|
|
217
|
+
f"robots.txt returned HTTP {response.status_code}."
|
|
218
|
+
)
|
|
217
219
|
return assessment
|
|
218
220
|
|
|
219
221
|
parser = RobotFileParser()
|
|
@@ -266,13 +268,20 @@ class TOSEvaluatorSkill(BaseSkill):
|
|
|
266
268
|
else:
|
|
267
269
|
candidates[item["url"]] = item
|
|
268
270
|
|
|
269
|
-
ordered = sorted(
|
|
271
|
+
ordered = sorted(
|
|
272
|
+
candidates.values(), key=lambda item: item["score"], reverse=True
|
|
273
|
+
)
|
|
270
274
|
return {"candidates": ordered[:max_terms_pages]}
|
|
271
275
|
|
|
272
|
-
def _extract_candidate_links(
|
|
276
|
+
def _extract_candidate_links(
|
|
277
|
+
self, page_url: str, origin: str
|
|
278
|
+
) -> List[Dict[str, Any]]:
|
|
273
279
|
links: List[Dict[str, Any]] = []
|
|
274
280
|
response = self._safe_get(page_url, timeout=10)
|
|
275
|
-
if
|
|
281
|
+
if (
|
|
282
|
+
not response
|
|
283
|
+
or "html" not in response.headers.get("Content-Type", "").lower()
|
|
284
|
+
):
|
|
276
285
|
return links
|
|
277
286
|
|
|
278
287
|
soup = BeautifulSoup(response.text[:300000], "html.parser")
|
|
@@ -449,7 +458,10 @@ class TOSEvaluatorSkill(BaseSkill):
|
|
|
449
458
|
return False
|
|
450
459
|
if robots_assessment.get("can_fetch") is False:
|
|
451
460
|
return False
|
|
452
|
-
return bool(
|
|
461
|
+
return bool(
|
|
462
|
+
tos_assessment.get("matched_clauses")
|
|
463
|
+
or tos_assessment["status"] == "caution"
|
|
464
|
+
)
|
|
453
465
|
|
|
454
466
|
def _run_llm_evaluator(
|
|
455
467
|
self, normalized: Dict[str, Any], tos_assessment: Dict[str, Any]
|
|
@@ -512,26 +524,33 @@ class TOSEvaluatorSkill(BaseSkill):
|
|
|
512
524
|
verdict = "INSUFFICIENT_EVIDENCE"
|
|
513
525
|
confidence_score = 0.35
|
|
514
526
|
reason = "Insufficient policy evidence to safely approve the requested action."
|
|
515
|
-
recommended_next_step =
|
|
527
|
+
recommended_next_step = (
|
|
528
|
+
"Review the discovered policy pages manually before proceeding."
|
|
529
|
+
)
|
|
516
530
|
|
|
517
531
|
if robots_assessment.get("can_fetch") is False:
|
|
518
532
|
verdict = "UNSAFE"
|
|
519
533
|
confidence_score = 0.98
|
|
520
534
|
reason = robots_assessment["reason"]
|
|
521
|
-
recommended_next_step =
|
|
522
|
-
"Do not automate access to this path unless you have explicit permission."
|
|
523
|
-
)
|
|
535
|
+
recommended_next_step = "Do not automate access to this path unless you have explicit permission."
|
|
524
536
|
elif tos_assessment["status"] == "blocked":
|
|
525
537
|
verdict = "UNSAFE"
|
|
526
538
|
confidence_score = 0.9
|
|
527
539
|
reason = tos_assessment["summary"]
|
|
528
|
-
recommended_next_step =
|
|
540
|
+
recommended_next_step = (
|
|
541
|
+
"Avoid the requested action or obtain explicit written permission."
|
|
542
|
+
)
|
|
529
543
|
elif tos_assessment["status"] == "caution":
|
|
530
544
|
verdict = "CAUTION"
|
|
531
545
|
confidence_score = 0.65
|
|
532
546
|
reason = tos_assessment["summary"]
|
|
533
|
-
recommended_next_step =
|
|
534
|
-
|
|
547
|
+
recommended_next_step = (
|
|
548
|
+
"Prefer an official API or documented integration path if one exists."
|
|
549
|
+
)
|
|
550
|
+
elif (
|
|
551
|
+
tos_assessment["status"] == "allowed"
|
|
552
|
+
and robots_assessment.get("can_fetch") is not False
|
|
553
|
+
):
|
|
535
554
|
verdict = "SAFE"
|
|
536
555
|
confidence_score = 0.72
|
|
537
556
|
reason = tos_assessment["summary"]
|
|
@@ -575,7 +594,9 @@ class TOSEvaluatorSkill(BaseSkill):
|
|
|
575
594
|
"tos_assessment": tos_assessment,
|
|
576
595
|
"llm_assessment": llm_assessment or {"status": "not_used"},
|
|
577
596
|
"discovered_policy_urls": {
|
|
578
|
-
"candidates": [
|
|
597
|
+
"candidates": [
|
|
598
|
+
item["url"] for item in policy_candidates.get("candidates", [])
|
|
599
|
+
]
|
|
579
600
|
},
|
|
580
601
|
"evidence": evidence,
|
|
581
602
|
}
|
|
@@ -18,6 +18,7 @@ class SyntheticGeneratorSkill(BaseSkill):
|
|
|
18
18
|
manifest_path = os.path.join(os.path.dirname(__file__), "manifest.yaml")
|
|
19
19
|
if os.path.exists(manifest_path):
|
|
20
20
|
import yaml
|
|
21
|
+
|
|
21
22
|
with open(manifest_path, "r", encoding="utf-8") as f:
|
|
22
23
|
return yaml.safe_load(f)
|
|
23
24
|
return {}
|
|
@@ -35,16 +36,11 @@ class SyntheticGeneratorSkill(BaseSkill):
|
|
|
35
36
|
# Scaled for readability
|
|
36
37
|
return round(min(ratio * 1.5, 1.0), 3)
|
|
37
38
|
|
|
38
|
-
def _call_gemini(
|
|
39
|
-
self, prompt: str, temperature: float, model_name: str
|
|
40
|
-
) -> str:
|
|
39
|
+
def _call_gemini(self, prompt: str, temperature: float, model_name: str) -> str:
|
|
41
40
|
import google.genai as genai
|
|
42
41
|
from google.genai import types
|
|
43
42
|
|
|
44
|
-
api_key = (
|
|
45
|
-
self.config.get("GOOGLE_API_KEY")
|
|
46
|
-
or os.environ.get("GOOGLE_API_KEY")
|
|
47
|
-
)
|
|
43
|
+
api_key = self.config.get("GOOGLE_API_KEY") or os.environ.get("GOOGLE_API_KEY")
|
|
48
44
|
client = genai.Client(api_key=api_key)
|
|
49
45
|
response = client.models.generate_content(
|
|
50
46
|
model=model_name,
|
|
@@ -53,31 +49,28 @@ class SyntheticGeneratorSkill(BaseSkill):
|
|
|
53
49
|
)
|
|
54
50
|
return response.text
|
|
55
51
|
|
|
56
|
-
def _call_anthropic(
|
|
57
|
-
self, prompt: str, temperature: float, model_name: str
|
|
58
|
-
) -> str:
|
|
52
|
+
def _call_anthropic(self, prompt: str, temperature: float, model_name: str) -> str:
|
|
59
53
|
import anthropic
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
54
|
+
|
|
55
|
+
api_key = self.config.get("ANTHROPIC_API_KEY") or os.environ.get(
|
|
56
|
+
"ANTHROPIC_API_KEY"
|
|
63
57
|
)
|
|
64
58
|
client = anthropic.Anthropic(api_key=api_key)
|
|
65
59
|
message = client.messages.create(
|
|
66
60
|
model=model_name,
|
|
67
61
|
max_tokens=4096,
|
|
68
62
|
temperature=temperature,
|
|
69
|
-
messages=[{"role": "user", "content": prompt}]
|
|
63
|
+
messages=[{"role": "user", "content": prompt}],
|
|
70
64
|
)
|
|
71
65
|
return message.content[0].text
|
|
72
66
|
|
|
73
|
-
def _call_ollama(
|
|
74
|
-
self, prompt: str, temperature: float, model_name: str
|
|
75
|
-
) -> str:
|
|
67
|
+
def _call_ollama(self, prompt: str, temperature: float, model_name: str) -> str:
|
|
76
68
|
import ollama
|
|
69
|
+
|
|
77
70
|
response = ollama.chat(
|
|
78
71
|
model=model_name,
|
|
79
72
|
messages=[{"role": "user", "content": prompt}],
|
|
80
|
-
options={"temperature": temperature}
|
|
73
|
+
options={"temperature": temperature},
|
|
81
74
|
)
|
|
82
75
|
return response.get("message", {}).get("content", "")
|
|
83
76
|
|
|
@@ -107,21 +100,15 @@ class SyntheticGeneratorSkill(BaseSkill):
|
|
|
107
100
|
|
|
108
101
|
try:
|
|
109
102
|
if provider == "gemini":
|
|
110
|
-
raw_text = self._call_gemini(
|
|
111
|
-
system_prompt, temperature, model_name
|
|
112
|
-
)
|
|
103
|
+
raw_text = self._call_gemini(system_prompt, temperature, model_name)
|
|
113
104
|
elif provider == "anthropic":
|
|
114
|
-
raw_text = self._call_anthropic(
|
|
115
|
-
system_prompt, temperature, model_name
|
|
116
|
-
)
|
|
105
|
+
raw_text = self._call_anthropic(system_prompt, temperature, model_name)
|
|
117
106
|
else:
|
|
118
|
-
raw_text = self._call_ollama(
|
|
119
|
-
system_prompt, temperature, model_name
|
|
120
|
-
)
|
|
107
|
+
raw_text = self._call_ollama(system_prompt, temperature, model_name)
|
|
121
108
|
except Exception as e:
|
|
122
109
|
return {
|
|
123
110
|
"status": "error",
|
|
124
|
-
"message": f"LLM Call Failed via {provider}: {str(e)}"
|
|
111
|
+
"message": f"LLM Call Failed via {provider}: {str(e)}",
|
|
125
112
|
}
|
|
126
113
|
|
|
127
114
|
samples = []
|
|
@@ -141,7 +128,7 @@ class SyntheticGeneratorSkill(BaseSkill):
|
|
|
141
128
|
return {
|
|
142
129
|
"status": "error",
|
|
143
130
|
"message": f"Parsing failed: {e}",
|
|
144
|
-
"raw_output": raw_text
|
|
131
|
+
"raw_output": raw_text,
|
|
145
132
|
}
|
|
146
133
|
|
|
147
134
|
all_text = " ".join([str(s) for s in samples])
|
|
@@ -152,5 +139,5 @@ class SyntheticGeneratorSkill(BaseSkill):
|
|
|
152
139
|
"entropy_score": score,
|
|
153
140
|
"status": "success",
|
|
154
141
|
"provider_used": provider,
|
|
155
|
-
"samples_generated": len(samples)
|
|
142
|
+
"samples_generated": len(samples),
|
|
156
143
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Minimal contract ABIs for Uniswap V2 router and ERC20."""
|
|
2
|
+
|
|
3
|
+
ROUTER_V2_ABI = [
|
|
4
|
+
{
|
|
5
|
+
"name": "getAmountsOut",
|
|
6
|
+
"type": "function",
|
|
7
|
+
"stateMutability": "view",
|
|
8
|
+
"inputs": [
|
|
9
|
+
{"name": "amountIn", "type": "uint256"},
|
|
10
|
+
{"name": "path", "type": "address[]"},
|
|
11
|
+
],
|
|
12
|
+
"outputs": [{"name": "amounts", "type": "uint256[]"}],
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "getAmountsIn",
|
|
16
|
+
"type": "function",
|
|
17
|
+
"stateMutability": "view",
|
|
18
|
+
"inputs": [
|
|
19
|
+
{"name": "amountOut", "type": "uint256"},
|
|
20
|
+
{"name": "path", "type": "address[]"},
|
|
21
|
+
],
|
|
22
|
+
"outputs": [{"name": "amounts", "type": "uint256[]"}],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "swapExactTokensForTokens",
|
|
26
|
+
"type": "function",
|
|
27
|
+
"stateMutability": "nonpayable",
|
|
28
|
+
"inputs": [
|
|
29
|
+
{"name": "amountIn", "type": "uint256"},
|
|
30
|
+
{"name": "amountOutMin", "type": "uint256"},
|
|
31
|
+
{"name": "path", "type": "address[]"},
|
|
32
|
+
{"name": "to", "type": "address"},
|
|
33
|
+
{"name": "deadline", "type": "uint256"},
|
|
34
|
+
],
|
|
35
|
+
"outputs": [{"name": "amounts", "type": "uint256[]"}],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "swapTokensForExactTokens",
|
|
39
|
+
"type": "function",
|
|
40
|
+
"stateMutability": "nonpayable",
|
|
41
|
+
"inputs": [
|
|
42
|
+
{"name": "amountOut", "type": "uint256"},
|
|
43
|
+
{"name": "amountInMax", "type": "uint256"},
|
|
44
|
+
{"name": "path", "type": "address[]"},
|
|
45
|
+
{"name": "to", "type": "address"},
|
|
46
|
+
{"name": "deadline", "type": "uint256"},
|
|
47
|
+
],
|
|
48
|
+
"outputs": [{"name": "amounts", "type": "uint256[]"}],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "swapExactETHForTokens",
|
|
52
|
+
"type": "function",
|
|
53
|
+
"stateMutability": "payable",
|
|
54
|
+
"inputs": [
|
|
55
|
+
{"name": "amountOutMin", "type": "uint256"},
|
|
56
|
+
{"name": "path", "type": "address[]"},
|
|
57
|
+
{"name": "to", "type": "address"},
|
|
58
|
+
{"name": "deadline", "type": "uint256"},
|
|
59
|
+
],
|
|
60
|
+
"outputs": [{"name": "amounts", "type": "uint256[]"}],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "swapETHForExactTokens",
|
|
64
|
+
"type": "function",
|
|
65
|
+
"stateMutability": "payable",
|
|
66
|
+
"inputs": [
|
|
67
|
+
{"name": "amountOut", "type": "uint256"},
|
|
68
|
+
{"name": "path", "type": "address[]"},
|
|
69
|
+
{"name": "to", "type": "address"},
|
|
70
|
+
{"name": "deadline", "type": "uint256"},
|
|
71
|
+
],
|
|
72
|
+
"outputs": [{"name": "amounts", "type": "uint256[]"}],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "swapExactTokensForETH",
|
|
76
|
+
"type": "function",
|
|
77
|
+
"stateMutability": "nonpayable",
|
|
78
|
+
"inputs": [
|
|
79
|
+
{"name": "amountIn", "type": "uint256"},
|
|
80
|
+
{"name": "amountOutMin", "type": "uint256"},
|
|
81
|
+
{"name": "path", "type": "address[]"},
|
|
82
|
+
{"name": "to", "type": "address"},
|
|
83
|
+
{"name": "deadline", "type": "uint256"},
|
|
84
|
+
],
|
|
85
|
+
"outputs": [{"name": "amounts", "type": "uint256[]"}],
|
|
86
|
+
},
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
ERC20_ABI = [
|
|
90
|
+
{
|
|
91
|
+
"name": "balanceOf",
|
|
92
|
+
"type": "function",
|
|
93
|
+
"stateMutability": "view",
|
|
94
|
+
"inputs": [{"name": "account", "type": "address"}],
|
|
95
|
+
"outputs": [{"name": "", "type": "uint256"}],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "decimals",
|
|
99
|
+
"type": "function",
|
|
100
|
+
"stateMutability": "view",
|
|
101
|
+
"inputs": [],
|
|
102
|
+
"outputs": [{"name": "", "type": "uint8"}],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"name": "allowance",
|
|
106
|
+
"type": "function",
|
|
107
|
+
"stateMutability": "view",
|
|
108
|
+
"inputs": [
|
|
109
|
+
{"name": "owner", "type": "address"},
|
|
110
|
+
{"name": "spender", "type": "address"},
|
|
111
|
+
],
|
|
112
|
+
"outputs": [{"name": "", "type": "uint256"}],
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "approve",
|
|
116
|
+
"type": "function",
|
|
117
|
+
"stateMutability": "nonpayable",
|
|
118
|
+
"inputs": [
|
|
119
|
+
{"name": "spender", "type": "address"},
|
|
120
|
+
{"name": "amount", "type": "uint256"},
|
|
121
|
+
],
|
|
122
|
+
"outputs": [{"name": "", "type": "bool"}],
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"name": "transfer",
|
|
126
|
+
"type": "function",
|
|
127
|
+
"stateMutability": "nonpayable",
|
|
128
|
+
"inputs": [
|
|
129
|
+
{"name": "to", "type": "address"},
|
|
130
|
+
{"name": "amount", "type": "uint256"},
|
|
131
|
+
],
|
|
132
|
+
"outputs": [{"name": "", "type": "bool"}],
|
|
133
|
+
},
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
MAX_UINT256 = 2**256 - 1
|