Skip to content

Commit e973dad

Browse files
committed
refactor(x/oracle): move to time based prices
Signed-off-by: Artur Troian <troian@users.noreply.github.com>
1 parent bb176f0 commit e973dad

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1013
-443
lines changed

_docs/pyth-integration.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -693,12 +693,12 @@ cat > oracle-params-proposal.json << 'EOF'
693693
"summary": "Add the pyth contract address to authorized sources and configure oracle parameters for Pyth integration.",
694694
"messages": [
695695
{
696-
"@type": "/akash.oracle.v1.MsgUpdateParams",
696+
"@type": "/akash.oracle.v2.MsgUpdateParams",
697697
"authority": "akash10d07y265gmmuvt4z0w9aw880jnsr700jhe7z0f",
698698
"params": {
699699
"sources": ["<pyth-contract-address>"],
700700
"min_price_sources": 1,
701-
"max_price_staleness_blocks": 60,
701+
"max_price_staleness_period": 60,
702702
"twap_window": 180,
703703
"max_price_deviation_bps": 150,
704704
"feed_contracts_params": [
@@ -734,7 +734,7 @@ akash tx gov submit-proposal oracle-params-proposal.json \
734734
|------------------------------|----------|----------------------------------|-----------------|
735735
| `sources` | []String | Authorized contract addresses | `[]` |
736736
| `min_price_sources` | u32 | Minimum sources for valid price | `1` |
737-
| `max_price_staleness_blocks` | i64 | Max age in blocks (~6s/block) | `60` (~6 min) |
737+
| `max_price_staleness_period` | i64 | Max age in seconds (~6s/block) | `60` |
738738
| `twap_window` | i64 | TWAP calculation window (blocks) | `180` (~18 min) |
739739
| `max_price_deviation_bps` | u64 | Max deviation in basis points | `150` (1.5%) |
740740

@@ -757,7 +757,7 @@ cat > guardian-update-proposal.json << 'EOF'
757757
"summary": "Update guardian addresses to Wormhole Guardian Set 5",
758758
"messages": [
759759
{
760-
"@type": "/akash.oracle.v1.MsgUpdateParams",
760+
"@type": "/akash.oracle.v2.MsgUpdateParams",
761761
"authority": "akash10d07y265gmmuvt4z0w9aw880jnsr700jhe7z0f",
762762
"params": {
763763
"feed_contracts_params": [

_run/init.sh

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,12 @@ configure_genesis() {
109109
| jq -M '.app_state.wasm.params.instantiate_default_permission = "Everybody"' \
110110
| jq -M --argjson guardians "$guardian_json" --arg feed_id "$AKT_PRICE_FEED_ID" '
111111
.app_state.oracle.params.min_price_sources = 1 |
112-
.app_state.oracle.params.max_price_staleness_blocks = 100 |
112+
.app_state.oracle.params.max_price_staleness_period = 30 |
113113
.app_state.oracle.params.twap_window = 50 |
114-
.app_state.oracle.params.max_price_deviation_bps = 1000' \
114+
.app_state.oracle.params.max_price_deviation_bps = 1000 |
115+
.app_state.oracle.params.price_retention = "86400s" |
116+
.app_state.oracle.params.prune_epoch = "hour" |
117+
.app_state.oracle.params.max_prune_per_epoch = 1000' \
115118
> "${GENESIS_PATH}"
116119

117120
log "Genesis configuration complete"
@@ -236,7 +239,7 @@ EOF
236239
{
237240
"admin": "$admin_addr",
238241
"wormhole_contract": "$wormhole_addr",
239-
"update_fee": "1000000",
242+
"update_fee": "1000",
240243
"price_feed_id": "$AKT_PRICE_FEED_ID",
241244
"data_sources": [
242245
{
@@ -258,8 +261,8 @@ EOF
258261
pyth_addr=$(akash query wasm list-contract-by-code "$pyth_code_id" -o json | jq -r '.contracts[-1]')
259262
log "Pyth contract address: $pyth_addr"
260263

261-
# Register Pyth as authorized oracle source
262-
register_oracle_source "$pyth_addr"
264+
# Register Pyth as authorized oracle source and fund BME vault via gov proposal
265+
register_oracle_source "$pyth_addr" "$admin_addr"
263266

264267
# Write configuration for Hermes
265268
write_hermes_config "$pyth_addr"
@@ -271,37 +274,37 @@ EOF
271274

272275
register_oracle_source() {
273276
local pyth_addr=$1
274-
log "Registering Pyth contract as authorized oracle source..."
277+
local admin_addr=$2
278+
log "Registering Pyth contract as authorized oracle source and funding BME vault..."
275279

276-
# Build guardian addresses JSON array for the proposal
277-
local guardian_json="["
278-
for i in "${!GUARDIAN_ADDRESSES[@]}"; do
279-
if [ "$i" -gt 0 ]; then
280-
guardian_json+=","
281-
fi
282-
guardian_json+="\"${GUARDIAN_ADDRESSES[$i]}\""
283-
done
284-
guardian_json+="]"
285-
286-
# Create proposal JSON
280+
# Create proposal JSON with both oracle params and BME vault funding
287281
cat > /tmp/oracle-params.json <<EOF
288282
{
289283
"messages": [
290284
{
291-
"@type": "/akash.oracle.v1.MsgUpdateParams",
285+
"@type": "/akash.oracle.v2.MsgUpdateParams",
292286
"authority": "akash10d07y265gmmuvt4z0w9aw880jnsr700jhe7z0f",
293287
"params": {
294288
"sources": ["$pyth_addr"],
295289
"min_price_sources": 1,
296-
"max_price_staleness_blocks": 100,
290+
"max_price_staleness_period": 30,
297291
"twap_window": 50,
298-
"max_price_deviation_bps": 1000
292+
"max_price_deviation_bps": 1000,
293+
"price_retention": "86400s",
294+
"prune_epoch": "hour",
295+
"max_prune_per_epoch": 1000
299296
}
297+
},
298+
{
299+
"@type": "/akash.bme.v1.MsgFundVault",
300+
"authority": "akash10d07y265gmmuvt4z0w9aw880jnsr700jhe7z0f",
301+
"amount": {"denom": "${CHAIN_TOKEN_DENOM}", "amount": "1000000000000"},
302+
"source": "$admin_addr"
300303
}
301304
],
302305
"deposit": "10000000uakt",
303-
"title": "Register Pyth Contract",
304-
"summary": "Authorize pyth contract as oracle source"
306+
"title": "Register Pyth Contract and Fund BME Vault",
307+
"summary": "Authorize pyth contract as oracle source and seed BME vault with initial AKT"
305308
}
306309
EOF
307310

_run/node/prop.json

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
{
22
"messages": [
33
{
4-
"@type": "/akash.oracle.v1.MsgUpdateParams",
4+
"@type": "/akash.oracle.v2.MsgUpdateParams",
55
"authority": "akash10d07y265gmmuvt4z0w9aw880jnsr700jhe7z0f",
66
"params": {
77
"sources": [
88
"akash1xcfl5u6g2yprvpr4q8j2pp5h6l5ys3nuf529qa"
99
],
1010
"min_price_sources": 1,
11-
"max_price_staleness_blocks": "60",
11+
"max_price_staleness_period": "30",
1212
"twap_window": "50",
1313
"max_price_deviation_bps": "150",
14-
"feed_contracts_params": [
15-
{
16-
"@type": "/akash.oracle.v1.PythContractParams",
17-
"akt_price_feed_id": "0x4ea5bb4d2f5900cc2e97ba534240950740b4d3b89fe712a94a7304fd2fd92702"
18-
}
19-
]
14+
"price_retention": "86400s",
15+
"prune_epoch": "hour",
16+
"max_prune_per_epoch": "1000"
2017
}
2118
}
2219
],

app/types/app.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ import (
7070
etypes "pkg.akt.dev/go/node/escrow/module"
7171
mtypes "pkg.akt.dev/go/node/market/v1"
7272
mvbeta "pkg.akt.dev/go/node/market/v1beta5"
73-
otypes "pkg.akt.dev/go/node/oracle/v1"
73+
otypes "pkg.akt.dev/go/node/oracle/v2"
7474
ptypes "pkg.akt.dev/go/node/provider/v1beta4"
7575
wtypes "pkg.akt.dev/go/node/wasm/v1"
7676
"pkg.akt.dev/go/sdkutil"
@@ -420,12 +420,14 @@ func (app *App) InitNormalKeepers(
420420
app.Keepers.Akash.Oracle = okeeper.NewKeeper(
421421
cdc,
422422
app.keys[otypes.StoreKey],
423+
app.tkeys[otypes.TStoreKey],
423424
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
424425
)
425426

426427
app.Keepers.Akash.Bme = bmekeeper.NewKeeper(
427428
cdc,
428429
app.keys[bmetypes.StoreKey],
430+
app.tkeys[bmetypes.TStoreKey],
429431
app.AC,
430432
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
431433
app.Keepers.Cosmos.Acct,
@@ -570,7 +572,9 @@ func (app *App) SetupHooks() {
570572
app.Keepers.Akash.Escrow.AddOnAccountClosedHook(hook.OnEscrowAccountClosed)
571573
app.Keepers.Akash.Escrow.AddOnPaymentClosedHook(hook.OnEscrowPaymentClosed)
572574

573-
app.Keepers.Akash.Epochs.SetHooks(epochstypes.NewMultiEpochHooks())
575+
app.Keepers.Akash.Epochs.SetHooks(epochstypes.NewMultiEpochHooks(
576+
okeeper.EpochHooksFor(app.Keepers.Akash.Oracle),
577+
))
574578
}
575579

576580
// initParamsKeeper init params keeper and its subspaces
@@ -634,6 +638,8 @@ func kvStoreKeys() []string {
634638
func transientStoreKeys() []string {
635639
return []string{
636640
paramstypes.TStoreKey,
641+
bmetypes.TStoreKey,
642+
otypes.TStoreKey,
637643
}
638644
}
639645

contracts/pyth/src/contract.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,10 @@ pub fn execute_update_price_feed(
254254
});
255255
}
256256

257-
// Update contract storage only if price is actually newer.
258-
// When publish_time == stored, skip the storage write but still
259-
// forward to x/oracle below to refresh the block height and
260-
// prevent the oracle price from going stale.
261-
if publish_time > price_feed.publish_time {
257+
// Update contract storage for same or newer timestamps.
258+
// Pyth may submit multiple prices within the same timestamp
259+
// but from different slots — all should be accepted.
260+
if publish_time >= price_feed.publish_time {
262261
price_feed.prev_publish_time = price_feed.publish_time;
263262
price_feed.price = price;
264263
price_feed.conf = conf;
@@ -286,7 +285,7 @@ pub fn execute_update_price_feed(
286285

287286
// Create Any message to submit price to x/oracle module
288287
let oracle_cosmos_msg: CosmosMsg = CosmosMsg::Any(AnyMsg {
289-
type_url: "/akash.oracle.v1.MsgAddPriceEntry".to_string(),
288+
type_url: "/akash.oracle.v2.MsgAddPriceEntry".to_string(),
290289
value: oracle_data.clone(),
291290
});
292291

contracts/pyth/src/integration_tests.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,9 @@ fn e2e_oracle_message_encoding() {
252252

253253
assert_eq!(msg.id.denom, "akt");
254254
assert_eq!(msg.id.base_denom, "usd");
255-
assert_eq!(msg.price.price, "1234567890000000000");
256-
assert_eq!(msg.price.timestamp_seconds, 1700000000);
257-
assert_eq!(msg.price.timestamp_nanos, 0);
255+
assert_eq!(msg.price, "1234567890000000000");
256+
assert_eq!(msg.timestamp_seconds, 1700000000);
257+
assert_eq!(msg.timestamp_nanos, 0);
258258

259259
let binary = msg.encode_to_protobuf();
260260
assert!(!binary.is_empty());
@@ -366,7 +366,8 @@ fn e2e_protobuf_encoding_verification() {
366366
// Verify structure:
367367
// Field 1 (signer): tag 0x0a, length, "akash1test"
368368
// Field 2 (id): tag 0x12, length, DataID submessage
369-
// Field 3 (price): tag 0x1a, length, PriceDataState submessage
369+
// Field 3 (price): tag 0x1a, length, cosmos.Dec string
370+
// Field 4 (timestamp): tag 0x22, length, google.protobuf.Timestamp
370371

371372
assert_eq!(binary[0], 0x0a); // Field 1 tag
372373

0 commit comments

Comments
 (0)