Keep funding addresses refreshing without token list
Some checks failed
deploy / deploy (push) Failing after 29s
Some checks failed
deploy / deploy (push) Failing after 29s
Proof: supported_tokens bridge RPC failures no longer abort liquidity-manager deposit address refresh; regression tests cover the non-fatal warning path. Assumptions: deposit handles remain chain-level NEAR Intents bridge data and Gnosis assets share the Gnosis handle when the bridge deposit_address RPC succeeds. Still fake: USDC deposits are not proven credited yet; supported_tokens is still unavailable upstream until the bridge RPC responds successfully.
This commit is contained in:
parent
0f33a53fa9
commit
4bf15be22e
6 changed files with 94 additions and 11 deletions
|
|
@ -18,6 +18,7 @@ import {
|
|||
} from '../core/funding-observations.mjs';
|
||||
import { createJsonStateStore } from '../core/json-state-store.mjs';
|
||||
import { normalizeLiquidityState } from '../core/liquidity-state.mjs';
|
||||
import { refreshSupportedTokens } from '../core/liquidity-supported-tokens.mjs';
|
||||
import { buildBridgeWithdrawalPlan } from '../core/liquidity-withdrawals.mjs';
|
||||
import { createLogger, serializeError } from '../core/log.mjs';
|
||||
import { assertFundingObservationEvent, assertLiquidityActionEvent } from '../core/schemas.mjs';
|
||||
|
|
@ -133,8 +134,12 @@ async function refresh() {
|
|||
if (state.paused) return;
|
||||
|
||||
try {
|
||||
const supported = await bridgeClient.supportedTokens({ chains });
|
||||
state.supported_tokens = mapSupportedTokens(supported?.tokens || []);
|
||||
await refreshSupportedTokens({
|
||||
bridgeClient,
|
||||
chains,
|
||||
state,
|
||||
logger,
|
||||
});
|
||||
|
||||
for (const chain of chains) {
|
||||
await refreshChain(chain, state);
|
||||
|
|
@ -816,15 +821,6 @@ async function shutdown() {
|
|||
process.on('SIGINT', shutdown);
|
||||
process.on('SIGTERM', shutdown);
|
||||
|
||||
function mapSupportedTokens(tokens) {
|
||||
return Object.fromEntries(
|
||||
tokens.map((token) => [
|
||||
`${token.near_token_id}:${token.defuse_asset_identifier}`,
|
||||
token,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
function mapDepositAssetId(deposit, chain) {
|
||||
return bridgeDepositAssetId(deposit, {
|
||||
assetRegistry: runtimeConfig.assetRegistry,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ export function normalizeLiquidityState(state, { withdrawalsFrozen }) {
|
|||
state.deposits ||= {};
|
||||
state.tracked_withdrawals ||= {};
|
||||
state.supported_tokens ||= {};
|
||||
state.supported_tokens_error ??= null;
|
||||
state.funding_observations ||= {};
|
||||
state.funding_observations_by_handle ||= {};
|
||||
state.funding_visibility_by_asset ||= {};
|
||||
|
|
|
|||
34
src/core/liquidity-supported-tokens.mjs
Normal file
34
src/core/liquidity-supported-tokens.mjs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { serializeError } from './log.mjs';
|
||||
|
||||
export function mapSupportedTokens(tokens = []) {
|
||||
return Object.fromEntries(
|
||||
tokens.map((token) => [
|
||||
`${token.near_token_id}:${token.defuse_asset_identifier}`,
|
||||
token,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
export async function refreshSupportedTokens({
|
||||
bridgeClient,
|
||||
chains,
|
||||
state,
|
||||
logger = null,
|
||||
}) {
|
||||
try {
|
||||
const supported = await bridgeClient.supportedTokens({ chains });
|
||||
state.supported_tokens = mapSupportedTokens(supported?.tokens || []);
|
||||
state.supported_tokens_error = null;
|
||||
return { ok: true, token_count: Object.keys(state.supported_tokens).length };
|
||||
} catch (error) {
|
||||
const serialized = serializeError(error);
|
||||
state.supported_tokens_error = serialized;
|
||||
logger?.warn?.('supported_tokens_refresh_failed', {
|
||||
details: {
|
||||
chains,
|
||||
error: serialized,
|
||||
},
|
||||
});
|
||||
return { ok: false, error: serialized };
|
||||
}
|
||||
}
|
||||
|
|
@ -62,6 +62,7 @@ export function summarizeServiceState(service, state) {
|
|||
'funding_observer_paused',
|
||||
'withdrawals_frozen',
|
||||
'deposit_addresses',
|
||||
'supported_tokens_error',
|
||||
'withdrawal_defaults',
|
||||
'latest_funding_observation_at',
|
||||
'last_refresh_at',
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ test('normalizeLiquidityState hydrates missing nested maps from persisted partia
|
|||
assert.deepEqual(state.deposits, {});
|
||||
assert.deepEqual(state.tracked_withdrawals, {});
|
||||
assert.deepEqual(state.supported_tokens, {});
|
||||
assert.equal(state.supported_tokens_error, null);
|
||||
assert.deepEqual(state.funding_observations, {});
|
||||
assert.deepEqual(state.funding_observations_by_handle, {});
|
||||
assert.deepEqual(state.funding_visibility_by_asset, {});
|
||||
|
|
|
|||
50
test/liquidity-supported-tokens.test.mjs
Normal file
50
test/liquidity-supported-tokens.test.mjs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import {
|
||||
mapSupportedTokens,
|
||||
refreshSupportedTokens,
|
||||
} from '../src/core/liquidity-supported-tokens.mjs';
|
||||
|
||||
test('mapSupportedTokens indexes bridge tokens by near and intents identifiers', () => {
|
||||
const mapped = mapSupportedTokens([
|
||||
{
|
||||
near_token_id: 'token.near',
|
||||
defuse_asset_identifier: 'nep141:token.near',
|
||||
decimals: 18,
|
||||
},
|
||||
]);
|
||||
|
||||
assert.deepEqual(Object.keys(mapped), ['token.near:nep141:token.near']);
|
||||
assert.equal(mapped['token.near:nep141:token.near'].decimals, 18);
|
||||
});
|
||||
|
||||
test('refreshSupportedTokens records warning state without throwing', async () => {
|
||||
const state = {
|
||||
supported_tokens: {
|
||||
previous: { near_token_id: 'previous' },
|
||||
},
|
||||
};
|
||||
const warnings = [];
|
||||
|
||||
const result = await refreshSupportedTokens({
|
||||
bridgeClient: {
|
||||
async supportedTokens() {
|
||||
throw new Error('Bridge RPC supported_tokens failed');
|
||||
},
|
||||
},
|
||||
chains: ['btc', 'gnosis'],
|
||||
state,
|
||||
logger: {
|
||||
warn(event, fields) {
|
||||
warnings.push({ event, fields });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.ok, false);
|
||||
assert.equal(state.supported_tokens.previous.near_token_id, 'previous');
|
||||
assert.equal(state.supported_tokens_error.message, 'Bridge RPC supported_tokens failed');
|
||||
assert.equal(warnings[0].event, 'supported_tokens_refresh_failed');
|
||||
assert.deepEqual(warnings[0].fields.details.chains, ['btc', 'gnosis']);
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue