Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 179 additions & 0 deletions skills/afp-product-builder/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
---
name: afp-product-builder
description: Build valid AFP products by composing on-chain PredictionProductV1, extended metadata DAG, and API-backed resolution rules. Use when creating or validating AFP product JSON for Forecastathon, selecting public data sources, or preparing IPFS pinning and registration.
compatibility: Requires Python 3.11+, afp-sdk, internet access, and an IPFS pinning endpoint (Filebase or IPFS node).
metadata:
author: autonity
version: "0.1.0"
---

# AFP Product Builder

Use this skill to produce a complete, valid product specification for the
Forecastathon competition, including extended metadata that can be pinned to
IPFS as a DAG-CBOR encoded DAG.

## Inputs to gather first

- Network: bakerloo or mainnet.
- Builder address (Forecastathon-registered).
- Product type: time series (scalar) or event (binary or ternary).
- Data source: public API URL and fields to extract.
- Start time and earliest FSP submission time (UTC ISO 8601).
- Min and max price band (unleveraged products only).
- Symbol and description.

## Forecastathon constraints (must enforce)

- Required contract addresses:
- Bakerloo: oracleAddress `0x72EeD9f7286292f119089F56e3068a3A931FCD49`,
collateralAsset `0xDEfAaC81a079533Bf2fb004c613cc2870cF0A5b5`.
- Mainnet: oracleAddress `0x06CaDDDf6CC08048596aE051c8ce644725219C73`,
collateralAsset `0xAE2C6c29F6403fDf5A31e74CC8bFd1D75a3CcB8d`.
- Builder must be a registered Forecastathon participant.
- startTime must be at least two full working days after PR submission.
- Products are unleveraged and must define minPrice and maxPrice.
- Extended metadata must be pinned on IPFS and conform to standard schemas.
- API source must be valid and freely accessible.

## Build the on-chain product (PredictionProductV1)

Use camelCase field names inside `product`:

- product.base.metadata.builder (EVM checksum address)
- product.base.metadata.symbol (A-Z0-9, 1-16 chars)
- product.base.metadata.description
- product.base.oracleSpec.oracleAddress (required per network)
- product.base.oracleSpec.fsvDecimals, fspAlpha, fspBeta, fsvCalldata
- product.base.collateralAsset (required per network)
- product.base.startTime (UTC ISO 8601, Z)
- product.base.pointValue
- product.base.priceDecimals
- product.base.extendedMetadata (CID, filled after pinning)
- product.expirySpec.earliestFSPSubmissionTime (UTC ISO 8601, Z)
- product.expirySpec.tradeoutInterval
- product.minPrice < product.maxPrice

## Build extended metadata (snake_case)

Extended metadata fields are `outcome_space`, `outcome_point`, `oracle_config`,
and `oracle_fallback`. These are pinned on IPFS and referenced by CID.

### Outcome space and point

Time series (scalar):

- outcome_space: OutcomeSpaceTimeSeries
- fsp_type: "scalar"
- description
- base_case.condition and base_case.fsp_resolution
- edge_cases (optional)
- units, source_name, source_uri
- frequency: daily, weekly, fortnightly, semimonthly, monthly, quarterly, yearly
- history_api_spec (optional for backing data)
- outcome_point: OutcomePointTimeSeries
- fsp_type: "scalar"
- observation.reference_date and observation.release_date (YYYY-MM-DD)

Event (binary or ternary):

- outcome_space: OutcomeSpace
- fsp_type: "binary" or "ternary"
- description
- base_case.condition and base_case.fsp_resolution
- edge_cases (optional)
- outcome_point: OutcomePointEvent
- fsp_type: "binary" or "ternary"
- outcome (specific candidate or yes/no outcome)

Template variables in conditions must resolve against outcome_point fields.
Example: `{outcome}` for events, `{observation.release_date}` for time series.

### Oracle config

Manual resolution:

- oracle_config: OracleConfig
- description
- project_url (optional)

API-backed resolution:

- oracle_config: OracleConfigPrototype1
- description
- project_url (optional)
- evaluation_api_spec: ApiSpecJSONPath
- spec_variant: "product-fsv"
- url, date_path, value_path
- date_format_type: iso_8601 | unix_timestamp | custom
- timestamp_scale if unix timestamps are ms
- auth_param_location: none | query | header
- auth_param_name / auth_param_prefix if needed

For time series, `history_api_spec` (OutcomeSpaceTimeSeries) should use
`spec_variant: "underlying-history"` when you include it.

### Oracle fallback

- oracle_fallback.fallback_time must be at least 7 days after
earliestFSPSubmissionTime.
- oracle_fallback.fallback_fsp must be within [minPrice, maxPrice].

## API spec guidance

- Use JSONPath strings that select parallel arrays for dates and values.
- Prefer APIs that return ISO 8601 dates or UNIX timestamps to avoid custom
parsing.
- Verify the URL is reachable (HEAD request succeeds).
- Prefer no-auth or free-access endpoints for Forecastathon.
- See references/api-sources.md for vetted examples.

## IPFS pinning (DAG-CBOR required)

Extended metadata must be pinned as a DAG-CBOR DAG, not a single JSON blob.
The AFP SDK handles this automatically by encoding and pinning each component
and the root DAG:

```python
import afp

app = afp.AFP(
rpc_url=AUTONITY_RPC_URL,
authenticator=afp.PrivateKeyAuthenticator(PRIVATE_KEY),
ipfs_api_url=IPFS_API_URL,
ipfs_api_key=IPFS_API_KEY,
)
product_api = app.Product()

spec = product_api.validate(product_dict)
pinned = product_api.pin(spec) # builds and pins DAG-CBOR
```

If you build the DAG manually, ensure you store it as dag-cbor (e.g.,
`ipfs dag put` default store codec) and include schema CIDs for each component.

## Validation and output

1) Use `Product.validate` or `Product.validate_json` to enforce schemas.
2) Ensure business rules and Forecastathon constraints pass.
3) Use `Product.dump_json` for canonical JSON output.

```python
import afp

product_api = afp.AFP(...).Product()
spec = product_api.validate(product_dict)
pinned = product_api.pin(spec)
product_json = product_api.dump_json(pinned)
```

## Deliverables

- Complete product JSON with `extendedMetadata` CID filled in.
- Clear explanation of outcome_space resolution and data source.
- Validation checklist confirmation (see references/validation-checklist.md).

## References

- Public API options and JSONPath examples: references/api-sources.md
- Validation checklist and constraints: references/validation-checklist.md
103 changes: 103 additions & 0 deletions skills/afp-product-builder/references/api-sources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Public API sources (examples)

Each example below includes a sample endpoint and a matching ApiSpecJSONPath
snippet. Verify the endpoint response and terms of use before finalizing.

## Open-Meteo (weather, no key for non-commercial)

Sample endpoint:

`https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&daily=temperature_2m_max&timezone=UTC`

ApiSpecJSONPath:

```json
{
"standard": "JSONPath",
"spec_variant": "underlying-history",
"url": "https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&daily=temperature_2m_max&timezone=UTC",
"date_path": "$.daily.time[*]",
"value_path": "$.daily.temperature_2m_max[*]",
"date_format_type": "iso_8601",
"timezone": "UTC"
}
```

Notes:
- Returns ISO 8601 dates in `daily.time`.
- Ensure daily arrays align (same length).

## Climate Monitor (climate, public)

Sample endpoint:

`https://climatemonitor.info/api/public/v1/co2/monthly_gl`

ApiSpecJSONPath:

```json
{
"standard": "JSONPath",
"spec_variant": "underlying-history",
"url": "https://climatemonitor.info/api/public/v1/co2/monthly_gl",
"date_path": "$.data.readings[*].label",
"value_path": "$.data.readings[*].value",
"date_format_type": "iso_8601",
"timezone": "UTC"
}
```

Notes:
- Response is JSend; data lives under `data.readings`.
- Labels are ISO 8601 dates in the example payloads.

## World Bank Indicators API (economic, public)

Sample endpoint:

`https://api.worldbank.org/v2/country/USA/indicator/FP.CPI.TOTL?format=json&per_page=1000`

ApiSpecJSONPath:

```json
{
"standard": "JSONPath",
"spec_variant": "underlying-history",
"url": "https://api.worldbank.org/v2/country/USA/indicator/FP.CPI.TOTL?format=json&per_page=1000",
"date_path": "$[1][*].date",
"value_path": "$[1][*].value",
"date_format_type": "custom",
"date_format_custom": "%Y",
"timezone": "UTC",
"max_pages": 1
}
```

Notes:
- The `date` field is a year string (YYYY). Use a custom format.
- Set `per_page` high to avoid pagination and keep `max_pages` small.

## CoinGecko Market Chart (crypto, public with rate limits)

Sample endpoint:

`https://api.coingecko.com/api/v3/coins/bitcoin/market_chart?vs_currency=usd&days=90`

ApiSpecJSONPath:

```json
{
"standard": "JSONPath",
"spec_variant": "underlying-history",
"url": "https://api.coingecko.com/api/v3/coins/bitcoin/market_chart?vs_currency=usd&days=90",
"date_path": "$.prices[*][0]",
"value_path": "$.prices[*][1]",
"date_format_type": "unix_timestamp",
"timestamp_scale": 1000,
"timezone": "UTC"
}
```

Notes:
- Timestamps are milliseconds since epoch.
- Check current API terms and rate limits; free access may be limited.
46 changes: 46 additions & 0 deletions skills/afp-product-builder/references/validation-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Validation checklist

Use this list to preflight a product before pinning or PR submission.

## Forecastathon rules

- Builder address is registered for Forecastathon.
- startTime is at least two full working days after PR submission.
- Correct oracleAddress and collateralAsset for the selected network.
- Only one environment per PR (bakerloo or mainnet).
- Product is unleveraged with explicit minPrice and maxPrice.
- Extended metadata is pinned on IPFS as DAG-CBOR.
- API source is reachable and freely accessible.

## On-chain product (PredictionProductV1)

- minPrice < maxPrice.
- startTime < earliestFSPSubmissionTime.
- builder and contract addresses are valid checksummed EVM addresses.
- symbol matches required pattern if time series.

## Extended metadata

- outcome_space.fsp_type matches outcome_point.fsp_type.
- outcome_space.base_case and edge_cases have non-empty condition and
fsp_resolution strings.
- Template variables in conditions resolve against outcome_point.
- oracle_fallback.fallback_time >= earliestFSPSubmissionTime + 7 days.
- oracle_fallback.fallback_fsp within [minPrice, maxPrice].
- OracleConfig and ApiSpec fields are present when used.

## Time series symbol format

Symbols encode the release date and frequency. Month codes:
F=Jan, G=Feb, H=Mar, J=Apr, K=May, M=Jun, N=Jul, Q=Aug, U=Sep, V=Oct,
X=Nov, Z=Dec.

Patterns (prefix is 1-8 uppercase letters):

- daily: PREFIXDDMYY (DD day, M month code, YY year)
- weekly/fortnightly: PREFIXWW WYY (ISO week number)
- semimonthly: PREFIX1MYY or PREFIX2MYY (1 = days 1-15, 2 = days 16+)
- monthly/quarterly: PREFIXMYY
- yearly: PREFIXYYYY

Release date in outcome_point must match the symbol date encoding.