diff --git a/packages/sdk-core/README.md b/packages/sdk-core/README.md index 1016b501..59be8918 100644 --- a/packages/sdk-core/README.md +++ b/packages/sdk-core/README.md @@ -102,84 +102,12 @@ The on-chain registry is authoritative for protocol identity and activation. RPC URLs, explorers, icons, wallet adapters, and application capabilities stay in the consuming application's runtime configuration. -## Reserves +## Depot-native settlement -`contracts.sysio.reserv` provides normalized reserve registry reads, -chain/token and status filters, exact reserve lookup, WIRE-side activation, and -read-only swap quotes. External-chain reserve creation and cancellation remain -in the chain SDK that owns the deployed ABI or IDL. - -```ts -const reserves = new contracts.sysio.reserv.ReserveClient({ client: api }) -const pending = await reserves.listReserves({ - status: SysioReservReservestatus.RESERVE_STATUS_PENDING -}) - -await reserves.pushMatchReserve({ - chainCode: "ETHEREUM", - tokenCode: "ETH", - reserveCode: "PRIMARY", - matcher: "alice", - wireAmount: pending[0].requestedWireAmount -}) - -// Several pending rows can be activated atomically in one signed transaction. -await reserves.pushMatchReserves({ - matches: pending.map(reserve => ({ - chainCode: reserve.chainCode, - tokenCode: reserve.tokenCode, - reserveCode: reserve.reserveCode, - matcher: "alice", - wireAmount: reserve.requestedWireAmount - })) -}) -``` - -`pushMatchReserves` preserves the supplied action order and rejects an empty -match list. The Wire transaction is atomic: either every `matchreserve` action -is accepted or none is applied. - -## Reserve swaps - -Reserve swap integrations compose three on-chain sources instead of carrying a -parallel token or route catalog: - -- `contracts.sysio.tokens.TokenRegistryClient` reads canonical token metadata - and active chain deployments. -- `contracts.sysio.reserv.ReserveClient` discovers active liquidity and returns - live `swapquote` output for external or WIRE endpoints. -- `contracts.sysio.uwrit.UnderwritingClient` reads swap lifecycle state and - submits WIRE-origin swaps into the next-epoch queue. - -```ts -const tokens = new contracts.sysio.tokens.TokenRegistryClient({ client: api }) -const reserves = new contracts.sysio.reserv.ReserveClient({ client: api }) -const underwriting = new contracts.sysio.uwrit.UnderwritingClient({ client: api }) - -const assets = await tokens.listAssets() -const quote = await reserves.getSwapQuote({ - from: contracts.sysio.uwrit.WIRE_SWAP_ENDPOINT, - fromAmount: 10_000_000_000n, - to: { chainCode: "SOLANA", tokenCode: "SOL", reserveCode: "PRIMARY" } -}) - -await underwriting.pushSwapFromWire({ - user: "alice", - wireAmount: 10_000_000_000n, - destination: { chainCode: "SOLANA", tokenCode: "SOL", reserveCode: "PRIMARY" }, - targetAmount: quote, - targetToleranceBps: 500, - recipientKind: SysioUwritChainkind.CHAIN_KIND_SVM, - recipientAddress: "" -}) -``` - -External-origin swap submission remains in the chain SDK that owns the deployed -outpost ABI or IDL. A mined source transaction means the swap was submitted; -`uwreqs` remains the source of truth for relay, underwriting, settlement, and -revert status. Normalized underwriting rows expose `sourceRequestId` for -matching the outpost's `SwapDeposit` id; transaction hashes and signatures are -transport receipts rather than protocol correlation values. +Use generated `sysio.opreg`, `sysio.synd`, `sysio.bond`, `sysio.liq` and +`sysio.swap` proxies for collateral, syndicated envelopes, bond resolution, +shadow LIQ and native pools. `TokenRegistryClient` supplies canonical asset +metadata. The external reserve and swap-underwriter clients have been removed. ## Install diff --git a/packages/sdk-core/src/contracts/sysio/Codecs.ts b/packages/sdk-core/src/contracts/sysio/Codecs.ts index bb03b620..b59308bd 100644 --- a/packages/sdk-core/src/contracts/sysio/Codecs.ts +++ b/packages/sdk-core/src/contracts/sysio/Codecs.ts @@ -11,7 +11,6 @@ import { MsigPropose, MsigUnapprove } from "./msig/Structs.js" -import { ReservMatchReserve, ReservSwapQuote } from "./reserv/Structs.js" /** Generated action names for one system contract. */ type ActionName = Extract< @@ -49,10 +48,6 @@ const ActionCodecs: SysioActionCodecMapping = { invalidate: { serialize: data => MsigInvalidate.from(data) }, propose: { serialize: data => MsigPropose.from(data) }, unapprove: { serialize: data => MsigUnapprove.from(data) } - }, - [SysioContractName.reserv]: { - matchreserve: { serialize: data => ReservMatchReserve.from(data) }, - swapquote: { serialize: data => ReservSwapQuote.from(data) } } } diff --git a/packages/sdk-core/src/contracts/sysio/index.ts b/packages/sdk-core/src/contracts/sysio/index.ts index fa93c4e5..8bc21455 100644 --- a/packages/sdk-core/src/contracts/sysio/index.ts +++ b/packages/sdk-core/src/contracts/sysio/index.ts @@ -1,7 +1,5 @@ export * as authex from "./authex/index.js" export * as chains from "./chains/index.js" export * as msig from "./msig/index.js" -export * as reserv from "./reserv/index.js" export * as tokens from "./tokens/index.js" -export * as uwrit from "./uwrit/index.js" export * from "./Client.js" diff --git a/packages/sdk-core/src/contracts/sysio/reserv/Actions.ts b/packages/sdk-core/src/contracts/sysio/reserv/Actions.ts deleted file mode 100644 index 40f99470..00000000 --- a/packages/sdk-core/src/contracts/sysio/reserv/Actions.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { Action } from "../../../chain/Action.js" -import { Name } from "../../../chain/Name.js" -import { PermissionLevel } from "../../../chain/PermissionLevel.js" -import type * as SysioContracts from "../../../types/SysioContractTypes.js" -import { SysioContractName } from "../../../types/SysioContractTypes.js" -import { assertEncodedAction, getSysioContract } from "../Client.js" - -import { DEFAULT_RESERV_CONTRACT } from "./Constants.js" -import { reserveSlugString } from "./Slug.js" -import type { MatchReserveOptions, ReserveQuoteOptions } from "./Types.js" - -/** Any value with a string form — an amount as a number, string, bigint, or a BN/Decimal-like object. */ -interface Stringifiable { - toString(): string -} - -function amountString(value: number | string | bigint | Stringifiable): string { - return value.toString() -} - -/** Builds generated action data for `sysio.reserv::matchreserve`. */ -export function matchReserveActionData( - options: MatchReserveOptions -): SysioContracts.SysioReservMatchreserveAction { - return { - chain_code: reserveSlugString(options.chainCode), - token_code: reserveSlugString(options.tokenCode), - reserve_code: reserveSlugString(options.reserveCode), - matcher: Name.from(options.matcher).toString(), - wire_amount: amountString(options.wireAmount) - } -} - -/** Builds an unsigned `sysio.reserv::matchreserve` action. */ -export function buildMatchReserveAction(options: MatchReserveOptions): Action { - const matcher = Name.from(options.matcher) - - return assertEncodedAction( - getSysioContract(SysioContractName.reserv, { - contract: options.contract || DEFAULT_RESERV_CONTRACT - }).actions.matchreserve.prepare(matchReserveActionData(options), { - authorization: [ - PermissionLevel.from({ - actor: matcher, - permission: options.permission || "active" - }) - ] - }) - ) -} - -/** Builds generated action data for read-only `sysio.reserv::swapquote`. */ -export function swapQuoteActionData( - options: ReserveQuoteOptions -): SysioContracts.SysioReservSwapquoteAction { - return { - from_chain_code: reserveSlugString(options.from.chainCode), - from_token_code: reserveSlugString(options.from.tokenCode), - from_reserve_code: reserveSlugString(options.from.reserveCode), - from_amount: amountString(options.fromAmount), - to_chain_code: reserveSlugString(options.to.chainCode), - to_token_code: reserveSlugString(options.to.tokenCode), - to_reserve_code: reserveSlugString(options.to.reserveCode) - } -} - -/** Builds an unsigned read-only `sysio.reserv::swapquote` action. */ -export function buildSwapQuoteAction(options: ReserveQuoteOptions): Action { - return assertEncodedAction( - getSysioContract(SysioContractName.reserv, { - contract: options.contract || DEFAULT_RESERV_CONTRACT - }).actions.swapquote.prepare(swapQuoteActionData(options)) - ) -} diff --git a/packages/sdk-core/src/contracts/sysio/reserv/Client.ts b/packages/sdk-core/src/contracts/sysio/reserv/Client.ts deleted file mode 100644 index 0600b973..00000000 --- a/packages/sdk-core/src/contracts/sysio/reserv/Client.ts +++ /dev/null @@ -1,313 +0,0 @@ -import type { APIClient } from "../../../api/Client.js" -import type { TransactionExtraOptions } from "../../../api/Types.js" -import type { Action } from "../../../chain/Action.js" -import { UInt64 } from "../../../chain/Integer.js" -import { Name, type NameType } from "../../../chain/Name.js" -import { SignedTransaction } from "../../../chain/Transaction.js" -import { Serializer } from "../../../serializer/index.js" -import { - SysioReservChainkind, - SysioReservReservestatus, - SysioContractName -} from "../../../types/SysioContractTypes.js" -import type * as SysioContracts from "../../../types/SysioContractTypes.js" -import type { ContractTableRowsOptions } from "../../Contract.js" -import { getSysioContract, type SysioContractClient } from "../Client.js" - -import { - buildMatchReserveAction, - buildSwapQuoteAction, - matchReserveActionData -} from "./Actions.js" -import { - DEFAULT_RESERV_CONTRACT, - DEFAULT_RESERVE_QUERY_LIMIT -} from "./Constants.js" -import { reserveSlugString, reserveSlugValue } from "./Slug.js" -import type { - ListReservesOptions, - PushMatchReserveOptions, - PushMatchReservesOptions, - ReserveClientOptions, - ReserveIdentity, - ReserveQuoteOptions, - ReserveRecord, - ReserveRewards -} from "./Types.js" - -/** Push-transaction response returned by the configured API client. */ -type APIClientPushTransactionResponse = ReturnType - -function enumValue>( - enumType: T, - value: number | keyof T -): number { - if (typeof value === "number") return value - - const serialized = String(value) - if (/^[0-9]+$/.test(serialized)) return Number(serialized) - - const mapped = enumType[value] - if (mapped == null) { - throw new Error(`Unknown reserve enum value: ${serialized}`) - } - return Number(mapped) -} - -function bigintValue(value: number | string): bigint { - return BigInt(value.toString()) -} - -function accountString(value: NameType): string { - return Name.from(value).toString() -} - -function optionalAccountString(value: NameType): string { - return value ? accountString(value) : "" -} - -/** Normalizes a generated reserve row into application-friendly values. */ -export function normalizeReserveRow( - row: SysioContracts.SysioReservReserveRowType -): ReserveRecord { - const chainCodeValue = reserveSlugValue(row.chain_code), - tokenCodeValue = reserveSlugValue(row.token_code), - reserveCodeValue = reserveSlugValue(row.reserve_code) - - return { - chainCode: reserveSlugString(chainCodeValue), - chainCodeValue, - tokenCode: reserveSlugString(tokenCodeValue), - tokenCodeValue, - reserveCode: reserveSlugString(reserveCodeValue), - reserveCodeValue, - name: row.name, - description: row.description, - status: enumValue( - SysioReservReservestatus, - row.status - ) as SysioReservReservestatus, - chainAmount: bigintValue(row.reserve_chain_amount), - wireAmount: bigintValue(row.reserve_wire_amount), - sourceTokenPrecision: row.source_token_precision, - connectorWeightBps: row.connector_weight_bps, - creatorChainKind: enumValue( - SysioReservChainkind, - row.creator_addr.kind - ) as SysioReservChainkind, - creatorAddress: row.creator_addr.address, - requestedWireAmount: bigintValue(row.requested_wire_amount), - externalTokenAmount: bigintValue(row.external_token_amount), - registeredAtMs: bigintValue(row.registered_at_ms), - activatedAtMs: bigintValue(row.activated_at_ms), - cancelledAtMs: bigintValue(row.cancelled_at_ms), - isPrivate: row.is_private, - owner: optionalAccountString(row.owner), - creatorPublicKey: row.creator_pub_key, - raw: row - } -} - -/** Decodes the uint64 return value from a read-only reserve action trace. */ -export function decodeReserveUInt64Return(response: any): bigint { - const traces = response?.processed?.action_traces || [], - trace = traces.find((candidate: any) => candidate?.act?.name) || traces[0], - value = - trace?.return_value_data ?? - trace?.return_value ?? - trace?.return_value_hex_data ?? - trace?.return_value_data_hex - - if (value == null || value === "") { - throw new Error( - "Unable to find reserve return value in read-only transaction trace." - ) - } - - if (typeof value === "number" || typeof value === "bigint") { - return BigInt(value) - } - - if (typeof value === "string" && /^[0-9]+$/.test(value)) { - return BigInt(value) - } - - const decoded = Serializer.decode({ data: value, type: UInt64 }) as UInt64 - return BigInt(decoded.toString()) -} - -/** UI-neutral client for public `sysio.reserv` reads and user actions. */ -export class ReserveClient { - /** Chain API client used for RPC calls. */ - readonly client: APIClient - - /** Reserve contract account. */ - readonly contract: NameType - - /** Generic typed client for direct public action and table access. */ - readonly contractClient: SysioContractClient - - /** Creates a reserve client. */ - constructor(config: ReserveClientOptions) { - this.client = config.client - this.contract = config.contract || DEFAULT_RESERV_CONTRACT - this.contractClient = getSysioContract(SysioContractName.reserv, { - client: config.client, - contract: this.contract - }) - } - - /** Lists raw generated reserve rows with optional indexed filtering. */ - async listReserveRows( - options: ListReservesOptions = {} - ): Promise { - const limit = Math.max( - Math.floor(options.limit || DEFAULT_RESERVE_QUERY_LIMIT), - 1 - ), - owner = options.owner ? accountString(options.owner) : null, - rows: SysioContracts.SysioReservReserveRowType[] = [] - let lowerBound: string | undefined - - // The v6 node JSON API currently exposes KV rows through their primary - // key only. Scan pages and filter locally until named-index traversal is - // available; callers receive the same stable API when that optimization lands. - do { - const query: ContractTableRowsOptions = { - limit: DEFAULT_RESERVE_QUERY_LIMIT, - ...(lowerBound ? { lower_bound: lowerBound } : {}) - }, - result = await this.contractClient.tables.reserves.query(query), - matches = result.rows.filter(row => { - const status = enumValue(SysioReservReservestatus, row.status), - chainMatches = - options.chainCode == null || - reserveSlugValue(row.chain_code) === - reserveSlugValue(options.chainCode), - tokenMatches = - options.tokenCode == null || - reserveSlugValue(row.token_code) === - reserveSlugValue(options.tokenCode), - statusMatches = options.status == null || status === options.status, - ownerMatches = !owner || optionalAccountString(row.owner) === owner, - privacyMatches = - options.isPrivate == null || row.is_private === options.isPrivate - - return ( - chainMatches && - tokenMatches && - statusMatches && - ownerMatches && - privacyMatches - ) - }) - - rows.push(...matches.slice(0, limit - rows.length)) - - const nextKey = result.more ? result.next_key : undefined - if (!nextKey || String(nextKey) === lowerBound) { - break - } - lowerBound = String(nextKey) - } while (rows.length < limit) - - return rows - } - - /** Lists normalized reserve records with optional indexed filtering. */ - async listReserves( - options: ListReservesOptions = {} - ): Promise { - return (await this.listReserveRows(options)).map(normalizeReserveRow) - } - - /** Reads one reserve by its three-part identity, or null when absent. */ - async getReserve(identity: ReserveIdentity): Promise { - const reserveCode = reserveSlugValue(identity.reserveCode), - rows = await this.listReserveRows({ - chainCode: identity.chainCode, - tokenCode: identity.tokenCode, - // Exact identity reads must not silently stop at the list-view cap. - limit: Number.MAX_SAFE_INTEGER - }), - row = rows.find( - candidate => reserveSlugValue(candidate.reserve_code) === reserveCode - ) - - return row ? normalizeReserveRow(row) : null - } - - /** Lists reserves owned by one matched Wire account. */ - async getOwnedReserves( - owner: NameType, - options: Omit = {} - ): Promise { - return this.listReserves({ ...options, owner }) - } - - /** Reads the reserve rewards bucket, returning zeroes before initialization. */ - async getRewards(): Promise { - const row = await this.contractClient.tables.rewardbkt.first() - - return { - balance: row ? bigintValue(row.balance) : 0n, - lifetimeAccrued: row ? bigintValue(row.lifetime_accrued) : 0n - } - } - - /** Builds and pushes a signed Wire transaction that activates a pending reserve. */ - async pushMatchReserve( - options: PushMatchReserveOptions, - pushOptions: TransactionExtraOptions = options.pushOptions || {} - ): APIClientPushTransactionResponse { - return this.contractClient.actions.matchreserve.invoke( - matchReserveActionData(options), - { - authorization: [ - { - actor: options.matcher, - permission: options.permission || "active" - } - ], - pushOptions - } - ) - } - - /** Builds and pushes one signed Wire transaction that activates several pending reserves atomically. */ - async pushMatchReserves( - options: PushMatchReservesOptions, - pushOptions: TransactionExtraOptions = options.pushOptions || {} - ): APIClientPushTransactionResponse { - if (options.matches.length === 0) { - throw new Error("At least one reserve match is required.") - } - - return this.client.pushTransaction( - options.matches.map(buildMatchReserveAction), - pushOptions - ) - } - - /** Reads the current on-chain quote for one reserve route. */ - async getSwapQuote(options: ReserveQuoteOptions): Promise { - const response = await this.sendReadOnlyAction( - buildSwapQuoteAction({ contract: this.contract, ...options }) - ) - return decodeReserveUInt64Return(response) - } - - private async sendReadOnlyAction(action: Action): Promise { - const info = await this.client.v1.chain.get_info(), - transaction = SignedTransaction.from({ - ...info.getTransactionHeader(), - context_free_actions: [], - actions: [action], - transaction_extensions: [], - signatures: [], - context_free_data: [] - }) - - return this.client.v1.chain.send_read_only_transaction(transaction) - } -} diff --git a/packages/sdk-core/src/contracts/sysio/reserv/Constants.ts b/packages/sdk-core/src/contracts/sysio/reserv/Constants.ts deleted file mode 100644 index b2f972c5..00000000 --- a/packages/sdk-core/src/contracts/sysio/reserv/Constants.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** Default account that hosts the Wire reserve registry. */ -export const DEFAULT_RESERV_CONTRACT = "sysio.reserv" - -/** Rows requested per page while scanning the v6 KV reserve table. */ -export const DEFAULT_RESERVE_QUERY_LIMIT = 500 - -/** Symmetric constant-product connector weight. */ -export const DEFAULT_CONNECTOR_WEIGHT_BPS = 5000 - -/** Lowest valid connector weight accepted by `sysio.reserv`. */ -export const MIN_CONNECTOR_WEIGHT_BPS = 1 - -/** Highest valid connector weight accepted by `sysio.reserv`. */ -export const MAX_CONNECTOR_WEIGHT_BPS = 9999 - -/** Fixed decimal precision of the WIRE side of every reserve. */ -export const WIRE_RESERVE_PRECISION = 9 diff --git a/packages/sdk-core/src/contracts/sysio/reserv/Slug.ts b/packages/sdk-core/src/contracts/sysio/reserv/Slug.ts deleted file mode 100644 index d2709c31..00000000 --- a/packages/sdk-core/src/contracts/sysio/reserv/Slug.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { SlugName, slugValue } from "../../../SlugName.js" - -import type { ReserveSlugName } from "./Types.js" - -/** - * Converts a reserve slug cell to its safe numeric form, in any carrier — - * see {@link slugValue} for how each one is read. - */ -export function reserveSlugValue(value: ReserveSlugName): number { - return slugValue(value, "Reserve") -} - -/** Returns the display form of a packed reserve slug. */ -export function reserveSlugString(value: ReserveSlugName): string { - return SlugName.toString(reserveSlugValue(value)) -} - -/** Packs a chain/token pair exactly as the deployed `bychaintok` index does. */ -export function reserveChainTokenIndexValue( - chainCode: ReserveSlugName, - tokenCode: ReserveSlugName -): bigint { - return ( - (BigInt(reserveSlugValue(chainCode)) << 64n) | - BigInt(reserveSlugValue(tokenCode)) - ) -} diff --git a/packages/sdk-core/src/contracts/sysio/reserv/Structs.ts b/packages/sdk-core/src/contracts/sysio/reserv/Structs.ts deleted file mode 100644 index 071bc1d0..00000000 --- a/packages/sdk-core/src/contracts/sysio/reserv/Structs.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { ABIDecoder } from "../../../serializer/Decoder.js" -import { ABIEncoder } from "../../../serializer/Encoder.js" -import { ABISerializableObject } from "../../../serializer/Serializable.js" -import { UInt64 } from "../../../chain/Integer.js" -import { Name } from "../../../chain/Name.js" -import { Struct } from "../../../chain/Struct.js" -import { SlugName } from "../../../SlugName.js" -import { isInstanceOf } from "../../../Utils.js" - -/** - * Runtime serializer for the Wire `slug_name` chain type used by `sysio.reserv`. - * - * Modelled on `Name`, not on `Struct`: `slug_name` is an ABI BUILTIN on the - * chain, so it has one wire form (a packed `uint64` — unchanged, the bytes are - * what the depot stores) and one JSON form (the canonical spelling, the only - * carrier the builtin emits or accepts). A `Struct` subclass cannot express - * that — the object decoder dispatches on `type.fields` before consulting a - * class's own `from`, so a struct-shaped slug can only ever be written as - * `{ value }`. - */ -export class ReservSlugName implements ABISerializableObject { - static abiName = "slug_name" - - /** Packed eight-symbol code — the wire form. */ - value: UInt64 - - /** Builds from the canonical spelling, an already-packed value, or itself. */ - static from(value: ReservSlugName | UInt64 | string | number): ReservSlugName { - if (isInstanceOf(value, ReservSlugName)) return value - if (isInstanceOf(value, UInt64)) return new ReservSlugName(value) - - return new ReservSlugName( - UInt64.from(typeof value === "string" ? SlugName.from(value) : value) - ) - } - - static fromABI(decoder: ABIDecoder) { - return new ReservSlugName(UInt64.fromABI(decoder)) - } - - static abiDefault() { - return new this(UInt64.from(0)) - } - - constructor(value: UInt64) { - this.value = value - } - - /** Return true if this slug is equal to the passed slug. */ - equals(other: ReservSlugName | UInt64 | string | number): boolean { - return this.value.equals(ReservSlugName.from(other).value) - } - - /** The canonical spelling — `""` for the zero sentinel. */ - toString(): string { - return SlugName.toString(this.value.toNumber()) - } - - toABI(encoder: ABIEncoder) { - this.value.toABI(encoder) - } - - /** @internal */ - toJSON() { - return this.toString() - } -} - -/** Runtime serializer for `sysio.reserv::matchreserve`. */ -@Struct.type("matchreserve") -export class ReservMatchReserve extends Struct { - /** Source outpost chain code. */ - @Struct.field(ReservSlugName) declare chain_code: ReservSlugName - - /** Source asset token code. */ - @Struct.field(ReservSlugName) declare token_code: ReservSlugName - - /** Reserve discriminator code. */ - @Struct.field(ReservSlugName) declare reserve_code: ReservSlugName - - /** AuthEx-linked Wire account funding the WIRE side. */ - @Struct.field("name") declare matcher: Name - - /** Exact WIRE base-unit amount requested by the pending reserve. */ - @Struct.field("uint64") declare wire_amount: UInt64 -} - -/** Runtime serializer for read-only `sysio.reserv::swapquote`. */ -@Struct.type("swapquote") -export class ReservSwapQuote extends Struct { - /** Source chain code. */ - @Struct.field(ReservSlugName) declare from_chain_code: ReservSlugName - - /** Source token code. */ - @Struct.field(ReservSlugName) declare from_token_code: ReservSlugName - - /** Source reserve code. */ - @Struct.field(ReservSlugName) declare from_reserve_code: ReservSlugName - - /** Source amount in source-token base units. */ - @Struct.field("uint64") declare from_amount: UInt64 - - /** Destination chain code. */ - @Struct.field(ReservSlugName) declare to_chain_code: ReservSlugName - - /** Destination token code. */ - @Struct.field(ReservSlugName) declare to_token_code: ReservSlugName - - /** Destination reserve code. */ - @Struct.field(ReservSlugName) declare to_reserve_code: ReservSlugName -} diff --git a/packages/sdk-core/src/contracts/sysio/reserv/Types.ts b/packages/sdk-core/src/contracts/sysio/reserv/Types.ts deleted file mode 100644 index f059d17e..00000000 --- a/packages/sdk-core/src/contracts/sysio/reserv/Types.ts +++ /dev/null @@ -1,141 +0,0 @@ -import type { APIClient } from "../../../api/Client.js" -import type { TransactionExtraOptions } from "../../../api/Types.js" -import type { UInt64Type } from "../../../chain/Integer.js" -import type { NameType } from "../../../chain/Name.js" -import type * as SysioContracts from "../../../types/SysioContractTypes.js" -import type { SlugNameValue } from "../../../SlugName.js" - -/** Every carrier a reserve `slug_name` may arrive in — see {@link SlugNameValue}. */ -export type ReserveSlugName = SlugNameValue - -/** Three-part identity that uniquely addresses one reserve. */ -export interface ReserveIdentity { - /** Source outpost chain code. */ - chainCode: ReserveSlugName - /** Source asset token code. */ - tokenCode: ReserveSlugName - /** Reserve discriminator code. */ - reserveCode: ReserveSlugName -} - -/** Configuration for `ReserveClient`. */ -export interface ReserveClientOptions { - /** Chain API client used for reads and optional signed pushes. */ - client: APIClient - /** Reserve contract account. Defaults to `sysio.reserv`. */ - contract?: NameType -} - -/** Options for listing and filtering reserve rows. */ -export interface ListReservesOptions { - /** Maximum matching rows returned after filtering. Defaults to 500. */ - limit?: number - /** Optional source outpost chain code. */ - chainCode?: ReserveSlugName - /** Optional source asset token code. */ - tokenCode?: ReserveSlugName - /** Optional lifecycle status. */ - status?: SysioContracts.SysioReservReservestatus - /** Optional Wire owner filter. */ - owner?: NameType - /** Optional public/private filter. */ - isPrivate?: boolean -} - -/** Options for building or pushing `sysio.reserv::matchreserve`. */ -export interface MatchReserveOptions extends ReserveIdentity { - /** AuthEx-linked Wire account funding and owning the reserve. */ - matcher: NameType - /** Exact requested WIRE amount in nine-decimal base units. */ - wireAmount: UInt64Type | bigint - /** Wire permission authorizing the action. Defaults to `active`. */ - permission?: NameType - /** Reserve contract account override. */ - contract?: NameType -} - -/** Options for pushing a signed reserve match transaction. */ -export interface PushMatchReserveOptions extends MatchReserveOptions { - /** Optional push behavior such as finality waiting. */ - pushOptions?: TransactionExtraOptions -} - -/** Options for atomically matching several pending reserves on Wire. */ -export interface PushMatchReservesOptions { - /** Ordered reserve matches included in one Wire transaction. */ - matches: readonly MatchReserveOptions[] - /** Optional push behavior such as finality waiting. */ - pushOptions?: TransactionExtraOptions -} - -/** Options for a read-only reserve-to-reserve quote. */ -export interface ReserveQuoteOptions { - /** Source reserve identity. */ - from: ReserveIdentity - /** Source amount in the reserve's depot precision frame. */ - fromAmount: UInt64Type | bigint - /** Destination reserve identity. */ - to: ReserveIdentity - /** Reserve contract account override. */ - contract?: NameType -} - -/** Normalized reserve row intended for application and service integrations. */ -export interface ReserveRecord { - /** Friendly source chain code. */ - chainCode: string - /** Packed source chain code. */ - chainCodeValue: number - /** Friendly source token code. */ - tokenCode: string - /** Packed source token code. */ - tokenCodeValue: number - /** Friendly reserve discriminator code. */ - reserveCode: string - /** Packed reserve discriminator code. */ - reserveCodeValue: number - /** User-facing reserve name. */ - name: string - /** User-facing reserve description. */ - description: string - /** Canonical reserve lifecycle status. */ - status: SysioContracts.SysioReservReservestatus - /** Current external-chain book amount in depot units. */ - chainAmount: bigint - /** Current WIRE book amount in WIRE base units. */ - wireAmount: bigint - /** External-token precision recorded by the outpost. */ - sourceTokenPrecision: number - /** WIRE-side connector weight in basis points. */ - connectorWeightBps: number - /** Creator's external chain kind. */ - creatorChainKind: SysioContracts.SysioReservChainkind - /** Creator's external address bytes as returned by the chain API. */ - creatorAddress: string - /** Exact WIRE amount required to activate a pending reserve. */ - requestedWireAmount: bigint - /** Original external amount recorded at creation. */ - externalTokenAmount: bigint - /** Depot registration timestamp in milliseconds. */ - registeredAtMs: bigint - /** Activation timestamp in milliseconds, or zero while inactive. */ - activatedAtMs: bigint - /** Cancellation timestamp in milliseconds, or zero while not cancelled. */ - cancelledAtMs: bigint - /** Whether swaps are restricted to same-owner private counterparts. */ - isPrivate: boolean - /** Wire account that matched the reserve, empty while pending. */ - owner: string - /** Creator public-key bytes recorded by the depot. */ - creatorPublicKey: string - /** Original generated row for integrations that need raw field names. */ - raw: SysioContracts.SysioReservReserveRowType -} - -/** Normalized reserve rewards bucket. */ -export interface ReserveRewards { - /** WIRE rewards awaiting distribution. */ - balance: bigint - /** Lifetime WIRE rewards routed to the bucket. */ - lifetimeAccrued: bigint -} diff --git a/packages/sdk-core/src/contracts/sysio/reserv/index.ts b/packages/sdk-core/src/contracts/sysio/reserv/index.ts deleted file mode 100644 index 7f9cb04d..00000000 --- a/packages/sdk-core/src/contracts/sysio/reserv/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from "./Actions.js" -export * from "./Client.js" -export * from "./Constants.js" -export * from "./Slug.js" -export * from "./Structs.js" -export * from "./Types.js" diff --git a/packages/sdk-core/src/contracts/sysio/tokens/Client.ts b/packages/sdk-core/src/contracts/sysio/tokens/Client.ts index df024a60..6fdac88f 100644 --- a/packages/sdk-core/src/contracts/sysio/tokens/Client.ts +++ b/packages/sdk-core/src/contracts/sysio/tokens/Client.ts @@ -5,7 +5,7 @@ import { } from "../../../types/SysioContractTypes.js" import type * as SysioContracts from "../../../types/SysioContractTypes.js" import { getSysioContract, type SysioContractClient } from "../Client.js" -import { reserveSlugString, reserveSlugValue } from "../reserv/Slug.js" +import { SlugName, slugValue } from "../../../SlugName.js" import { DEFAULT_TOKENS_CONTRACT, @@ -40,10 +40,10 @@ function enumValue>( export function normalizeTokenRow( row: SysioContracts.SysioTokensTokenRowType ): TokenRecord { - const codeValue = reserveSlugValue(row.code) + const codeValue = slugValue(row.code, "Token registry") return { - code: reserveSlugString(codeValue), + code: SlugName.toString(codeValue), codeValue, kind: enumValue(SysioTokensTokenkind, row.kind) as SysioTokensTokenkind, symbol: row.symbol_name, @@ -65,13 +65,13 @@ export function normalizeTokenRow( export function normalizeChainTokenRow( row: SysioContracts.SysioTokensChainTokenRowType ): ChainTokenRecord { - const chainCodeValue = reserveSlugValue(row.chain_code), - tokenCodeValue = reserveSlugValue(row.token_code) + const chainCodeValue = slugValue(row.chain_code, "Token registry"), + tokenCodeValue = slugValue(row.token_code, "Token registry") return { - chainCode: reserveSlugString(chainCodeValue), + chainCode: SlugName.toString(chainCodeValue), chainCodeValue, - tokenCode: reserveSlugString(tokenCodeValue), + tokenCode: SlugName.toString(tokenCodeValue), tokenCodeValue, contractAddress: row.contract_addr, isNative: row.is_native, @@ -119,9 +119,13 @@ export class TokenRegistryClient { ) }), chainCode = - options.chainCode == null ? null : reserveSlugValue(options.chainCode), + options.chainCode == null + ? null + : slugValue(options.chainCode, "Token registry"), tokenCode = - options.tokenCode == null ? null : reserveSlugValue(options.tokenCode) + options.tokenCode == null + ? null + : slugValue(options.tokenCode, "Token registry") return result.rows .map(normalizeChainTokenRow) diff --git a/packages/sdk-core/src/contracts/sysio/uwrit/Actions.ts b/packages/sdk-core/src/contracts/sysio/uwrit/Actions.ts deleted file mode 100644 index 03e087fd..00000000 --- a/packages/sdk-core/src/contracts/sysio/uwrit/Actions.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Name } from "../../../chain/Name.js" -import type * as SysioContracts from "../../../types/SysioContractTypes.js" -import { reserveSlugString } from "../reserv/Slug.js" - -import type { SwapFromWireOptions } from "./Types.js" - -/** Builds generated action data for `sysio.uwrit::swapfromwire`. */ -export function swapFromWireActionData( - options: SwapFromWireOptions -): SysioContracts.SysioUwritSwapfromwireAction { - return { - user: Name.from(options.user).toString(), - wire_amount: options.wireAmount.toString(), - dst_chain_code: reserveSlugString(options.destination.chainCode), - dst_token_code: reserveSlugString(options.destination.tokenCode), - dst_reserve_code: reserveSlugString(options.destination.reserveCode), - target_amount: options.targetAmount.toString(), - target_tolerance_bps: options.targetToleranceBps, - recipient_kind: options.recipientKind, - recipient_addr: options.recipientAddress - } -} diff --git a/packages/sdk-core/src/contracts/sysio/uwrit/Client.ts b/packages/sdk-core/src/contracts/sysio/uwrit/Client.ts deleted file mode 100644 index bbbb9733..00000000 --- a/packages/sdk-core/src/contracts/sysio/uwrit/Client.ts +++ /dev/null @@ -1,295 +0,0 @@ -import { Name } from "../../../chain/Name.js" -import { - SysioContractName, - SysioUwritAttestationtype, - SysioUwritChainkind, - SysioUwritUnderwriterequeststatus, - SysioUwritUnderwritestatus -} from "../../../types/SysioContractTypes.js" -import type * as SysioContracts from "../../../types/SysioContractTypes.js" -import { getSysioContract, type SysioContractClient } from "../Client.js" -import { reserveSlugString, reserveSlugValue } from "../reserv/Slug.js" - -import { swapFromWireActionData } from "./Actions.js" -import { - DEFAULT_UWRIT_CONTRACT, - DEFAULT_UWRIT_QUERY_LIMIT -} from "./Constants.js" -import type { - FromWireQueueRecord, - ListFromWireQueueOptions, - ListUnderwritingRequestsOptions, - SwapFromWireOptions, - UnderwritingClientOptions, - UnderwritingCommitRecord, - UnderwritingConfig, - UnderwritingRequestRecord -} from "./Types.js" - -/** - * The three slug fields that identify a reserve leg on a `uwreqs` row. Typed by - * indexed access off the generated row so a codegen change propagates here. - */ -interface ReserveIdentitySlugs { - chain: SysioContracts.SysioUwritUwRequestTType["src_chain_code"] - token: SysioContracts.SysioUwritUwRequestTType["src_token_code"] - reserve: SysioContracts.SysioUwritUwRequestTType["src_reserve_code"] -} - -function bigintValue(value: number | string): bigint { - return BigInt(value.toString()) -} - -function enumValue>( - enumType: T, - value: number | keyof T -): number { - if (typeof value === "number") return value - const mapped = enumType[value] - if (mapped == null) { - throw new Error(`Unknown underwriting enum value: ${String(value)}`) - } - return Number(mapped) -} - -function identity( - chain: ReserveIdentitySlugs["chain"], - token: ReserveIdentitySlugs["token"], - reserve: ReserveIdentitySlugs["reserve"] -) { - return { - chainCode: reserveSlugString(chain), - tokenCode: reserveSlugString(token), - reserveCode: reserveSlugString(reserve) - } -} - -function hexBytes(value: string): number[] { - const normalized = String(value || "") - .trim() - .replace(/^0x/i, "") - if ( - !normalized || - normalized.length % 2 !== 0 || - !/^[0-9a-f]+$/i.test(normalized) - ) { - return [] - } - const pairs = normalized.match(/.{2}/g) - return pairs ? pairs.map(pair => Number.parseInt(pair, 16)) : [] -} - -function sourceRequestId( - value: string, - wireOrigin: boolean -): bigint | undefined { - const bytes = hexBytes(value) - if (bytes.length !== 8) return undefined - const ordered = wireOrigin ? [...bytes].reverse() : bytes - return ordered.reduce((result, byte) => (result << 8n) | BigInt(byte), 0n) -} - -function wireDepositorAccount(value: string): string | undefined { - const bytes = hexBytes(value) - if (!bytes.length) return undefined - try { - return Name.from(String.fromCharCode(...bytes)).toString() - } catch { - return undefined - } -} - -function normalizeCommit( - row: SysioContracts.SysioUwritCommitEntryType -): UnderwritingCommitRecord { - return { - underwriter: row.underwriter, - sourceReceivedAtMs: bigintValue(row.source_received_at_ms), - destinationReceivedAtMs: bigintValue(row.dest_received_at_ms), - status: enumValue( - SysioUwritUnderwritestatus, - row.status - ) as SysioUwritUnderwritestatus, - reason: row.reason, - raw: row - } -} - -/** Normalizes a generated `sysio.uwrit::uwreqs` row. */ -export function normalizeUnderwritingRequest( - row: SysioContracts.SysioUwritUwRequestTType -): UnderwritingRequestRecord { - const source = identity( - row.src_chain_code, - row.src_token_code, - row.src_reserve_code - ), - wireOrigin = source.chainCode === "WIRE" - - return { - id: bigintValue(row.id), - type: enumValue( - SysioUwritAttestationtype, - row.type - ) as SysioUwritAttestationtype, - status: enumValue( - SysioUwritUnderwriterequeststatus, - row.status - ) as SysioUwritUnderwriterequeststatus, - source, - sourceAmount: bigintValue(row.src_amount), - destination: identity( - row.dst_chain_code, - row.dst_token_code, - row.dst_reserve_code - ), - destinationAmount: bigintValue(row.dst_amount), - toleranceBps: row.variance_tolerance_bps, - sourceTransactionId: row.source_tx_id, - sourceRequestId: sourceRequestId(row.source_tx_id, wireOrigin), - depositor: row.depositor, - depositorAccount: wireOrigin - ? wireDepositorAccount(row.depositor) - : undefined, - commits: row.commits_by.map(normalizeCommit), - winner: row.winner, - settledAtMs: bigintValue(row.settled_at_ms), - expiresAtEpoch: row.expires_at_epoch, - raw: row - } -} - -/** Normalizes a generated `sysio.uwrit::fwqueue` row. */ -export function normalizeFromWireQueue( - row: SysioContracts.SysioUwritFromwireQType -): FromWireQueueRecord { - return { - id: bigintValue(row.id), - user: row.user, - wireAmount: bigintValue(row.wire_amount), - destination: identity( - row.dst_chain_code, - row.dst_token_code, - row.dst_reserve_code - ), - targetAmount: bigintValue(row.target_amount), - toleranceBps: row.variance_tolerance_bps, - recipientKind: enumValue( - SysioUwritChainkind, - row.recipient_kind - ) as SysioUwritChainkind, - recipientAddress: row.recipient_addr, - createdAtEpoch: row.created_at_epoch, - raw: row - } -} - -/** UI-neutral client for swap underwriting reads and WIRE-origin submission. */ -export class UnderwritingClient { - /** Generic typed client for direct public action and table access. */ - readonly contractClient: SysioContractClient - - /** Creates an underwriting client. */ - constructor(config: UnderwritingClientOptions) { - this.contractClient = getSysioContract(SysioContractName.uwrit, { - client: config.client, - contract: config.contract || DEFAULT_UWRIT_CONTRACT - }) - } - - /** Lists normalized protocol swap requests. */ - async listRequests( - options: ListUnderwritingRequestsOptions = {} - ): Promise { - const result = await this.contractClient.tables.uwreqs.query({ - limit: Math.max( - Math.floor(options.limit || DEFAULT_UWRIT_QUERY_LIMIT), - 1 - ) - }), - sourceChain = - options.sourceChainCode == null - ? null - : reserveSlugValue(options.sourceChainCode), - destinationChain = - options.destinationChainCode == null - ? null - : reserveSlugValue(options.destinationChainCode) - - return result.rows - .map(normalizeUnderwritingRequest) - .filter( - record => - (options.status == null || record.status === options.status) && - (sourceChain == null || - reserveSlugValue(record.source.chainCode) === sourceChain) && - (destinationChain == null || - reserveSlugValue(record.destination.chainCode) === destinationChain) - ) - } - - /** Reads one protocol swap request, or null when absent. */ - async getRequest( - id: number | string | bigint - ): Promise { - const result = await this.contractClient.tables.uwreqs.query({ - lower_bound: id.toString(), - upper_bound: id.toString(), - limit: 1 - }), - row = result.rows[0] - return row ? normalizeUnderwritingRequest(row) : null - } - - /** Lists WIRE-origin swaps waiting for the next epoch drain. */ - async listFromWireQueue( - options: ListFromWireQueueOptions = {} - ): Promise { - const result = await this.contractClient.tables.fwqueue.query({ - limit: Math.max( - Math.floor(options.limit || DEFAULT_UWRIT_QUERY_LIMIT), - 1 - ) - }), - user = options.user ? Name.from(options.user).toString() : null - - return result.rows - .map(normalizeFromWireQueue) - .filter(record => !user || record.user === user) - } - - /** Reads the active underwriting configuration, or null before initialization. */ - async getConfig(): Promise { - const row = await this.contractClient.tables.uwconfig.first() - return row - ? { - feeBps: row.fee_bps, - collateralLockDurationMs: bigintValue( - row.collateral_lock_duration_ms - ), - minimumFromWireAmount: bigintValue(row.min_fromwire_amount), - fromWireRevertFeeBps: row.fromwire_revert_fee_bps - } - : null - } - - /** Escrows WIRE and queues a signed WIRE-to-external swap. */ - async pushSwapFromWire( - options: SwapFromWireOptions - ): Promise< - Awaited> - > { - return this.contractClient.actions.swapfromwire.invoke( - swapFromWireActionData(options), - { - authorization: [ - { - actor: options.user, - permission: options.permission || "active" - } - ], - pushOptions: options.pushOptions - } - ) - } -} diff --git a/packages/sdk-core/src/contracts/sysio/uwrit/Constants.ts b/packages/sdk-core/src/contracts/sysio/uwrit/Constants.ts deleted file mode 100644 index 7c45dff5..00000000 --- a/packages/sdk-core/src/contracts/sysio/uwrit/Constants.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** Default account hosting the underwriting coordinator. */ -export const DEFAULT_UWRIT_CONTRACT = "sysio.uwrit" - -/** Default maximum rows returned from underwriting tables. */ -export const DEFAULT_UWRIT_QUERY_LIMIT = 500 - -/** Canonical WIRE endpoint used by reserve quotes and underwriting requests. */ -export const WIRE_SWAP_ENDPOINT = Object.freeze({ - chainCode: "WIRE", - tokenCode: "WIRE", - reserveCode: "PRIMARY" -}) diff --git a/packages/sdk-core/src/contracts/sysio/uwrit/Types.ts b/packages/sdk-core/src/contracts/sysio/uwrit/Types.ts deleted file mode 100644 index 541437e6..00000000 --- a/packages/sdk-core/src/contracts/sysio/uwrit/Types.ts +++ /dev/null @@ -1,156 +0,0 @@ -import type { APIClient } from "../../../api/Client.js" -import type { TransactionExtraOptions } from "../../../api/Types.js" -import type { NameType } from "../../../chain/Name.js" -import type { - SysioUwritAttestationtype, - SysioUwritChainkind, - SysioUwritUnderwriterequeststatus, - SysioUwritUnderwritestatus -} from "../../../types/SysioContractTypes.js" -import type * as SysioContracts from "../../../types/SysioContractTypes.js" -import type { ReserveIdentity, ReserveSlugName } from "../reserv/Types.js" - -/** Configuration for `UnderwritingClient`. */ -export interface UnderwritingClientOptions { - /** Chain API client used for reads and signed pushes. */ - client: APIClient - /** Underwriting contract override. Defaults to `sysio.uwrit`. */ - contract?: NameType -} - -/** Filters for underwriting request history. */ -export interface ListUnderwritingRequestsOptions { - /** Optional lifecycle status. */ - status?: SysioUwritUnderwriterequeststatus - /** Optional source chain slug. */ - sourceChainCode?: ReserveSlugName - /** Optional destination chain slug. */ - destinationChainCode?: ReserveSlugName - /** Maximum rows returned. Defaults to 500. */ - limit?: number -} - -/** Filters for queued WIRE-origin swaps. */ -export interface ListFromWireQueueOptions { - /** Optional depositor account. */ - user?: NameType - /** Maximum rows returned. Defaults to 500. */ - limit?: number -} - -/** Input for `sysio.uwrit::swapfromwire`. */ -export interface SwapFromWireOptions { - /** Wire account escrowing WIRE into reserve custody. */ - user: NameType - /** WIRE input in nine-decimal base units. */ - wireAmount: number | string | bigint - /** Destination external reserve. */ - destination: ReserveIdentity - /** Current quoted destination amount in depot units. */ - targetAmount: number | string | bigint - /** Maximum accepted quote drift in basis points. */ - targetToleranceBps: number - /** Destination signing/address family. */ - recipientKind: SysioUwritChainkind | keyof typeof SysioUwritChainkind - /** Raw destination address bytes accepted by the deployed contract. */ - recipientAddress: string - /** Wire permission authorizing escrow. Defaults to `active`. */ - permission?: NameType - /** Optional push behavior such as waiting for finality. */ - pushOptions?: TransactionExtraOptions -} - -/** Normalized underwriter commitment for one swap leg. */ -export interface UnderwritingCommitRecord { - /** Underwriter account. */ - underwriter: string - /** Source outpost receipt time. */ - sourceReceivedAtMs: bigint - /** Destination outpost receipt time. */ - destinationReceivedAtMs: bigint - /** Current commitment lifecycle status. */ - status: SysioUwritUnderwritestatus - /** Protocol reason when disqualified or rejected. */ - reason: string - /** Original generated commitment. */ - raw: SysioContracts.SysioUwritCommitEntryType -} - -/** Normalized swap request coordinated by `sysio.uwrit`. */ -export interface UnderwritingRequestRecord { - /** Protocol request identifier. */ - id: bigint - /** Original cross-chain attestation type. */ - type: SysioUwritAttestationtype - /** Current request lifecycle status. */ - status: SysioUwritUnderwriterequeststatus - /** Source reserve identity. */ - source: ReserveIdentity - /** Source amount in depot units. */ - sourceAmount: bigint - /** Destination reserve identity. */ - destination: ReserveIdentity - /** Quoted destination amount in depot units. */ - destinationAmount: bigint - /** Accepted quote drift in basis points. */ - toleranceBps: number - /** Raw protocol source-request bytes returned by the chain API. */ - sourceTransactionId: string - /** - * Decoded outpost deposit id, or the synthetic WIRE queue/request id. - * - * This is the stable correlation value emitted by source-chain swap - * submission. It is not an EVM transaction hash or Solana signature. - */ - sourceRequestId?: bigint - /** Raw source-chain depositor address bytes returned by the chain API. */ - depositor: string - /** Decoded Wire depositor for WIRE-origin requests. */ - depositorAccount?: string - /** Underwriter commitments received for this request. */ - commits: UnderwritingCommitRecord[] - /** Winning underwriter account, empty while unresolved. */ - winner: string - /** Settlement timestamp in milliseconds. */ - settledAtMs: bigint - /** Epoch after which an unresolved request expires. */ - expiresAtEpoch: number - /** Original generated request row. */ - raw: SysioContracts.SysioUwritUwRequestTType -} - -/** Normalized WIRE-origin swap awaiting the next epoch drain. */ -export interface FromWireQueueRecord { - /** Queue identifier. */ - id: bigint - /** Wire depositor account. */ - user: string - /** Escrowed WIRE amount. */ - wireAmount: bigint - /** Destination external reserve. */ - destination: ReserveIdentity - /** Current quoted destination amount. */ - targetAmount: bigint - /** Accepted quote drift in basis points. */ - toleranceBps: number - /** Destination signing/address family. */ - recipientKind: SysioUwritChainkind - /** Raw destination recipient bytes. */ - recipientAddress: string - /** Epoch in which the queue entry was created. */ - createdAtEpoch: number - /** Original generated queue row. */ - raw: SysioContracts.SysioUwritFromwireQType -} - -/** Normalized underwriting configuration used for client preflight. */ -export interface UnderwritingConfig { - /** Protocol fee in basis points. */ - feeBps: number - /** Collateral lock duration in milliseconds. */ - collateralLockDurationMs: bigint - /** Minimum WIRE-origin input amount. */ - minimumFromWireAmount: bigint - /** Fee retained when a WIRE-origin swap reverts. */ - fromWireRevertFeeBps: number -} diff --git a/packages/sdk-core/src/contracts/sysio/uwrit/index.ts b/packages/sdk-core/src/contracts/sysio/uwrit/index.ts deleted file mode 100644 index a74dae1c..00000000 --- a/packages/sdk-core/src/contracts/sysio/uwrit/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./Actions.js" -export * from "./Client.js" -export * from "./Constants.js" -export * from "./Types.js" diff --git a/packages/sdk-core/src/types/SysioContractTypes.ts b/packages/sdk-core/src/types/SysioContractTypes.ts index d4525f9d..f407988d 100644 --- a/packages/sdk-core/src/types/SysioContractTypes.ts +++ b/packages/sdk-core/src/types/SysioContractTypes.ts @@ -78,12 +78,11 @@ export enum SysioAuthexChainkind { CHAIN_KIND_UNKNOWN = 0, CHAIN_KIND_WIRE = 1, CHAIN_KIND_EVM = 2, - CHAIN_KIND_SVM = 3, + CHAIN_KIND_SVM = 3 } /** sysio.authex::clearlinks (action) */ -export interface SysioAuthexClearlinksAction { -} +export interface SysioAuthexClearlinksAction {} /** sysio.authex::createlink (action) */ export interface SysioAuthexCreatelinkAction { @@ -350,7 +349,7 @@ export interface SysioBiosContract { /** sysio.bond::escrow_kind (enum, uint8) */ export enum SysioBondEscrowKind { BOUNTY = 0, - HOLD_BOND = 1, + HOLD_BOND = 1 } /** sysio.bond::request_state (enum, uint8) */ @@ -360,7 +359,7 @@ export enum SysioBondRequestState { APPROVED = 2, HELD = 3, VALID = 4, - INVALID = 5, + INVALID = 5 } /** sysio.bond::accept (action) */ @@ -370,6 +369,11 @@ export interface SysioBondAcceptAction { amount: number | string } +/** sysio.bond::ack (action) */ +export interface SysioBondAckAction { + request_id: number | string +} + /** sysio.bond::addbounty (action) */ export interface SysioBondAddbountyAction { request_id: number | string @@ -412,6 +416,11 @@ export interface SysioBondClaimAction { account: string } +/** sysio.bond::claimwire (action) */ +export interface SysioBondClaimwireAction { + account: string +} + /** sysio.bond::escrow_key (type) */ export interface SysioBondEscrowKeyType { request_id: number | string @@ -496,6 +505,18 @@ export interface SysioBondRequestRowType { resolved_at: string resolved_index: string forfeit_pending: number | string + outcome_acknowledged: boolean +} + +/** sysio.bond::requestkeep (action) */ +export interface SysioBondRequestkeepAction { + issuer: string + schema: string + statement: string + token_code: string + covered: number | string + bounty: number | string + window_sec: number } /** sysio.bond::rslvinvalid (action) */ @@ -518,6 +539,17 @@ export interface SysioBondSweepyieldAction { token_code: string } +/** sysio.bond::wire_claim (type) */ +export interface SysioBondWireClaimType { + account: string + amount: number | string +} + +/** sysio.bond::wire_key (type) */ +export interface SysioBondWireKeyType { + account: string +} + /** sysio.bond::yield_pool (type) */ export interface SysioBondYieldPoolType { received: number | string @@ -530,12 +562,15 @@ export interface SysioBondYieldPoolType { export interface SysioBondContract { actions: { accept: SysioBondAcceptAction + ack: SysioBondAckAction addbounty: SysioBondAddbountyAction approve: SysioBondApproveAction claim: SysioBondClaimAction + claimwire: SysioBondClaimwireAction hold: SysioBondHoldAction prune: SysioBondPruneAction request: SysioBondRequestAction + requestkeep: SysioBondRequestkeepAction rslvinvalid: SysioBondRslvinvalidAction rslvvalid: SysioBondRslvvalidAction setconfig: SysioBondSetconfigAction @@ -547,6 +582,7 @@ export interface SysioBondContract { bonds: SysioBondBondRowType escrows: SysioBondEscrowRowType requests: SysioBondRequestRowType + wireclaims: SysioBondWireClaimType yieldpool: SysioBondPoolRowType } } @@ -558,7 +594,7 @@ export enum SysioChainsChainkind { CHAIN_KIND_UNKNOWN = 0, CHAIN_KIND_WIRE = 1, CHAIN_KIND_EVM = 2, - CHAIN_KIND_SVM = 3, + CHAIN_KIND_SVM = 3 } /** sysio.chains::activchain (action) */ @@ -627,41 +663,7 @@ export interface SysioChainsContract { export enum SysioChalgDisputestatus { DISPUTE_STATUS_UNKNOWN = 0, DISPUTE_STATUS_OPEN = 1, - DISPUTE_STATUS_RESOLVED = 2, -} - -/** sysio.chalg::underwrite_fault_reason (enum, uint8) */ -export enum SysioChalgUnderwriteFaultReason { - SOURCE_DEPOSIT_MISSING = 0, - SOURCE_DEPOSIT_MISMATCH = 1, - NON_CANONICAL_ENVELOPE = 2, -} - -/** sysio.chalg::uwchal_ballot (enum, uint8) */ -export enum SysioChalgUwchalBallot { - UPHOLD = 0, - REJECT_REFUND = 1, - REJECT_FORFEIT = 2, -} - -/** sysio.chalg::uwchal_verdict (enum, uint8) */ -export enum SysioChalgUwchalVerdict { - NONE = 0, - UPHELD = 1, - REJECTED_REFUND = 2, - REJECTED_FORFEIT = 3, - LAPSED = 4, -} - -/** sysio.chalg::bond_credit (type) */ -export interface SysioChalgBondCreditType { - account: string - amount: number | string -} - -/** sysio.chalg::bond_credit_key (type) */ -export interface SysioChalgBondCreditKeyType { - account: number | string + DISPUTE_STATUS_RESOLVED = 2 } /** sysio.chalg::chalg_state (type) */ @@ -674,16 +676,6 @@ export interface SysioChalgChkdisputeAction { dispute_id: number | string } -/** sysio.chalg::chkuwchal (action) */ -export interface SysioChalgChkuwchalAction { - chal_id: number | string -} - -/** sysio.chalg::claimbond (action) */ -export interface SysioChalgClaimbondAction { - account: string -} - /** sysio.chalg::dispute_candidate (type) */ export interface SysioChalgDisputeCandidateType { checksum: string @@ -729,62 +721,12 @@ export interface SysioChalgOpendisputeAction { candidates: SysioChalgDisputeCandidateType[] } -/** sysio.chalg::openuwchal (action) */ -export interface SysioChalgOpenuwchalAction { - challenger: string - uwreq_id: number | string - underwriter: string - reason: number - detail: string -} - /** sysio.chalg::slashop (action) */ export interface SysioChalgSlashopAction { operator_acct: string reason: string } -/** sysio.chalg::uwchal_entry (type) */ -export interface SysioChalgUwchalEntryType { - id: number | string - uwreq_id: number | string - underwriter: string - challenger: string - reason: SysioChalgUnderwriteFaultReason | keyof typeof SysioChalgUnderwriteFaultReason - detail: string - status: SysioChalgDisputestatus | keyof typeof SysioChalgDisputestatus - verdict: SysioChalgUwchalVerdict | keyof typeof SysioChalgUwchalVerdict - bond_amount: number | string - deadline_ms: number | string - opened_at: string - network_gen: number - electorate: string[] - quorum: number -} - -/** sysio.chalg::uwchal_key (type) */ -export interface SysioChalgUwchalKeyType { - id: number | string -} - -/** sysio.chalg::uwchal_vote (type) */ -export interface SysioChalgUwchalVoteType { - owner: string - ballot: SysioChalgUwchalBallot | keyof typeof SysioChalgUwchalBallot - voted_at: string -} - -/** sysio.chalg::uwchal_vote_key (type) */ -export interface SysioChalgUwchalVoteKeyType { - owner: number | string -} - -/** sysio.chalg::uwchalbond (action) */ -export interface SysioChalgUwchalbondAction { - uwreq_id: number | string - underwriter: string -} - /** sysio.chalg::votedispute (action) */ export interface SysioChalgVotedisputeAction { owner: string @@ -792,33 +734,18 @@ export interface SysioChalgVotedisputeAction { chosen_checksum: string } -/** sysio.chalg::voteuwchal (action) */ -export interface SysioChalgVoteuwchalAction { - owner: string - chal_id: number | string - ballot: number -} - /** sysio.chalg - action + table surface for the typed contract client. */ export interface SysioChalgContract { actions: { chkdispute: SysioChalgChkdisputeAction - chkuwchal: SysioChalgChkuwchalAction - claimbond: SysioChalgClaimbondAction opendispute: SysioChalgOpendisputeAction - openuwchal: SysioChalgOpenuwchalAction slashop: SysioChalgSlashopAction - uwchalbond: SysioChalgUwchalbondAction votedispute: SysioChalgVotedisputeAction - voteuwchal: SysioChalgVoteuwchalAction } tables: { - bondcredits: SysioChalgBondCreditType chalgstate: SysioChalgChalgStateType disputes: SysioChalgDisputeEntryType disputevote: SysioChalgDisputeVoteType - uwchals: SysioChalgUwchalEntryType - uwchalvote: SysioChalgUwchalVoteType } } @@ -829,7 +756,7 @@ export enum SysioCounclCleanupMode { NONE = 0, INIT_ABORT = 1, ACTIVE_ABORT = 2, - COMPLETED = 3, + COMPLETED = 3 } /** sysio.councl::cleanup_stage (enum, uint8) */ @@ -840,7 +767,7 @@ export enum SysioCounclCleanupStage { TIER3 = 3, REMAP = 4, COUNCIL = 5, - COMPLETE = 6, + COMPLETE = 6 } /** sysio.councl::election_phase (enum, uint8) */ @@ -848,7 +775,7 @@ export enum SysioCounclElectionPhase { AWAIT_REP = 0, VOTING = 1, BACKSTOP = 2, - DONE = 3, + DONE = 3 } /** sysio.councl::election_tier (enum, uint8) */ @@ -856,7 +783,7 @@ export enum SysioCounclElectionTier { GOVERNANCE = 0, T1 = 1, T2 = 2, - T3 = 3, + T3 = 3 } /** sysio.councl::init_phase (enum, uint8) */ @@ -864,7 +791,7 @@ export enum SysioCounclInitPhase { REG = 0, LOADING = 1, READY = 2, - CLEANING = 3, + CLEANING = 3 } /** sysio.councl::addcandidate (action) */ @@ -943,8 +870,7 @@ export interface SysioCounclElectionStateType { } /** sysio.councl::finalizeinit (action) */ -export interface SysioCounclFinalizeinitAction { -} +export interface SysioCounclFinalizeinitAction {} /** sysio.councl::forceassign (action) */ export interface SysioCounclForceassignAction { @@ -952,8 +878,7 @@ export interface SysioCounclForceassignAction { } /** sysio.councl::forceback (action) */ -export interface SysioCounclForcebackAction { -} +export interface SysioCounclForcebackAction {} /** sysio.councl::index_key (type) */ export interface SysioCounclIndexKeyType { @@ -987,8 +912,7 @@ export interface SysioCounclRepcandidateAction { } /** sysio.councl::reset (action) */ -export interface SysioCounclResetAction { -} +export interface SysioCounclResetAction {} /** sysio.councl::rmcandidate (action) */ export interface SysioCounclRmcandidateAction { @@ -1074,7 +998,7 @@ export enum SysioDclaimChainkind { CHAIN_KIND_UNKNOWN = 0, CHAIN_KIND_WIRE = 1, CHAIN_KIND_EVM = 2, - CHAIN_KIND_SVM = 3, + CHAIN_KIND_SVM = 3 } /** sysio.dclaim::cap_config (type) */ @@ -1106,8 +1030,7 @@ export interface SysioDclaimImportCreditType { } /** sysio.dclaim::importdone (action) */ -export interface SysioDclaimImportdoneAction { -} +export interface SysioDclaimImportdoneAction {} /** sysio.dclaim::importseed (action) */ export interface SysioDclaimImportseedAction { @@ -1166,8 +1089,7 @@ export interface SysioDclaimSetclmwindowAction { } /** sysio.dclaim::setconfig (action) */ -export interface SysioDclaimSetconfigAction { -} +export interface SysioDclaimSetconfigAction {} /** sysio.dclaim::unmapped_key (type) */ export interface SysioDclaimUnmappedKeyType { @@ -1212,17 +1134,18 @@ export enum SysioEpochEmissionsblockreason { EMISSIONS_BLOCK_REASON_CONFIG_MISSING = 1, EMISSIONS_BLOCK_REASON_STATE_UNINITIALIZED = 2, EMISSIONS_BLOCK_REASON_TREASURY_EXHAUSTED = 3, - EMISSIONS_BLOCK_REASON_BALANCE_INSUFFICIENT = 4, + EMISSIONS_BLOCK_REASON_BALANCE_INSUFFICIENT = 4 } /** sysio.epoch::advance (action) */ -export interface SysioEpochAdvanceAction { -} +export interface SysioEpochAdvanceAction {} /** sysio.epoch::blocklog_entry (type) */ export interface SysioEpochBlocklogEntryType { epoch_index: number - reason: SysioEpochEmissionsblockreason | keyof typeof SysioEpochEmissionsblockreason + reason: + | SysioEpochEmissionsblockreason + | keyof typeof SysioEpochEmissionsblockreason attempted_emission: number | string treasury_remaining: number | string sysio_balance: number | string @@ -1257,12 +1180,10 @@ export interface SysioEpochEpochStateType { } /** sysio.epoch::pause (action) */ -export interface SysioEpochPauseAction { -} +export interface SysioEpochPauseAction {} /** sysio.epoch::schbatchgps (action) */ -export interface SysioEpochSchbatchgpsAction { -} +export interface SysioEpochSchbatchgpsAction {} /** sysio.epoch::setconfig (action) */ export interface SysioEpochSetconfigAction { @@ -1274,8 +1195,7 @@ export interface SysioEpochSetconfigAction { } /** sysio.epoch::unpause (action) */ -export interface SysioEpochUnpauseAction { -} +export interface SysioEpochUnpauseAction {} /** sysio.epoch - action + table surface for the typed contract client. */ export interface SysioEpochContract { @@ -1417,6 +1337,13 @@ export interface SysioLiqSetkickerAction { bps: number } +/** sysio.liq::settle (action) */ +export interface SysioLiqSettleAction { + custodian: string + beneficiary: string + quantity: string +} + /** sysio.liq::symbol_key (type) */ export interface SysioLiqSymbolKeyType { symbol_code: number | string @@ -1454,6 +1381,7 @@ export interface SysioLiqContract { recredit: SysioLiqRecreditAction regliqpool: SysioLiqRegliqpoolAction setkicker: SysioLiqSetkickerAction + settle: SysioLiqSettleAction transfer: SysioLiqTransferAction } tables: { @@ -1471,7 +1399,7 @@ export interface SysioLiqContract { export enum SysioMsgchAttestationstatus { ATTESTATION_STATUS_PENDING = 0, ATTESTATION_STATUS_READY = 1, - ATTESTATION_STATUS_PROCESSED = 2, + ATTESTATION_STATUS_PROCESSED = 2 } /** sysio.msgch::AttestationType (enum, int32) */ @@ -1505,7 +1433,7 @@ export enum SysioMsgchAttestationtype { ATTESTATION_TYPE_EMISSIONS_BLOCKED = 60962, ATTESTATION_TYPE_SYNDICATE_LIQ = 60963, ATTESTATION_TYPE_LIQ_YIELD = 60964, - ATTESTATION_TYPE_DESYNDICATE_LIQ = 60965, + ATTESTATION_TYPE_DESYNDICATE_LIQ = 60965 } /** sysio.msgch::ChainKind (enum, int32) */ @@ -1513,20 +1441,20 @@ export enum SysioMsgchChainkind { CHAIN_KIND_UNKNOWN = 0, CHAIN_KIND_WIRE = 1, CHAIN_KIND_EVM = 2, - CHAIN_KIND_SVM = 3, + CHAIN_KIND_SVM = 3 } /** sysio.msgch::EnvelopeStatus (enum, int32) */ export enum SysioMsgchEnvelopestatus { ENVELOPE_STATUS_PENDING_DELIVERY = 0, ENVELOPE_STATUS_DELIVERED = 1, - ENVELOPE_STATUS_CONFIRMED = 2, + ENVELOPE_STATUS_CONFIRMED = 2 } /** sysio.msgch::MessageDirection (enum, int32) */ export enum SysioMsgchMessagedirection { MESSAGE_DIRECTION_INBOUND = 0, - MESSAGE_DIRECTION_OUTBOUND = 1, + MESSAGE_DIRECTION_OUTBOUND = 1 } /** sysio.msgch::MessageStatus (enum, int32) */ @@ -1534,7 +1462,7 @@ export enum SysioMsgchMessagestatus { MESSAGE_STATUS_PENDING = 0, MESSAGE_STATUS_READY = 1, MESSAGE_STATUS_PROCESSED = 2, - MESSAGE_STATUS_CANCELLED = 3, + MESSAGE_STATUS_CANCELLED = 3 } /** sysio.msgch::ChainId (type) */ @@ -1574,8 +1502,7 @@ export interface SysioMsgchAttestationEntryType { } /** sysio.msgch::bootstrap (action) */ -export interface SysioMsgchBootstrapAction { -} +export interface SysioMsgchBootstrapAction {} /** sysio.msgch::buildenv (action) */ export interface SysioMsgchBuildenvAction { @@ -1583,8 +1510,7 @@ export interface SysioMsgchBuildenvAction { } /** sysio.msgch::chkcons (action) */ -export interface SysioMsgchChkconsAction { -} +export interface SysioMsgchChkconsAction {} /** sysio.msgch::deliver (action) */ export interface SysioMsgchDeliverAction { @@ -1632,7 +1558,9 @@ export interface SysioMsgchMessageEntryType { epoch_index: number message_id: string previous_message_id: string - direction: SysioMsgchMessagedirection | keyof typeof SysioMsgchMessagedirection + direction: + | SysioMsgchMessagedirection + | keyof typeof SysioMsgchMessagedirection status: SysioMsgchMessagestatus | keyof typeof SysioMsgchMessagestatus raw_payload: string received_at: string @@ -1668,7 +1596,9 @@ export interface SysioMsgchOutpostConsensusKeyType { /** sysio.msgch::queueout (action) */ export interface SysioMsgchQueueoutAction { chain_code: number | string - attest_type: SysioMsgchAttestationtype | keyof typeof SysioMsgchAttestationtype + attest_type: + | SysioMsgchAttestationtype + | keyof typeof SysioMsgchAttestationtype data: string } @@ -1891,7 +1821,7 @@ export enum SysioOpregActiontype { ACTION_TYPE_DEPOSIT_REQUEST = 1, ACTION_TYPE_WITHDRAW_REQUEST = 2, ACTION_TYPE_WITHDRAW_REMIT = 3, - ACTION_TYPE_SLASH = 4, + ACTION_TYPE_SLASH = 4 } /** sysio.opreg::ChainKind (enum, int32) */ @@ -1899,7 +1829,7 @@ export enum SysioOpregChainkind { CHAIN_KIND_UNKNOWN = 0, CHAIN_KIND_WIRE = 1, CHAIN_KIND_EVM = 2, - CHAIN_KIND_SVM = 3, + CHAIN_KIND_SVM = 3 } /** sysio.opreg::OperatorStatus (enum, int32) */ @@ -1909,7 +1839,7 @@ export enum SysioOpregOperatorstatus { OPERATOR_STATUS_COOLDOWN = 2, OPERATOR_STATUS_ACTIVE = 3, OPERATOR_STATUS_TERMINATED = 240, - OPERATOR_STATUS_SLASHED = 241, + OPERATOR_STATUS_SLASHED = 241 } /** sysio.opreg::OperatorType (enum, int32) */ @@ -1918,7 +1848,7 @@ export enum SysioOpregOperatortype { OPERATOR_TYPE_PRODUCER = 1, OPERATOR_TYPE_BATCH = 2, OPERATOR_TYPE_UNDERWRITER = 3, - OPERATOR_TYPE_CHALLENGER = 4, + OPERATOR_TYPE_CHALLENGER = 4 } /** sysio.opreg::ChainAddress (type) */ @@ -2017,17 +1947,6 @@ export interface SysioOpregDepositAction { amount: number | string } -/** sysio.opreg::depositinle (action) */ -export interface SysioOpregDepositinleAction { - account: string - chain_code: string - token_code: string - amount: number | string - actor_chain: SysioOpregChainkind | keyof typeof SysioOpregChainkind - actor_address: string - original_message_id: string -} - /** sysio.opreg::flushwtdw (action) */ export interface SysioOpregFlushwtdwAction { current_epoch: number @@ -2101,8 +2020,7 @@ export interface SysioOpregProcessuwAction { } /** sysio.opreg::prune (action) */ -export interface SysioOpregPruneAction { -} +export interface SysioOpregPruneAction {} /** sysio.opreg::recorddel (action) */ export interface SysioOpregRecorddelAction { @@ -2118,14 +2036,6 @@ export interface SysioOpregRegoperatorAction { is_bootstrapped: boolean } -/** sysio.opreg::releaselock (action) */ -export interface SysioOpregReleaselockAction { - account: string - chain_code: string - token_code: string - amount: number | string -} - /** sysio.opreg::remit_claim (type) */ export interface SysioOpregRemitClaimType { account: string @@ -2209,14 +2119,6 @@ export interface SysioOpregWithdrawRequestType { requested_at_epoch: number } -/** sysio.opreg::withdrawinle (action) */ -export interface SysioOpregWithdrawinleAction { - account: string - chain_code: string - token_code: string - amount: number | string -} - /** sysio.opreg::yield_pool (type) */ export interface SysioOpregYieldPoolType { received: number | string @@ -2238,7 +2140,6 @@ export interface SysioOpregContract { claimremit: SysioOpregClaimremitAction claimyield: SysioOpregClaimyieldAction deposit: SysioOpregDepositAction - depositinle: SysioOpregDepositinleAction flushwtdw: SysioOpregFlushwtdwAction processbatch: SysioOpregProcessbatchAction processprod: SysioOpregProcessprodAction @@ -2246,14 +2147,12 @@ export interface SysioOpregContract { prune: SysioOpregPruneAction recorddel: SysioOpregRecorddelAction regoperator: SysioOpregRegoperatorAction - releaselock: SysioOpregReleaselockAction setconfig: SysioOpregSetconfigAction slash: SysioOpregSlashAction sweepyield: SysioOpregSweepyieldAction termcheck: SysioOpregTermcheckAction terminate: SysioOpregTerminateAction withdraw: SysioOpregWithdrawAction - withdrawinle: SysioOpregWithdrawinleAction } tables: { dellog: SysioOpregDeliveryLogEntryType @@ -2266,298 +2165,6 @@ export interface SysioOpregContract { } } -// ── sysio.reserv ── - -/** sysio.reserv::ChainKind (enum, int32) */ -export enum SysioReservChainkind { - CHAIN_KIND_UNKNOWN = 0, - CHAIN_KIND_WIRE = 1, - CHAIN_KIND_EVM = 2, - CHAIN_KIND_SVM = 3, -} - -/** sysio.reserv::ReserveStatus (enum, int32) */ -export enum SysioReservReservestatus { - RESERVE_STATUS_UNKNOWN = 0, - RESERVE_STATUS_PENDING = 1, - RESERVE_STATUS_ACTIVE = 2, - RESERVE_STATUS_CANCELLED = 3, -} - -/** sysio.reserv::ChainAddress (type) */ -export interface SysioReservChainaddressType { - kind: SysioReservChainkind | keyof typeof SysioReservChainkind - address: string -} - -/** sysio.reserv::applyfromwire (action) */ -export interface SysioReservApplyfromwireAction { - dst_chain_code: string - dst_token_code: string - dst_reserve_code: string - wire_in: number | string - dst_amount: number | string - underwriter: string -} - -/** sysio.reserv::applyswap (action) */ -export interface SysioReservApplyswapAction { - src_chain_code: string - src_token_code: string - src_reserve_code: string - src_amount: number | string - dst_chain_code: string - dst_token_code: string - dst_reserve_code: string - dst_amount: number | string - underwriter: string -} - -/** sysio.reserv::claimrsvfee (action) */ -export interface SysioReservClaimrsvfeeAction { - chain_code: string - token_code: string - reserve_code: string -} - -/** sysio.reserv::claimuwfee (action) */ -export interface SysioReservClaimuwfeeAction { - underwriter: string -} - -/** sysio.reserv::claimwire (action) */ -export interface SysioReservClaimwireAction { - account: string -} - -/** sysio.reserv::debit (action) */ -export interface SysioReservDebitAction { - chain_code: string - token_code: string - reserve_code: string - amount: number | string -} - -/** sysio.reserv::drainrewards (action) */ -export interface SysioReservDrainrewardsAction { - amount: number | string -} - -/** sysio.reserv::matchreserve (action) */ -export interface SysioReservMatchreserveAction { - chain_code: string - token_code: string - reserve_code: string - matcher: string - wire_amount: number | string -} - -/** sysio.reserv::oncnclrsv (action) */ -export interface SysioReservOncnclrsvAction { - chain_code: string - token_code: string - reserve_code: string - creator_chain_kind: SysioReservChainkind | keyof typeof SysioReservChainkind - creator_chain_addr: string -} - -/** sysio.reserv::oncrtreserve (action) */ -export interface SysioReservOncrtreserveAction { - chain_code: string - token_code: string - reserve_code: string - name: string - description: string - external_token_amount: number | string - requested_wire_amount: number | string - source_token_precision: number - connector_weight_bps: number - creator_chain_kind: SysioReservChainkind | keyof typeof SysioReservChainkind - creator_chain_addr: string - is_private: boolean - creator_pub_key: string -} - -/** sysio.reserv::paywire (action) */ -export interface SysioReservPaywireAction { - src_chain_code: string - src_token_code: string - src_reserve_code: string - src_amount: number | string - recipient: string - wire_out: number | string - underwriter: string -} - -/** sysio.reserv::refundwire (action) */ -export interface SysioReservRefundwireAction { - recipient: string - wire_amount: number | string - revert_fee_bps: number -} - -/** sysio.reserv::regreserve (action) */ -export interface SysioReservRegreserveAction { - chain_code: string - token_code: string - reserve_code: string - name: string - description: string - initial_chain_amount: number | string - initial_wire_amount: number | string - source_token_precision: number - connector_weight_bps: number - is_private: boolean - owner: string -} - -/** sysio.reserv::reserve_config (type) */ -export interface SysioReservReserveConfigType { - fee_emissions_share_bps: number -} - -/** sysio.reserv::reserve_key (type) */ -export interface SysioReservReserveKeyType { - chain_code: string - token_code: string - reserve_code: string -} - -/** sysio.reserv::reserve_row (type) */ -export interface SysioReservReserveRowType { - chain_code: string - token_code: string - reserve_code: string - name: string - description: string - status: SysioReservReservestatus | keyof typeof SysioReservReservestatus - reserve_chain_amount: number | string - reserve_wire_amount: number | string - source_token_precision: number - connector_weight_bps: number - creator_addr: SysioReservChainaddressType - requested_wire_amount: number | string - external_token_amount: number | string - registered_at_ms: number | string - activated_at_ms: number | string - cancelled_at_ms: number | string - is_private: boolean - owner: string - creator_pub_key: string - owner_fee_bps: number - owner_fee_accrued: number | string - owner_fee_lifetime: number | string -} - -/** sysio.reserv::rewardbal (action) */ -export interface SysioReservRewardbalAction { -} - -/** sysio.reserv::rewards_bucket (type) */ -export interface SysioReservRewardsBucketType { - balance: number | string - lifetime_accrued: number | string -} - -/** sysio.reserv::rsvfeebal (action) */ -export interface SysioReservRsvfeebalAction { - chain_code: string - token_code: string - reserve_code: string -} - -/** sysio.reserv::setconfig (action) */ -export interface SysioReservSetconfigAction { - fee_emissions_share_bps: number -} - -/** sysio.reserv::setrsvfee (action) */ -export interface SysioReservSetrsvfeeAction { - chain_code: string - token_code: string - reserve_code: string - owner_fee_bps: number -} - -/** sysio.reserv::swapquote (action) */ -export interface SysioReservSwapquoteAction { - from_chain_code: string - from_token_code: string - from_reserve_code: string - from_amount: number | string - to_chain_code: string - to_token_code: string - to_reserve_code: string -} - -/** sysio.reserv::sweepclaims (action) */ -export interface SysioReservSweepclaimsAction { - max_rows: number -} - -/** sysio.reserv::uw_fee_key (type) */ -export interface SysioReservUwFeeKeyType { - underwriter: string -} - -/** sysio.reserv::uw_fee_row (type) */ -export interface SysioReservUwFeeRowType { - underwriter: string - balance: number | string - lifetime_accrued: number | string - lifetime_claimed: number | string -} - -/** sysio.reserv::uwfeebal (action) */ -export interface SysioReservUwfeebalAction { - underwriter: string -} - -/** sysio.reserv::wire_claim (type) */ -export interface SysioReservWireClaimType { - account: string - balance: number | string - expires_at_sec: number -} - -/** sysio.reserv::wireclaim_key (type) */ -export interface SysioReservWireclaimKeyType { - account: number | string -} - -/** sysio.reserv - action + table surface for the typed contract client. */ -export interface SysioReservContract { - actions: { - applyfromwire: SysioReservApplyfromwireAction - applyswap: SysioReservApplyswapAction - claimrsvfee: SysioReservClaimrsvfeeAction - claimuwfee: SysioReservClaimuwfeeAction - claimwire: SysioReservClaimwireAction - debit: SysioReservDebitAction - drainrewards: SysioReservDrainrewardsAction - matchreserve: SysioReservMatchreserveAction - oncnclrsv: SysioReservOncnclrsvAction - oncrtreserve: SysioReservOncrtreserveAction - paywire: SysioReservPaywireAction - refundwire: SysioReservRefundwireAction - regreserve: SysioReservRegreserveAction - rewardbal: SysioReservRewardbalAction - rsvfeebal: SysioReservRsvfeebalAction - setconfig: SysioReservSetconfigAction - setrsvfee: SysioReservSetrsvfeeAction - swapquote: SysioReservSwapquoteAction - sweepclaims: SysioReservSweepclaimsAction - uwfeebal: SysioReservUwfeebalAction - } - tables: { - reservcfg: SysioReservReserveConfigType - reserves: SysioReservReserveRowType - rewardbkt: SysioReservRewardsBucketType - uwfees: SysioReservUwFeeRowType - wireclaims: SysioReservWireClaimType - } -} - // ── sysio.roa ── /** sysio.roa::activateroa (action) */ @@ -3054,13 +2661,13 @@ export enum SysioSyndChainkind { CHAIN_KIND_UNKNOWN = 0, CHAIN_KIND_WIRE = 1, CHAIN_KIND_EVM = 2, - CHAIN_KIND_SVM = 3, + CHAIN_KIND_SVM = 3 } /** sysio.synd::bucket_direction (enum, uint8) */ export enum SysioSyndBucketDirection { SYNDICATION = 0, - DESYNDICATION = 1, + DESYNDICATION = 1 } /** sysio.synd::envelope_state (enum, uint8) */ @@ -3071,13 +2678,13 @@ export enum SysioSyndEnvelopeState { RELEASABLE = 3, HELD = 4, INVALID = 5, - DONE = 6, + DONE = 6 } /** sysio.synd::item_kind (enum, uint8) */ export enum SysioSyndItemKind { SYNDICATION = 0, - YIELD = 1, + YIELD = 1 } /** sysio.synd::request_outcome (enum, uint8) */ @@ -3085,7 +2692,7 @@ export enum SysioSyndRequestOutcome { PENDING = 0, APPROVED = 1, VALID = 2, - INVALID = 3, + INVALID = 3 } /** sysio.synd::bucket_key (type) */ @@ -3136,21 +2743,6 @@ export interface SysioSyndCursorKeyType { chain_code: number | string } -/** sysio.synd::desynd_key (type) */ -export interface SysioSyndDesyndKeyType { - request_id: number | string -} - -/** sysio.synd::desynd_row (type) */ -export interface SysioSyndDesyndRowType { - request_id: number | string - chain_code: string - token_code: string - amount: number | string - desyndicated_sum: number | string - total_syndicated: number | string -} - /** sysio.synd::desyndicate (action) */ export interface SysioSyndDesyndicateAction { holder: string @@ -3199,6 +2791,11 @@ export interface SysioSyndFeeRowType { position: SysioSyndPositionType } +/** sysio.synd::finishreturn (action) */ +export interface SysioSyndFinishreturnAction { + request_id: number | string +} + /** sysio.synd::import_credit (type) */ export interface SysioSyndImportCreditType { pubkey: string @@ -3206,8 +2803,7 @@ export interface SysioSyndImportCreditType { } /** sysio.synd::importdone (action) */ -export interface SysioSyndImportdoneAction { -} +export interface SysioSyndImportdoneAction {} /** sysio.synd::importsynd (action) */ export interface SysioSyndImportsyndAction { @@ -3248,10 +2844,9 @@ export interface SysioSyndLedgerKeyType { export interface SysioSyndLedgerRowType { chain_code: string token_code: string - syndicated_sum: number | string - yield_sum: number | string - desyndicated_sum: number | string queue_epoch: number + underwriting_epoch: number + retained_from_epoch: number | string } /** sysio.synd::linkswept (action) */ @@ -3264,7 +2859,7 @@ export interface SysioSyndLinksweptAction { /** sysio.synd::mismatch_key (type) */ export interface SysioSyndMismatchKeyType { chain_code: number | string - sequence: number | string + token_code: number | string } /** sysio.synd::mismatch_row (type) */ @@ -3332,6 +2927,41 @@ export interface SysioSyndPositionType { owed_wire: number | string } +/** sysio.synd::pruneenv (action) */ +export interface SysioSyndPruneenvAction { + chain_code: string + token_code: string + limit: number +} + +/** sysio.synd::reconcile (action) */ +export interface SysioSyndReconcileAction { + chain_code: string + token_code: string + reported: number | string +} + +/** sysio.synd::refundreturn (action) */ +export interface SysioSyndRefundreturnAction { + request_id: number | string +} + +/** sysio.synd::return_key (type) */ +export interface SysioSyndReturnKeyType { + request_id: number | string +} + +/** sysio.synd::return_row (type) */ +export interface SysioSyndReturnRowType { + request_id: number | string + holder: string + chain_code: string + token_code: string + chain_kind: SysioSyndChainkind | keyof typeof SysioSyndChainkind + pubkey: string + amount: number | string +} + /** sysio.synd::setconfig (action) */ export interface SysioSyndSetconfigAction { chain_code: string @@ -3358,6 +2988,18 @@ export interface SysioSyndSweepyieldAction { token_code: string } +/** sysio.synd::sync (action) */ +export interface SysioSyndSyncAction { + limit: number +} + +/** sysio.synd::syncenv (action) */ +export interface SysioSyndSyncenvAction { + chain_code: string + token_code: string + epoch_index: number +} + /** sysio.synd::synd_config (type) */ export interface SysioSyndSyndConfigType { chain_code: string @@ -3390,6 +3032,8 @@ export interface SysioSyndSyndCursorType { export interface SysioSyndSyndStateType { import_complete: boolean queue_cursor: number | string + underwriting_cursor: number | string + sync_cursor: SysioSyndEnvelopeKeyType } /** sysio.synd::token_key (type) */ @@ -3413,24 +3057,30 @@ export interface SysioSyndContract { crank: SysioSyndCrankAction desyndicate: SysioSyndDesyndicateAction dropenv: SysioSyndDropenvAction + finishreturn: SysioSyndFinishreturnAction importdone: SysioSyndImportdoneAction importsynd: SysioSyndImportsyndAction linkswept: SysioSyndLinksweptAction onsynd: SysioSyndOnsyndAction onyield: SysioSyndOnyieldAction + pruneenv: SysioSyndPruneenvAction + reconcile: SysioSyndReconcileAction + refundreturn: SysioSyndRefundreturnAction setconfig: SysioSyndSetconfigAction sweep: SysioSyndSweepAction sweepyield: SysioSyndSweepyieldAction + sync: SysioSyndSyncAction + syncenv: SysioSyndSyncenvAction } tables: { buckets: SysioSyndBucketRowType - desyndlog: SysioSyndDesyndRowType envelopes: SysioSyndEnvelopeRowType feepot: SysioSyndFeeRowType items: SysioSyndItemRowType ledger: SysioSyndLedgerRowType mismatch: SysioSyndMismatchRowType parked: SysioSyndParkedRowType + returns: SysioSyndReturnRowType syndconfig: SysioSyndSyndConfigType syndcounters: SysioSyndSyndCountersType syndcursors: SysioSyndSyndCursorType @@ -3445,7 +3095,7 @@ export interface SysioSyndContract { export enum SysioSystemTrxMatchType { only = 0, first = 1, - any = 2, + any = 2 } /** sysio.system::abi_hash (type) */ @@ -4095,12 +3745,10 @@ export interface SysioSystemUpdateauthAction { } /** sysio.system::viewemitcfg (action) */ -export interface SysioSystemViewemitcfgAction { -} +export interface SysioSystemViewemitcfgAction {} /** sysio.system::viewepoch (action) */ -export interface SysioSystemViewepochAction { -} +export interface SysioSystemViewepochAction {} /** sysio.system::viewnodedist (action) */ export interface SysioSystemViewnodedistAction { @@ -4139,8 +3787,7 @@ export interface SysioSystemDelpeerkeyAction { } /** sysio.system::getpeerkeys (action) */ -export interface SysioSystemGetpeerkeysAction { -} +export interface SysioSystemGetpeerkeysAction {} /** sysio.system::peer_key (type) */ export interface SysioSystemPeerKeyType { @@ -4375,7 +4022,7 @@ export enum SysioTokensChainkind { CHAIN_KIND_UNKNOWN = 0, CHAIN_KIND_WIRE = 1, CHAIN_KIND_EVM = 2, - CHAIN_KIND_SVM = 3, + CHAIN_KIND_SVM = 3 } /** sysio.tokens::TokenKind (enum, int32) */ @@ -4387,7 +4034,7 @@ export enum SysioTokensTokenkind { TOKEN_KIND_ERC1155 = 4, TOKEN_KIND_SPL = 5, TOKEN_KIND_SPL_NFT = 6, - TOKEN_KIND_LIQ = 7, + TOKEN_KIND_LIQ = 7 } /** sysio.tokens::ChainAddress (type) */ @@ -4474,292 +4121,6 @@ export interface SysioTokensContract { } } -// ── sysio.uwrit ── - -/** sysio.uwrit::AttestationType (enum, int32) */ -export enum SysioUwritAttestationtype { - ATTESTATION_TYPE_UNSPECIFIED = 0, - ATTESTATION_TYPE_OPERATOR_ACTION = 2001, - ATTESTATION_TYPE_STAKE = 3001, - ATTESTATION_TYPE_UNSTAKE = 3002, - ATTESTATION_TYPE_PRETOKEN_PURCHASE = 3004, - ATTESTATION_TYPE_PRETOKEN_YIELD = 3006, - ATTESTATION_TYPE_RESERVE_BALANCE_SHEET = 43520, - ATTESTATION_TYPE_STAKE_UPDATE = 60928, - ATTESTATION_TYPE_WIRE_TOKEN_PURCHASE = 60930, - ATTESTATION_TYPE_CHALLENGE_RESPONSE = 60932, - ATTESTATION_TYPE_SWAP_REQUEST = 60934, - ATTESTATION_TYPE_SWAP_REMIT = 60944, - ATTESTATION_TYPE_CHALLENGE_REQUEST = 60945, - ATTESTATION_TYPE_OPERATORS = 60947, - ATTESTATION_TYPE_BATCH_OPERATOR_GROUPS = 60943, - ATTESTATION_TYPE_NODE_OWNER_REG = 60949, - ATTESTATION_TYPE_STAKING_REWARD = 60950, - ATTESTATION_TYPE_STAKE_RESULT = 60951, - ATTESTATION_TYPE_ATTESTATION_PROCESSING_ERROR = 60952, - ATTESTATION_TYPE_UNDERWRITE_INTENT_COMMIT = 60953, - ATTESTATION_TYPE_SWAP_REVERT = 60955, - ATTESTATION_TYPE_DEPOSIT_REVERT = 60956, - ATTESTATION_TYPE_RESERVE_CREATE = 60958, - ATTESTATION_TYPE_RESERVE_CREATE_CANCEL = 60959, - ATTESTATION_TYPE_RESERVE_CREATE_CANCELLED = 60960, - ATTESTATION_TYPE_RESERVE_READY = 60961, - ATTESTATION_TYPE_EMISSIONS_BLOCKED = 60962, - ATTESTATION_TYPE_SYNDICATE_LIQ = 60963, - ATTESTATION_TYPE_LIQ_YIELD = 60964, - ATTESTATION_TYPE_DESYNDICATE_LIQ = 60965, -} - -/** sysio.uwrit::ChainKind (enum, int32) */ -export enum SysioUwritChainkind { - CHAIN_KIND_UNKNOWN = 0, - CHAIN_KIND_WIRE = 1, - CHAIN_KIND_EVM = 2, - CHAIN_KIND_SVM = 3, -} - -/** sysio.uwrit::UnderwriteRequestStatus (enum, int32) */ -export enum SysioUwritUnderwriterequeststatus { - UNDERWRITE_REQUEST_STATUS_PENDING = 0, - UNDERWRITE_REQUEST_STATUS_CONFIRMED = 1, - UNDERWRITE_REQUEST_STATUS_REJECTED = 2, - UNDERWRITE_REQUEST_STATUS_COMPLETED = 3, - UNDERWRITE_REQUEST_STATUS_EXPIRED = 4, -} - -/** sysio.uwrit::UnderwriteStatus (enum, int32) */ -export enum SysioUwritUnderwritestatus { - UNDERWRITE_STATUS_INTENT_CREATED = 0, - UNDERWRITE_STATUS_INTENT_SUBMITTED = 1, - UNDERWRITE_STATUS_INTENT_CONFIRMED = 2, - UNDERWRITE_STATUS_READY = 3, - UNDERWRITE_STATUS_RELEASED = 5, - UNDERWRITE_STATUS_SLASHED = 10, - UNDERWRITE_STATUS_DISQUALIFIED = 11, -} - -/** sysio.uwrit::chklocks (action) */ -export interface SysioUwritChklocksAction { - max_rows: number -} - -/** sysio.uwrit::commit_entry (type) */ -export interface SysioUwritCommitEntryType { - underwriter: string - source_received_at_ms: number | string - source_outpost_id: number | string - source_uic_bytes: string - dest_received_at_ms: number | string - dest_outpost_id: number | string - dest_uic_bytes: string - status: SysioUwritUnderwritestatus | keyof typeof SysioUwritUnderwritestatus - reason: string -} - -/** sysio.uwrit::createuwreq (action) */ -export interface SysioUwritCreateuwreqAction { - attestation_id: number | string - type: SysioUwritAttestationtype | keyof typeof SysioUwritAttestationtype - chain_code: number | string - data: string -} - -/** sysio.uwrit::drainfwq (action) */ -export interface SysioUwritDrainfwqAction { -} - -/** sysio.uwrit::freelocks (action) */ -export interface SysioUwritFreelocksAction { - uwreq_id: number | string - underwriter: string -} - -/** sysio.uwrit::fromwire_q (type) */ -export interface SysioUwritFromwireQType { - id: number | string - user: string - wire_amount: number | string - dst_chain_code: string - dst_token_code: string - dst_reserve_code: string - target_amount: number | string - variance_tolerance_bps: number - recipient_kind: SysioUwritChainkind | keyof typeof SysioUwritChainkind - recipient_addr: string - created_at_epoch: number -} - -/** sysio.uwrit::fw_key (type) */ -export interface SysioUwritFwKeyType { - id: number | string -} - -/** sysio.uwrit::holdlocks (action) */ -export interface SysioUwritHoldlocksAction { - uwreq_id: number | string - underwriter: string - chal_id: number | string -} - -/** sysio.uwrit::id_key (type) */ -export interface SysioUwritIdKeyType { - id: number | string -} - -/** sysio.uwrit::lock_entry (type) */ -export interface SysioUwritLockEntryType { - lock_id: number | string - uwreq_id: number | string - underwriter: string - chain_code: string - token_code: string - reserve_code: string - amount: number | string - created_at_ms: number | string - expires_at_ms: number | string - challenge_id: number | string -} - -/** sysio.uwrit::lock_key (type) */ -export interface SysioUwritLockKeyType { - lock_id: number | string -} - -/** sysio.uwrit::lock_sum (type) */ -export interface SysioUwritLockSumType { - underwriter: string - chain_code: string - token_code: string - amount: number | string -} - -/** sysio.uwrit::lock_sum_key (type) */ -export interface SysioUwritLockSumKeyType { - underwriter: string - chain_code: string - token_code: string -} - -/** sysio.uwrit::pruneuwreqs (action) */ -export interface SysioUwritPruneuwreqsAction { - max_rows: number -} - -/** sysio.uwrit::rcrdcommit (action) */ -export interface SysioUwritRcrdcommitAction { - uwreq_id: number | string - underwriter: string - chain_code: number | string - from_chain_code: string - from_token_code: string - reserve_code: string - uic_bytes: string -} - -/** sysio.uwrit::setconfig (action) */ -export interface SysioUwritSetconfigAction { - fee_bps: number - collateral_lock_duration_ms: number | string - min_fromwire_amount: number | string - fromwire_revert_fee_bps: number - uwreq_pending_timeout_epochs: number - uwreq_retention_epochs: number -} - -/** sysio.uwrit::sumlocks (action) */ -export interface SysioUwritSumlocksAction { - underwriter: string - chain_code: string - token_code: string -} - -/** sysio.uwrit::swapfromwire (action) */ -export interface SysioUwritSwapfromwireAction { - user: string - wire_amount: number | string - dst_chain_code: string - dst_token_code: string - dst_reserve_code: string - target_amount: number | string - target_tolerance_bps: number - recipient_kind: SysioUwritChainkind | keyof typeof SysioUwritChainkind - recipient_addr: string -} - -/** sysio.uwrit::sweeplocks (action) */ -export interface SysioUwritSweeplocksAction { - uwreq_id: number | string - underwriter: string -} - -/** sysio.uwrit::uw_config (type) */ -export interface SysioUwritUwConfigType { - fee_bps: number - collateral_lock_duration_ms: number | string - min_fromwire_amount: number | string - fromwire_revert_fee_bps: number - uwreq_pending_timeout_epochs: number - uwreq_retention_epochs: number -} - -/** sysio.uwrit::uw_counters (type) */ -export interface SysioUwritUwCountersType { - next_lock_id: number | string - next_fromwire_seq: number | string -} - -/** sysio.uwrit::uw_request_t (type) */ -export interface SysioUwritUwRequestTType { - id: number | string - type: SysioUwritAttestationtype | keyof typeof SysioUwritAttestationtype - status: SysioUwritUnderwriterequeststatus | keyof typeof SysioUwritUnderwriterequeststatus - src_chain_code: string - src_token_code: string - src_reserve_code: string - src_amount: number | string - dst_chain_code: string - dst_token_code: string - dst_reserve_code: string - dst_amount: number | string - target_amount: number | string - variance_tolerance_bps: number - source_tx_id: string - depositor: string - commits_by: SysioUwritCommitEntryType[] - winner: string - committed_at_ms: number | string - settled_at_ms: number | string - expires_at_epoch: number - attestation_inbound_data: string - attestation_outbound_data: string - challenge_id: number | string -} - -/** sysio.uwrit - action + table surface for the typed contract client. */ -export interface SysioUwritContract { - actions: { - chklocks: SysioUwritChklocksAction - createuwreq: SysioUwritCreateuwreqAction - drainfwq: SysioUwritDrainfwqAction - freelocks: SysioUwritFreelocksAction - holdlocks: SysioUwritHoldlocksAction - pruneuwreqs: SysioUwritPruneuwreqsAction - rcrdcommit: SysioUwritRcrdcommitAction - setconfig: SysioUwritSetconfigAction - sumlocks: SysioUwritSumlocksAction - swapfromwire: SysioUwritSwapfromwireAction - sweeplocks: SysioUwritSweeplocksAction - } - tables: { - fwqueue: SysioUwritFromwireQType - locks: SysioUwritLockEntryType - locksums: SysioUwritLockSumType - uwconfig: SysioUwritUwConfigType - uwcounters: SysioUwritUwCountersType - uwreqs: SysioUwritUwRequestTType - } -} - // ── sysio.wrap ── /** sysio.wrap::action (type) */ @@ -4810,8 +4171,7 @@ export interface SysioWrapContract { actions: { exec: SysioWrapExecAction } - tables: { - } + tables: {} } // ── contract registry ── @@ -4831,15 +4191,13 @@ export enum SysioContractName { msgch = "msgch", msig = "msig", opreg = "opreg", - reserv = "reserv", roa = "roa", swap = "swap", synd = "synd", system = "system", token = "token", tokens = "tokens", - uwrit = "uwrit", - wrap = "wrap", + wrap = "wrap" } /** On-chain account per contract (default sysio.; system/bios -> sysio). */ @@ -4857,15 +4215,13 @@ export const SysioContractAccount: Record = { [SysioContractName.msgch]: "sysio.msgch", [SysioContractName.msig]: "sysio.msig", [SysioContractName.opreg]: "sysio.opreg", - [SysioContractName.reserv]: "sysio.reserv", [SysioContractName.roa]: "sysio.roa", [SysioContractName.swap]: "sysio.swap", [SysioContractName.synd]: "sysio.synd", [SysioContractName.system]: "sysio", [SysioContractName.token]: "sysio.token", [SysioContractName.tokens]: "sysio.tokens", - [SysioContractName.uwrit]: "sysio.uwrit", - [SysioContractName.wrap]: "sysio.wrap", + [SysioContractName.wrap]: "sysio.wrap" } /** Each contract -> its action+table surface, for the typed contract client. */ @@ -4883,14 +4239,12 @@ export interface SysioContractMapping { [SysioContractName.msgch]: SysioMsgchContract [SysioContractName.msig]: SysioMsigContract [SysioContractName.opreg]: SysioOpregContract - [SysioContractName.reserv]: SysioReservContract [SysioContractName.roa]: SysioRoaContract [SysioContractName.swap]: SysioSwapContract [SysioContractName.synd]: SysioSyndContract [SysioContractName.system]: SysioSystemContract [SysioContractName.token]: SysioTokenContract [SysioContractName.tokens]: SysioTokensContract - [SysioContractName.uwrit]: SysioUwritContract [SysioContractName.wrap]: SysioWrapContract } @@ -4904,26 +4258,430 @@ export interface SysioContractDefinition { export const SysioContractDefinitions: { readonly [Name in SysioContractName]: SysioContractDefinition } = { - [SysioContractName.andon]: { name: SysioContractName.andon, account: "sysio.andon", actions: ["addpuller", "clear", "pull", "setpanic"], tables: ["andonconfig", "cord"] }, - [SysioContractName.authex]: { name: SysioContractName.authex, account: "sysio.authex", actions: ["clearlinks", "createlink", "recordlink"], tables: ["links"] }, - [SysioContractName.bios]: { name: SysioContractName.bios, account: "sysio", actions: ["activate", "deleteauth", "linkauth", "newaccount", "reqactivated", "reqauth", "setabi", "setalimits", "setcode", "setfinalizer", "setparams", "setpriv", "setprodkeys", "setprods", "unlinkauth", "updateauth"], tables: ["abihash"] }, - [SysioContractName.bond]: { name: SysioContractName.bond, account: "sysio.bond", actions: ["accept", "addbounty", "approve", "claim", "hold", "prune", "request", "rslvinvalid", "rslvvalid", "setconfig", "sweepyield"], tables: ["bondconfig", "bondcounters", "bonds", "escrows", "requests", "yieldpool"] }, - [SysioContractName.chains]: { name: SysioContractName.chains, account: "sysio.chains", actions: ["activchain", "regchain", "setoutpost"], tables: ["chains"] }, - [SysioContractName.chalg]: { name: SysioContractName.chalg, account: "sysio.chalg", actions: ["chkdispute", "chkuwchal", "claimbond", "opendispute", "openuwchal", "slashop", "uwchalbond", "votedispute", "voteuwchal"], tables: ["bondcredits", "chalgstate", "disputes", "disputevote", "uwchals", "uwchalvote"] }, - [SysioContractName.councl]: { name: SysioContractName.councl, account: "sysio.councl", actions: ["addcandidate", "finalizeinit", "forceassign", "forceback", "loadtier", "purge", "repcandidate", "reset", "rmcandidate", "settle", "startinit", "stir", "vote"], tables: ["candidates", "config", "council", "roster", "state", "tier2", "tier3", "tier3remap"] }, - [SysioContractName.dclaim]: { name: SysioContractName.dclaim, account: "sysio.dclaim", actions: ["claim", "flushexpired", "importdone", "importseed", "linkswept", "onreward", "setclmwindow", "setconfig"], tables: ["capcfg", "capcounters", "pclaims", "rwdcursors", "unmapped"] }, - [SysioContractName.epoch]: { name: SysioContractName.epoch, account: "sysio.epoch", actions: ["advance", "pause", "schbatchgps", "setconfig", "unpause"], tables: ["blocklog", "epochcfg", "epochstate"] }, - [SysioContractName.liq]: { name: SysioContractName.liq, account: "sysio.liq", actions: ["addkicker", "addyield", "burn", "claim", "close", "create", "creditowed", "mint", "mintyield", "open", "queueyield", "recredit", "regliqpool", "setkicker", "transfer"], tables: ["accounts", "liqconfig", "liqpending", "stat", "yieldidx"] }, - [SysioContractName.msgch]: { name: SysioContractName.msgch, account: "sysio.msgch", actions: ["bootstrap", "buildenv", "chkcons", "deliver", "evalcons", "queueout", "resolvedisp"], tables: ["attestations", "attseq", "envelopes", "envlog", "messages", "outenvelopes", "outpcons"] }, - [SysioContractName.msig]: { name: SysioContractName.msig, account: "sysio.msig", actions: ["approve", "cancel", "exec", "getproposal", "invalidate", "propose", "unapprove"], tables: ["approvals", "approvals2", "invals", "propchunks", "proposal"] }, - [SysioContractName.opreg]: { name: SysioContractName.opreg, account: "sysio.opreg", actions: ["available", "cancelwtdw", "claimremit", "claimyield", "deposit", "depositinle", "flushwtdw", "processbatch", "processprod", "processuw", "prune", "recorddel", "regoperator", "releaselock", "setconfig", "slash", "sweepyield", "termcheck", "terminate", "withdraw", "withdrawinle"], tables: ["dellog", "opconfig", "opcounters", "operators", "remitclaims", "wtdwqueue", "yieldpool"] }, - [SysioContractName.reserv]: { name: SysioContractName.reserv, account: "sysio.reserv", actions: ["applyfromwire", "applyswap", "claimrsvfee", "claimuwfee", "claimwire", "debit", "drainrewards", "matchreserve", "oncnclrsv", "oncrtreserve", "paywire", "refundwire", "regreserve", "rewardbal", "rsvfeebal", "setconfig", "setrsvfee", "swapquote", "sweepclaims", "uwfeebal"], tables: ["reservcfg", "reserves", "rewardbkt", "uwfees", "wireclaims"] }, - [SysioContractName.roa]: { name: SysioContractName.roa, account: "sysio.roa", actions: ["activateroa", "addpolicy", "expandpolicy", "extendpolicy", "forcereg", "giftram", "newnameduser", "newuser", "nodeownreg", "reducepolicy", "setbyteprice", "setsysabi", "setsyscode"], tables: ["nodeownerreg", "nodeowners", "policies", "reslimit", "roastate", "sponsorcount", "sponsors"] }, - [SysioContractName.swap]: { name: SysioContractName.swap, account: "sysio.swap", actions: ["accrueyield", "addliquidity", "cancelyield", "changefee", "close", "closeext", "exchange", "fundyield", "inittoken", "open", "openext", "remliquidity", "setconfig", "setyield", "sync", "tickyield", "transfer", "withdraw"], tables: ["accounts", "evodexacnts", "evoindex", "priceaccum", "reservoirs", "stat", "swapconfig", "yieldfunds", "yieldpayouts"] }, - [SysioContractName.synd]: { name: SysioContractName.synd, account: "sysio.synd", actions: ["challenge", "closeenv", "crank", "desyndicate", "dropenv", "importdone", "importsynd", "linkswept", "onsynd", "onyield", "setconfig", "sweep", "sweepyield"], tables: ["buckets", "desyndlog", "envelopes", "feepot", "items", "ledger", "mismatch", "parked", "syndconfig", "syndcounters", "syndcursors", "syndstate", "yieldpool"] }, - [SysioContractName.system]: { name: SysioContractName.system, account: "sysio", actions: ["accrueepoch", "actfinkey", "activate", "addnodeowner", "claimnodedis", "claimpay", "deleteauth", "delfinkey", "delsnapprov", "fundclaim", "getsnaphash", "init", "initt5", "limitauthchg", "linkauth", "newaccount", "onblock", "payepoch", "rcrdbatch", "regfinkey", "regproducer", "regproducer2", "regsnapprov", "rmvproducer", "setabi", "setacctcpu", "setacctnet", "setacctram", "setalimits", "setcode", "setemitcfg", "setinittime", "setparams", "setpriv", "setprodkeys", "setprods", "setram", "setscorecfg", "setsnpcfg", "unlinkauth", "unregprod", "updateauth", "viewemitcfg", "viewepoch", "viewnodedist", "votesnaphash", "wasmcfg", "delpeerkey", "getpeerkeys", "regpeerkey", "addtrxp", "deltrxp"], tables: ["abihash", "batchepochs", "blockinfo", "emissionmngr", "emitcfg", "epochlog", "finalizers", "finkeyidgen", "finkeys", "global", "lastpropfins", "nodecount", "nodedist", "payclaims", "payclaimtot", "prodsched", "prodscorecfg", "producers", "snapconfig", "snapprovs", "snaprecords", "snapvotes", "t5state", "limitauthchg", "peerkeys", "trxpglobal", "trxpriority"] }, - [SysioContractName.token]: { name: SysioContractName.token, account: "sysio.token", actions: ["close", "create", "issue", "open", "retire", "transfer"], tables: ["accounts", "stat"] }, - [SysioContractName.tokens]: { name: SysioContractName.tokens, account: "sysio.tokens", actions: ["activctok", "activtoken", "regctok", "regtoken"], tables: ["chaintokens", "tokens"] }, - [SysioContractName.uwrit]: { name: SysioContractName.uwrit, account: "sysio.uwrit", actions: ["chklocks", "createuwreq", "drainfwq", "freelocks", "holdlocks", "pruneuwreqs", "rcrdcommit", "setconfig", "sumlocks", "swapfromwire", "sweeplocks"], tables: ["fwqueue", "locks", "locksums", "uwconfig", "uwcounters", "uwreqs"] }, - [SysioContractName.wrap]: { name: SysioContractName.wrap, account: "sysio.wrap", actions: ["exec"], tables: [] }, + [SysioContractName.andon]: { + name: SysioContractName.andon, + account: "sysio.andon", + actions: ["addpuller", "clear", "pull", "setpanic"], + tables: ["andonconfig", "cord"] + }, + [SysioContractName.authex]: { + name: SysioContractName.authex, + account: "sysio.authex", + actions: ["clearlinks", "createlink", "recordlink"], + tables: ["links"] + }, + [SysioContractName.bios]: { + name: SysioContractName.bios, + account: "sysio", + actions: [ + "activate", + "deleteauth", + "linkauth", + "newaccount", + "reqactivated", + "reqauth", + "setabi", + "setalimits", + "setcode", + "setfinalizer", + "setparams", + "setpriv", + "setprodkeys", + "setprods", + "unlinkauth", + "updateauth" + ], + tables: ["abihash"] + }, + [SysioContractName.bond]: { + name: SysioContractName.bond, + account: "sysio.bond", + actions: [ + "accept", + "ack", + "addbounty", + "approve", + "claim", + "claimwire", + "hold", + "prune", + "request", + "requestkeep", + "rslvinvalid", + "rslvvalid", + "setconfig", + "sweepyield" + ], + tables: [ + "bondconfig", + "bondcounters", + "bonds", + "escrows", + "requests", + "wireclaims", + "yieldpool" + ] + }, + [SysioContractName.chains]: { + name: SysioContractName.chains, + account: "sysio.chains", + actions: ["activchain", "regchain", "setoutpost"], + tables: ["chains"] + }, + [SysioContractName.chalg]: { + name: SysioContractName.chalg, + account: "sysio.chalg", + actions: ["chkdispute", "opendispute", "slashop", "votedispute"], + tables: ["chalgstate", "disputes", "disputevote"] + }, + [SysioContractName.councl]: { + name: SysioContractName.councl, + account: "sysio.councl", + actions: [ + "addcandidate", + "finalizeinit", + "forceassign", + "forceback", + "loadtier", + "purge", + "repcandidate", + "reset", + "rmcandidate", + "settle", + "startinit", + "stir", + "vote" + ], + tables: [ + "candidates", + "config", + "council", + "roster", + "state", + "tier2", + "tier3", + "tier3remap" + ] + }, + [SysioContractName.dclaim]: { + name: SysioContractName.dclaim, + account: "sysio.dclaim", + actions: [ + "claim", + "flushexpired", + "importdone", + "importseed", + "linkswept", + "onreward", + "setclmwindow", + "setconfig" + ], + tables: ["capcfg", "capcounters", "pclaims", "rwdcursors", "unmapped"] + }, + [SysioContractName.epoch]: { + name: SysioContractName.epoch, + account: "sysio.epoch", + actions: ["advance", "pause", "schbatchgps", "setconfig", "unpause"], + tables: ["blocklog", "epochcfg", "epochstate"] + }, + [SysioContractName.liq]: { + name: SysioContractName.liq, + account: "sysio.liq", + actions: [ + "addkicker", + "addyield", + "burn", + "claim", + "close", + "create", + "creditowed", + "mint", + "mintyield", + "open", + "queueyield", + "recredit", + "regliqpool", + "setkicker", + "settle", + "transfer" + ], + tables: ["accounts", "liqconfig", "liqpending", "stat", "yieldidx"] + }, + [SysioContractName.msgch]: { + name: SysioContractName.msgch, + account: "sysio.msgch", + actions: [ + "bootstrap", + "buildenv", + "chkcons", + "deliver", + "evalcons", + "queueout", + "resolvedisp" + ], + tables: [ + "attestations", + "attseq", + "envelopes", + "envlog", + "messages", + "outenvelopes", + "outpcons" + ] + }, + [SysioContractName.msig]: { + name: SysioContractName.msig, + account: "sysio.msig", + actions: [ + "approve", + "cancel", + "exec", + "getproposal", + "invalidate", + "propose", + "unapprove" + ], + tables: ["approvals", "approvals2", "invals", "propchunks", "proposal"] + }, + [SysioContractName.opreg]: { + name: SysioContractName.opreg, + account: "sysio.opreg", + actions: [ + "available", + "cancelwtdw", + "claimremit", + "claimyield", + "deposit", + "flushwtdw", + "processbatch", + "processprod", + "processuw", + "prune", + "recorddel", + "regoperator", + "setconfig", + "slash", + "sweepyield", + "termcheck", + "terminate", + "withdraw" + ], + tables: [ + "dellog", + "opconfig", + "opcounters", + "operators", + "remitclaims", + "wtdwqueue", + "yieldpool" + ] + }, + [SysioContractName.roa]: { + name: SysioContractName.roa, + account: "sysio.roa", + actions: [ + "activateroa", + "addpolicy", + "expandpolicy", + "extendpolicy", + "forcereg", + "giftram", + "newnameduser", + "newuser", + "nodeownreg", + "reducepolicy", + "setbyteprice", + "setsysabi", + "setsyscode" + ], + tables: [ + "nodeownerreg", + "nodeowners", + "policies", + "reslimit", + "roastate", + "sponsorcount", + "sponsors" + ] + }, + [SysioContractName.swap]: { + name: SysioContractName.swap, + account: "sysio.swap", + actions: [ + "accrueyield", + "addliquidity", + "cancelyield", + "changefee", + "close", + "closeext", + "exchange", + "fundyield", + "inittoken", + "open", + "openext", + "remliquidity", + "setconfig", + "setyield", + "sync", + "tickyield", + "transfer", + "withdraw" + ], + tables: [ + "accounts", + "evodexacnts", + "evoindex", + "priceaccum", + "reservoirs", + "stat", + "swapconfig", + "yieldfunds", + "yieldpayouts" + ] + }, + [SysioContractName.synd]: { + name: SysioContractName.synd, + account: "sysio.synd", + actions: [ + "challenge", + "closeenv", + "crank", + "desyndicate", + "dropenv", + "finishreturn", + "importdone", + "importsynd", + "linkswept", + "onsynd", + "onyield", + "pruneenv", + "reconcile", + "refundreturn", + "setconfig", + "sweep", + "sweepyield", + "sync", + "syncenv" + ], + tables: [ + "buckets", + "envelopes", + "feepot", + "items", + "ledger", + "mismatch", + "parked", + "returns", + "syndconfig", + "syndcounters", + "syndcursors", + "syndstate", + "yieldpool" + ] + }, + [SysioContractName.system]: { + name: SysioContractName.system, + account: "sysio", + actions: [ + "accrueepoch", + "actfinkey", + "activate", + "addnodeowner", + "claimnodedis", + "claimpay", + "deleteauth", + "delfinkey", + "delsnapprov", + "fundclaim", + "getsnaphash", + "init", + "initt5", + "limitauthchg", + "linkauth", + "newaccount", + "onblock", + "payepoch", + "rcrdbatch", + "regfinkey", + "regproducer", + "regproducer2", + "regsnapprov", + "rmvproducer", + "setabi", + "setacctcpu", + "setacctnet", + "setacctram", + "setalimits", + "setcode", + "setemitcfg", + "setinittime", + "setparams", + "setpriv", + "setprodkeys", + "setprods", + "setram", + "setscorecfg", + "setsnpcfg", + "unlinkauth", + "unregprod", + "updateauth", + "viewemitcfg", + "viewepoch", + "viewnodedist", + "votesnaphash", + "wasmcfg", + "delpeerkey", + "getpeerkeys", + "regpeerkey", + "addtrxp", + "deltrxp" + ], + tables: [ + "abihash", + "batchepochs", + "blockinfo", + "emissionmngr", + "emitcfg", + "epochlog", + "finalizers", + "finkeyidgen", + "finkeys", + "global", + "lastpropfins", + "nodecount", + "nodedist", + "payclaims", + "payclaimtot", + "prodsched", + "prodscorecfg", + "producers", + "snapconfig", + "snapprovs", + "snaprecords", + "snapvotes", + "t5state", + "limitauthchg", + "peerkeys", + "trxpglobal", + "trxpriority" + ] + }, + [SysioContractName.token]: { + name: SysioContractName.token, + account: "sysio.token", + actions: ["close", "create", "issue", "open", "retire", "transfer"], + tables: ["accounts", "stat"] + }, + [SysioContractName.tokens]: { + name: SysioContractName.tokens, + account: "sysio.tokens", + actions: ["activctok", "activtoken", "regctok", "regtoken"], + tables: ["chaintokens", "tokens"] + }, + [SysioContractName.wrap]: { + name: SysioContractName.wrap, + account: "sysio.wrap", + actions: ["exec"], + tables: [] + } } diff --git a/packages/sdk-core/tests/contracts/sysio/reserv/Actions.test.ts b/packages/sdk-core/tests/contracts/sysio/reserv/Actions.test.ts deleted file mode 100644 index 8ccd896c..00000000 --- a/packages/sdk-core/tests/contracts/sysio/reserv/Actions.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { contracts } from "@wireio/sdk-core" - -const { ReservMatchReserve, buildMatchReserveAction } = contracts.sysio.reserv - -describe("reserve actions", () => { - test("builds a typed matchreserve action from friendly slugs", () => { - const action = buildMatchReserveAction({ - chainCode: "ETHEREUM", - tokenCode: "ETH", - reserveCode: "PRIMARY", - matcher: "alice", - wireAmount: 2500000000n - }), - decoded = action.decodeData(ReservMatchReserve) - - expect(action.account.toString()).toBe("sysio.reserv") - expect(action.name.toString()).toBe("matchreserve") - expect(action.authorization.map(String)).toEqual(["alice@active"]) - expect(decoded.matcher.toString()).toBe("alice") - expect(decoded.wire_amount.toString()).toBe("2500000000") - }) -}) diff --git a/packages/sdk-core/tests/contracts/sysio/reserv/Client.test.ts b/packages/sdk-core/tests/contracts/sysio/reserv/Client.test.ts deleted file mode 100644 index 365fc96f..00000000 --- a/packages/sdk-core/tests/contracts/sysio/reserv/Client.test.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { UInt64 } from "@wireio/sdk-core/chain/Integer" -import { Serializer } from "@wireio/sdk-core/serializer" -import { contracts } from "@wireio/sdk-core" -import { SysioReservReservestatus } from "@wireio/sdk-core/types/SysioContractTypes" - -const { ReserveClient } = contracts.sysio.reserv - -function reserveRow(overrides: Record = {}) { - return { - chain_code: "ETHEREUM", - token_code: "ETH", - reserve_code: "PRIMARY", - name: "Primary ETH", - description: "Public ETH liquidity", - status: "RESERVE_STATUS_PENDING", - reserve_chain_amount: "1000000000", - reserve_wire_amount: "0", - source_token_precision: 9, - connector_weight_bps: 5000, - creator_addr: { kind: "CHAIN_KIND_EVM", address: "0x1234" }, - requested_wire_amount: "2500000000", - external_token_amount: "1000000000", - registered_at_ms: "1720000000000", - activated_at_ms: "0", - cancelled_at_ms: "0", - is_private: false, - owner: "", - creator_pub_key: "02abcd", - ...overrides - } -} - -function clientFixture(rows = [reserveRow()]) { - const getTableRows = jest.fn(async (params: any) => ({ - rows: - String(params.table) === "rewardbkt" - ? [{ balance: "9", lifetime_accrued: "12" }] - : rows, - more: false - })), - pushTransaction = jest.fn(async (_action: any, _options?: any) => ({ - transaction_id: "reserve-trx" - })), - sendReadOnlyTransaction = jest.fn(async () => ({ - processed: { - action_traces: [ - { - act: { name: "swapquote" }, - return_value_hex_data: Serializer.encode({ - object: UInt64.from(42), - type: UInt64 - }).hexString - } - ] - } - })), - client = new ReserveClient({ - client: { - v1: { - chain: { - get_table_rows: getTableRows, - get_info: jest.fn(async () => ({ - getTransactionHeader: () => ({ - expiration: "2026-07-14T12:00:00", - ref_block_num: 1, - ref_block_prefix: 2 - }) - })), - send_read_only_transaction: sendReadOnlyTransaction - } - }, - pushTransaction - } as any - }) - - return { client, getTableRows, pushTransaction, sendReadOnlyTransaction } -} - -describe("ReserveClient", () => { - test("normalizes and filters reserve rows", async () => { - const { client, getTableRows } = clientFixture(), - reserves = await client.listReserves({ - chainCode: "ETHEREUM", - tokenCode: "ETH" - }) - - expect(reserves).toHaveLength(1) - expect(reserves[0]).toMatchObject({ - chainCode: "ETHEREUM", - tokenCode: "ETH", - reserveCode: "PRIMARY", - status: SysioReservReservestatus.RESERVE_STATUS_PENDING, - requestedWireAmount: 2500000000n - }) - expect(getTableRows).toHaveBeenCalledWith( - expect.objectContaining({ - code: "sysio.reserv", - table: "reserves", - scope: "sysio.reserv" - }) - ) - }) - - test("finds one reserve and returns null for a missing code", async () => { - const { client } = clientFixture() - - await expect( - client.getReserve({ - chainCode: "ETHEREUM", - tokenCode: "ETH", - reserveCode: "PRIMARY" - }) - ).resolves.toMatchObject({ name: "Primary ETH" }) - await expect( - client.getReserve({ - chainCode: "ETHEREUM", - tokenCode: "ETH", - reserveCode: "MISSING" - }) - ).resolves.toBeNull() - }) - - test("continues paginating until an exact reserve identity is found", async () => { - const { client, getTableRows } = clientFixture() - getTableRows.mockImplementation(async (params: any) => ({ - rows: [ - reserveRow({ - reserve_code: params.lower_bound ? "PRIMARY" : "OTHER" - }) - ], - more: !params.lower_bound, - next_key: params.lower_bound ? "" : "next-page" - })) - - await expect( - client.getReserve({ - chainCode: "ETHEREUM", - tokenCode: "ETH", - reserveCode: "PRIMARY" - }) - ).resolves.toMatchObject({ reserveCode: "PRIMARY" }) - expect(getTableRows).toHaveBeenCalledTimes(2) - }) - - test("builds and pushes the exact requested Wire amount", async () => { - const { client, pushTransaction } = clientFixture() - - await expect( - client.pushMatchReserve({ - chainCode: "ETHEREUM", - tokenCode: "ETH", - reserveCode: "PRIMARY", - matcher: "alice", - wireAmount: "2500000000" - }) - ).resolves.toEqual({ transaction_id: "reserve-trx" }) - expect(pushTransaction).toHaveBeenCalledTimes(1) - const [action] = pushTransaction.mock.calls[0] - expect(action.account.toString()).toBe("sysio.reserv") - expect(action.name.toString()).toBe("matchreserve") - expect(action.authorization.map(String)).toEqual(["alice@active"]) - }) - - test("pushes ordered reserve matches in one Wire transaction", async () => { - const { client, pushTransaction } = clientFixture() - - await expect( - client.pushMatchReserves({ - matches: [ - { - chainCode: "ETHEREUM", - tokenCode: "ETH", - reserveCode: "PRIVATE", - matcher: "alice", - wireAmount: "2500000000" - }, - { - chainCode: "SOLANA", - tokenCode: "USDC", - reserveCode: "PRIVATE", - matcher: "alice", - wireAmount: "2500000000" - } - ] - }) - ).resolves.toEqual({ transaction_id: "reserve-trx" }) - - const [actions] = pushTransaction.mock.calls[0] - expect(actions).toHaveLength(2) - expect(actions.map(action => action.name.toString())).toEqual([ - "matchreserve", - "matchreserve" - ]) - expect(actions.map(action => action.authorization.map(String))).toEqual([ - ["alice@active"], - ["alice@active"] - ]) - }) - - test("rejects an empty atomic reserve match", async () => { - const { client, pushTransaction } = clientFixture() - - await expect(client.pushMatchReserves({ matches: [] })).rejects.toThrow( - "At least one reserve match is required." - ) - expect(pushTransaction).not.toHaveBeenCalled() - }) - - test("decodes read-only swapquote and rewards values", async () => { - const { client } = clientFixture() - - await expect( - client.getSwapQuote({ - from: { - chainCode: "ETHEREUM", - tokenCode: "ETH", - reserveCode: "PRIMARY" - }, - fromAmount: 1n, - to: { chainCode: "SOLANA", tokenCode: "SOL", reserveCode: "PRIMARY" } - }) - ).resolves.toBe(42n) - await expect(client.getRewards()).resolves.toEqual({ - balance: 9n, - lifetimeAccrued: 12n - }) - }) -}) diff --git a/packages/sdk-core/tests/contracts/sysio/reserv/Slug.test.ts b/packages/sdk-core/tests/contracts/sysio/reserv/Slug.test.ts deleted file mode 100644 index 52472204..00000000 --- a/packages/sdk-core/tests/contracts/sysio/reserv/Slug.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { contracts, UInt64 } from "@wireio/sdk-core" - -const { ReservSlugName } = contracts.sysio.reserv - -describe("sysio.reserv slug struct", () => { - test("ReservSlugName renders its canonical spelling and refuses an unsafe value", () => { - expect(ReservSlugName.from("PRIMARY").toString()).toBe("PRIMARY") - expect(ReservSlugName.abiDefault().toString()).toBe("") - // Past 53 bits the packed value cannot be a canonical slug; converting it - // throws instead of silently rounding to a different code. - expect(() => ReservSlugName.from(UInt64.from("18446744073709551615")).toString()).toThrow() - }) -}) diff --git a/packages/sdk-core/tests/contracts/sysio/uwrit/Client.test.ts b/packages/sdk-core/tests/contracts/sysio/uwrit/Client.test.ts deleted file mode 100644 index 90f176c6..00000000 --- a/packages/sdk-core/tests/contracts/sysio/uwrit/Client.test.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { contracts } from "@wireio/sdk-core" -import { - SysioUwritChainkind, - SysioUwritUnderwriterequeststatus -} from "@wireio/sdk-core/types/SysioContractTypes" - -const { - UnderwritingClient, - WIRE_SWAP_ENDPOINT, - normalizeFromWireQueue, - normalizeUnderwritingRequest, - swapFromWireActionData -} = contracts.sysio.uwrit - -interface TableQuery { - table: string -} - -function requestRow(overrides: Record = {}) { - return { - id: "7", - type: "ATTESTATION_TYPE_SWAP_REQUEST", - status: "UNDERWRITE_REQUEST_STATUS_PENDING", - src_chain_code: "ETHEREUM", - src_token_code: "ETH", - src_reserve_code: "PRIMARY", - src_amount: "100", - dst_chain_code: "SOLANA", - dst_token_code: "SOL", - dst_reserve_code: "PRIMARY", - dst_amount: "90", - variance_tolerance_bps: 500, - source_tx_id: "000000000000002a", - depositor: "7412bc256355abd22d53de3a38e8995b5d4c1d1", - commits_by: [], - winner: "", - committed_at_ms: "0", - settled_at_ms: "0", - expires_at_epoch: 12, - attestation_inbound_data: "", - attestation_outbound_data: "", - ...overrides - } -} - -function queueRow(overrides: Record = {}) { - return { - id: "8", - user: "alice", - wire_amount: "5000000000", - dst_chain_code: "SOLANA", - dst_token_code: "SOL", - dst_reserve_code: "PRIMARY", - target_amount: "80", - variance_tolerance_bps: 500, - recipient_kind: "CHAIN_KIND_SVM", - recipient_addr: "1234", - created_at_epoch: 5, - ...overrides - } -} - -function fixture() { - const getTableRows = jest.fn(async ({ table }: TableQuery) => ({ - rows: - table === "uwreqs" - ? [requestRow()] - : table === "fwqueue" - ? [queueRow()] - : [ - { - fee_bps: 10, - collateral_lock_duration_ms: "60000", - min_fromwire_amount: "5000000000", - fromwire_revert_fee_bps: 25 - } - ], - more: false - })), - pushTransaction = jest.fn(async (_action: any, _options?: any) => ({ - transaction_id: "wire-swap" - })), - client = new UnderwritingClient({ - client: { - v1: { chain: { get_table_rows: getTableRows } }, - pushTransaction - } as any - }) - - return { client, getTableRows, pushTransaction } -} - -describe("UnderwritingClient", () => { - test("exposes the canonical WIRE sentinel and action data", () => { - expect(WIRE_SWAP_ENDPOINT).toEqual({ - chainCode: "WIRE", - tokenCode: "WIRE", - reserveCode: "PRIMARY" - }) - expect( - swapFromWireActionData({ - user: "alice", - wireAmount: 5n, - destination: { - chainCode: "SOLANA", - tokenCode: "SOL", - reserveCode: "PRIMARY" - }, - targetAmount: 4n, - targetToleranceBps: 500, - recipientKind: SysioUwritChainkind.CHAIN_KIND_SVM, - recipientAddress: "1234" - }) - ).toMatchObject({ user: "alice", wire_amount: "5", target_amount: "4" }) - }) - - test("normalizes request and WIRE queue rows", () => { - expect(normalizeUnderwritingRequest(requestRow() as any)).toMatchObject({ - id: 7n, - status: - SysioUwritUnderwriterequeststatus.UNDERWRITE_REQUEST_STATUS_PENDING, - source: { chainCode: "ETHEREUM", tokenCode: "ETH" }, - destination: { chainCode: "SOLANA", tokenCode: "SOL" }, - sourceRequestId: 42n, - depositor: "7412bc256355abd22d53de3a38e8995b5d4c1d1" - }) - expect(normalizeFromWireQueue(queueRow() as any)).toMatchObject({ - user: "alice", - wireAmount: 5000000000n, - recipientKind: SysioUwritChainkind.CHAIN_KIND_SVM - }) - }) - - test("decodes the synthetic WIRE request id and depositor account", () => { - const row = requestRow({ - src_chain_code: "WIRE", - src_token_code: "WIRE", - src_reserve_code: "WIRE", - source_tx_id: "0700000000000080", - depositor: "776972656e6f2e616263" - }) - - expect(normalizeUnderwritingRequest(row as any)).toMatchObject({ - sourceRequestId: 0x8000000000000007n, - depositorAccount: "wireno.abc" - }) - }) - - test("leaves malformed protocol correlation bytes undecoded", () => { - expect( - normalizeUnderwritingRequest( - requestRow({ source_tx_id: "not-hex", depositor: "not-hex" }) as any - ) - ).toMatchObject({ - sourceRequestId: undefined, - depositorAccount: undefined - }) - }) - - test("reads request, queue, and config state", async () => { - const { client } = fixture() - - await expect(client.getRequest(7)).resolves.toMatchObject({ id: 7n }) - await expect(client.listFromWireQueue({ user: "alice" })).resolves.toEqual([ - expect.objectContaining({ id: 8n }) - ]) - await expect(client.getConfig()).resolves.toEqual({ - feeBps: 10, - collateralLockDurationMs: 60000n, - minimumFromWireAmount: 5000000000n, - fromWireRevertFeeBps: 25 - }) - }) - - test("pushes a WIRE-origin swap with user authorization", async () => { - const { client, pushTransaction } = fixture() - - await client.pushSwapFromWire({ - user: "alice", - wireAmount: 5000000000n, - destination: { - chainCode: "SOLANA", - tokenCode: "SOL", - reserveCode: "PRIMARY" - }, - targetAmount: 80n, - targetToleranceBps: 500, - recipientKind: SysioUwritChainkind.CHAIN_KIND_SVM, - recipientAddress: "1234" - }) - - const [action] = pushTransaction.mock.calls[0] - expect(action.account.toString()).toBe("sysio.uwrit") - expect(action.name.toString()).toBe("swapfromwire") - expect(action.authorization.map(String)).toEqual(["alice@active"]) - }) -}) diff --git a/packages/sdk-outpost/README.md b/packages/sdk-outpost/README.md index e5f60762..8e40406a 100644 --- a/packages/sdk-outpost/README.md +++ b/packages/sdk-outpost/README.md @@ -39,8 +39,8 @@ after building those outputs; otherwise the exact registry versions remain in us | Family | Generated clients and workflows | | -------- | ------------------------------------------------------------------------- | -| Ethereum | `OPP`, `OPPInbound`, `OperatorRegistry`, `ReserveManager`, reserve lifecycle and swaps | -| Solana | `liqsol_core`, configured reserve lifecycle, native SOL and classic SPL reserve swaps | +| Ethereum | `OPP`, `OPPInbound`, `BAR`, node-owner registration | +| Solana | `liqsol_core`, OPP transport and LIQ custody | Client creation verifies all four boundaries before returning: @@ -59,7 +59,7 @@ discriminator preserves the precise `EthereumOutpostClient` or factory entrypoints or internal module paths. These checks prove deployment compatibility, not end-to-end feature readiness. -Applications must still gate swaps, staking, settlement, retry, funding, and +Applications must still gate staking, settlement, retry, funding, and underwriting using platform capability evidence. ## Deployment profiles @@ -143,34 +143,9 @@ const ethereum = await OutpostClient.create({ connection: new JsonRpcProvider(ethereumRpcUrl) } }) -const reserves = ethereum.contract(EthereumContractName.ReserveManager) +const inbound = ethereum.contract(EthereumContractName.OPPInbound) ``` -Wallet-connected clients expose verified reserve-swap workflows without a -separate deployment address book: - -```ts -const submission = await ethereum.swaps.requestNative({ - sourceTokenCode, - sourceReserveCode, - sourceAmount, - targetChainCode, - targetTokenCode, - targetReserveCode, - targetRecipient, - targetAmount, - targetToleranceBps -}) - -// Correlate this protocol id with sysio.uwrit; the transaction hash alone is -// only source-chain submission evidence. -console.log(submission.sourceRequestId) -``` - -Ethereum also exposes `requestErc20WithApproval`, `nativeBalance`, and -`erc20Balance`. Solana exposes `requestNative`, `requestSpl`, `nativeBalance`, -and `splBalance` through the same `client.swaps` ownership boundary. - ## Ethereum node owners The verified Ethereum client exposes `nodeOwners` for the external half of the @@ -198,84 +173,6 @@ must keep the action disabled unless deployment and capability evidence both advertise the complete node-owner flow, then follow the resulting Wire-side registration state separately. -## Reserve lifecycle - -Wallet-connected clients expose the external half of the post-bootstrap -reserve lifecycle. The external create escrows reserve capital and emits the -attestation that creates a pending `sysio.reserv` row. A signed -`@wireio/sdk-core` `ReserveClient` then supplies the exact requested WIRE amount -and activates that row. - -```ts -const ethereumSubmission = await ethereum.reserves.createNative({ - tokenCode, - reserveCode, - externalTokenAmount, - requestedWireAmount, - connectorWeightBps: 5_000, - name: "Private ETH reserve", - description: "", - isPrivate: true, - creatorPubKey -}) - -const configuredTokens = await solana.reserves.getConfiguredTokens() -const splToken = configuredTokens.find(token => !token.isNative) -if (splToken == null) throw new Error("No configured SPL reserve token.") - -const solanaSubmission = await solana.reserves.create({ - tokenCode: splToken.tokenCode, - reserveCode, - externalTokenAmount: splAmount, - requestedWireAmount, - connectorWeightBps: 5_000, - name: "Private SPL reserve", - description: "", - isPrivate: true, - mint: splToken.mint -}) -``` - -Ethereum supports native creation, ERC-20 approval or permit creation, pending -cancellation, and local reserve reads. Solana supports deployment-configured -token discovery, instruction assembly, creation, pending cancellation, address -derivation, and local reserve reads. `cancel` is valid only while creation is -pending and drives the protocol refund path. - -The all-zero mint returned for a configured native SOL route is protocol -metadata, not an Anchor account. The current `create_reserve` account context -still requires a real placeholder SPL mint and the creator's token account for -native SOL creation. Consumers that have not provisioned those accounts should -select a configured non-native SPL route, as in the example above. - -Private is a routing constraint, not access control or confidentiality. Private -reserves cannot use WIRE as a swap endpoint; when either external route leg is -private, Wire requires both active reserves to have the same non-empty owner. -The current protocol exposes no creator withdrawal, close, or redemption after -activation. This SDK intentionally does not invent an active-reserve exit API. - -Solana uses the same facade and returns the precise Anchor program type at the -runtime program address: - -```ts -import { - OutpostChainFamily, - OutpostClient, - SolanaProgramName -} from "@wireio/sdk-outpost" - -const solana = await OutpostClient.create({ - family: OutpostChainFamily.solana, - options: { profile, provider: anchorProvider } -}) -const liqsol = solana.program(SolanaProgramName.liqsolCore) -``` - -The producer-owned `LiqsolCore` type preserves the IDL's literal account namespace, -including `Program["account"]["outpostConfig"]` and -`Program["account"]["reserve"]`. Import it from -`@wireio/outpost-solana-artifacts`; never widen the IDL to the base `Idl` type. - ## Artifact ownership `@wireio/outpost-ethereum-artifacts` and `@wireio/outpost-solana-artifacts` are @@ -288,16 +185,11 @@ download handoffs or regenerate chain code. ## Consumer boundaries -- Use this package for typed external `ReserveManager`, `OperatorRegistry`, - `OPP`, `OPPInbound`, `liqsol_core`, reserve lifecycle, and source reserve-swap - execution. -- Use `@wireio/sdk-core` for Wire transaction construction, reserve and token - registries, underwriting state, and settlement correlation. +- Use this package for verified `OPP`, `OPPInbound`, `BAR` and `liqsol_core` clients. +- Use `@wireio/sdk-core` for WIRE transactions, token registration, collateral, + syndication and bond state. - Recreate external clients whenever the selected deployment profile changes. -- Combine SDK deployment verification with flow-specific capability gates before - enabling a product action. -- Ethereum reserve-swap submissions estimate the live call and add 25% gas - headroom for nested OPP execution; unused gas is not charged. +- Combine deployment verification with flow-specific capability checks. ## Maintainer commands diff --git a/packages/sdk-outpost/src/artifacts/Registry.ts b/packages/sdk-outpost/src/artifacts/Registry.ts index 2ce4feff..46ae42e0 100644 --- a/packages/sdk-outpost/src/artifacts/Registry.ts +++ b/packages/sdk-outpost/src/artifacts/Registry.ts @@ -2,9 +2,7 @@ import { BAR__factory, EthereumOutpostArtifactManifest, OPPInbound__factory, - OPP__factory, - OperatorRegistry__factory, - ReserveManager__factory + OPP__factory } from "@wireio/outpost-ethereum-artifacts" import { SolanaOutpostArtifactManifest, @@ -24,8 +22,6 @@ export interface EthereumOutpostArtifactFactories { readonly [EthereumContractName.BAR]: typeof BAR__factory readonly [EthereumContractName.OPP]: typeof OPP__factory readonly [EthereumContractName.OPPInbound]: typeof OPPInbound__factory - readonly [EthereumContractName.OperatorRegistry]: typeof OperatorRegistry__factory - readonly [EthereumContractName.ReserveManager]: typeof ReserveManager__factory } /** Generated Anchor IDLs keyed by deployment identity. */ @@ -74,9 +70,7 @@ export const CurrentOutpostArtifactSuite: OutpostArtifactSuite = { factories: { [EthereumContractName.BAR]: BAR__factory, [EthereumContractName.OPP]: OPP__factory, - [EthereumContractName.OPPInbound]: OPPInbound__factory, - [EthereumContractName.OperatorRegistry]: OperatorRegistry__factory, - [EthereumContractName.ReserveManager]: ReserveManager__factory + [EthereumContractName.OPPInbound]: OPPInbound__factory } }, solana: { diff --git a/packages/sdk-outpost/src/clients/ethereum/EthereumOutpostClient.ts b/packages/sdk-outpost/src/clients/ethereum/EthereumOutpostClient.ts index 418f4219..d1b153eb 100644 --- a/packages/sdk-outpost/src/clients/ethereum/EthereumOutpostClient.ts +++ b/packages/sdk-outpost/src/clients/ethereum/EthereumOutpostClient.ts @@ -12,8 +12,6 @@ import { import { OutpostDeploymentVerifier } from "../../verification/index.js" import { ethereumProvider } from "./Connection.js" import { EthereumContractMap, EthereumOutpostClientOptions } from "./Types.js" -import { EthereumReserveClient } from "./EthereumReserveClient.js" -import { EthereumReserveSwapClient } from "./EthereumReserveSwapClient.js" import { EthereumNodeOwnerClient } from "./EthereumNodeOwnerClient.js" /** Strictly typed access to one verified Ethereum outpost deployment. */ @@ -43,14 +41,6 @@ export class EthereumOutpostClient { readonly provider: Provider, private readonly artifactSuite: OutpostArtifactSuite ) { - this.reserves = new EthereumReserveClient( - this.contract(EthereumContractName.ReserveManager), - options.connection - ) - this.swaps = new EthereumReserveSwapClient( - this.contract(EthereumContractName.ReserveManager), - options.connection - ) if (options.profile.ethereum.contracts[EthereumContractName.BAR] != null) { this.nodeOwnerClient = new EthereumNodeOwnerClient( this.contract(EthereumContractName.BAR), @@ -59,12 +49,6 @@ export class EthereumOutpostClient { } } - /** Reserve creation, cancellation, and reads for this verified outpost. */ - readonly reserves: EthereumReserveClient - - /** Reserve-swap writes and balance reads for this verified outpost. */ - readonly swaps: EthereumReserveSwapClient - private readonly nodeOwnerClient?: EthereumNodeOwnerClient /** Node-owner slot reads, approvals, and BAR registration when deployed. */ @@ -111,20 +95,6 @@ export class EthereumOutpostClient { connection ) ) - .with(EthereumContractName.OperatorRegistry, () => - factories[EthereumContractName.OperatorRegistry].connect( - profile.ethereum.contracts[EthereumContractName.OperatorRegistry] - .address, - connection - ) - ) - .with(EthereumContractName.ReserveManager, () => - factories[EthereumContractName.ReserveManager].connect( - profile.ethereum.contracts[EthereumContractName.ReserveManager] - .address, - connection - ) - ) .exhaustive() return contract as EthereumContractMap[T] diff --git a/packages/sdk-outpost/src/clients/ethereum/EthereumReserveClient.ts b/packages/sdk-outpost/src/clients/ethereum/EthereumReserveClient.ts deleted file mode 100644 index 32622ee6..00000000 --- a/packages/sdk-outpost/src/clients/ethereum/EthereumReserveClient.ts +++ /dev/null @@ -1,223 +0,0 @@ -import type { - ReserveManager, - ReserveManagerLib -} from "@wireio/outpost-ethereum-artifacts" -import { - Contract, - getAddress, - getBigInt, - ZeroAddress, - type Provider, - type Signer -} from "ethers" -import { match } from "ts-pattern" - -import { - assertEthereumReserveCreateRequest, - assertReserveUnsigned64, - OutpostReserveStatus, - type EthereumReserveCreateRequest, - type EthereumReservePermitSignature, - type EthereumReserveRecord, - type OutpostReserveIdentity, - type OutpostReserveSubmission -} from "../../reserves/index.js" -import { assertEthereumSigner } from "./Connection.js" - -const ConfirmationCount = 1, - EthereumLocalReserveStatus = { - pending: 0n, - active: 1n, - cancelled: 2n - } as const, - Erc20Interface = [ - "function allowance(address owner,address spender) view returns (uint256)", - "function approve(address spender,uint256 amount) returns (bool)" - ] - -/** Reserve creation, cancellation, and reads for one verified Ethereum outpost. */ -export class EthereumReserveClient { - /** Bind reserve lifecycle operations to a generated ReserveManager client. */ - constructor( - private readonly reserveManager: ReserveManager, - private readonly connection: Provider | Signer - ) {} - - /** Create a pending native-token reserve. */ - async createNative( - request: EthereumReserveCreateRequest - ): Promise { - assertEthereumReserveCreateRequest(request) - this.assertSigner() - const parameters = this.nativeParameters(request), - overrides = { value: request.externalTokenAmount } - - await this.reserveManager.create_reserve.staticCall( - ...parameters, - overrides - ) - const transaction = await this.reserveManager.create_reserve( - ...parameters, - overrides - ) - await transaction.wait(ConfirmationCount) - return { transactionId: transaction.hash } - } - - /** Approve and create a pending ERC-20 reserve. */ - async createErc20WithApproval( - request: EthereumReserveCreateRequest, - tokenAddress?: string - ): Promise { - assertEthereumReserveCreateRequest(request) - const signer = this.assertSigner(), - owner = await signer.getAddress(), - configuredTokenAddress = await this.reserveManager.tokenAddressesByCode( - request.tokenCode - ) - - if (configuredTokenAddress === ZeroAddress) { - throw new Error( - `No ERC-20 address is configured for tokenCode ${request.tokenCode.toString()}.` - ) - } - if ( - tokenAddress != null && - getAddress(tokenAddress) !== getAddress(configuredTokenAddress) - ) { - throw new Error( - `ERC-20 address ${tokenAddress} does not match the configured route ${configuredTokenAddress}.` - ) - } - - const token = new Contract(configuredTokenAddress, Erc20Interface, signer), - reserveManagerAddress = await this.reserveManager.getAddress(), - allowance = getBigInt( - await token.allowance(owner, reserveManagerAddress) - ) - if (allowance < getBigInt(request.externalTokenAmount)) { - const approval = await token.approve( - reserveManagerAddress, - request.externalTokenAmount - ) - await approval.wait(ConfirmationCount) - } - - const arguments_ = this.createArguments(request) - await this.reserveManager.requestReserveCreateErc20WithApproval.staticCall( - arguments_ - ) - const transaction = - await this.reserveManager.requestReserveCreateErc20WithApproval( - arguments_ - ) - await transaction.wait(ConfirmationCount) - return { transactionId: transaction.hash } - } - - /** Create a pending ERC-20 reserve using an EIP-2612 permit. */ - async createErc20WithPermit( - request: EthereumReserveCreateRequest, - permitSignature: EthereumReservePermitSignature - ): Promise { - assertEthereumReserveCreateRequest(request) - this.assertSigner() - const arguments_ = this.createArguments(request) - - await this.reserveManager.requestReserveCreateErc20WithPermit.staticCall( - arguments_, - permitSignature - ) - const transaction = - await this.reserveManager.requestReserveCreateErc20WithPermit( - arguments_, - permitSignature - ) - await transaction.wait(ConfirmationCount) - return { transactionId: transaction.hash } - } - - /** Request cancellation and refund of a pending reserve. */ - async cancel( - identity: OutpostReserveIdentity - ): Promise { - this.assertSigner() - assertReserveUnsigned64(identity.tokenCode, "tokenCode") - assertReserveUnsigned64(identity.reserveCode, "reserveCode") - const transaction = await this.reserveManager.cancel_create_reserve( - identity.tokenCode, - identity.reserveCode - ) - await transaction.wait(ConfirmationCount) - return { transactionId: transaction.hash } - } - - /** Read and normalize one local ReserveManager record. */ - async get(identity: OutpostReserveIdentity): Promise { - assertReserveUnsigned64(identity.tokenCode, "tokenCode") - assertReserveUnsigned64(identity.reserveCode, "reserveCode") - const reserve = await this.reserveManager.getReserve( - identity.tokenCode, - identity.reserveCode - ) - return { - tokenCode: reserve.tokenCode, - reserveCode: reserve.reserveCode, - externalTokenAmount: reserve.externalTokenAmount, - requestedWireAmount: reserve.requestedWireAmount, - connectorWeightBps: Number(reserve.connectorWeightBps), - status: match(reserve.status) - .with( - EthereumLocalReserveStatus.pending, - () => OutpostReserveStatus.pending - ) - .with( - EthereumLocalReserveStatus.active, - () => OutpostReserveStatus.active - ) - .with( - EthereumLocalReserveStatus.cancelled, - () => OutpostReserveStatus.cancelled - ) - .otherwise(value => { - throw new Error(`Unsupported Ethereum reserve status ${value}.`) - }), - creator: reserve.creator, - exists: reserve.exists - } - } - - private assertSigner(): Signer { - return assertEthereumSigner(this.connection, "Ethereum reserve operation") - } - - private createArguments( - request: EthereumReserveCreateRequest - ): ReserveManagerLib.ReserveCreateArgsStruct { - return { - tokenCode: request.tokenCode, - reserveCode: request.reserveCode, - externalTokenAmount: request.externalTokenAmount, - requestedWireAmount: request.requestedWireAmount, - connectorWeightBps: request.connectorWeightBps, - name: request.name, - description: request.description, - isPrivate: request.isPrivate, - creatorPubKey: request.creatorPubKey - } - } - - private nativeParameters(request: EthereumReserveCreateRequest) { - return [ - request.tokenCode, - request.reserveCode, - request.externalTokenAmount, - request.requestedWireAmount, - request.connectorWeightBps, - request.name, - request.description, - request.isPrivate, - request.creatorPubKey - ] as const - } -} diff --git a/packages/sdk-outpost/src/clients/ethereum/EthereumReserveSwapClient.ts b/packages/sdk-outpost/src/clients/ethereum/EthereumReserveSwapClient.ts deleted file mode 100644 index a7124764..00000000 --- a/packages/sdk-outpost/src/clients/ethereum/EthereumReserveSwapClient.ts +++ /dev/null @@ -1,201 +0,0 @@ -import type { - ReserveManager, - ReserveManagerLib -} from "@wireio/outpost-ethereum-artifacts" -import { - Contract, - getBigInt, - type BigNumberish, - type EventLog, - type Log, - type Provider, - type Signer -} from "ethers" - -import { - assertReserveSwapRequest, - type ReserveSwapRequest, - type ReserveSwapSubmission -} from "../../reserves/index.js" -import { assertEthereumSigner, ethereumProvider } from "./Connection.js" - -const BasisPointDenominator = 10_000, - ConfirmationCount = 1, - Erc20Interface = [ - "function allowance(address owner,address spender) view returns (uint256)", - "function approve(address spender,uint256 amount) returns (bool)", - "function balanceOf(address owner) view returns (uint256)" - ], - SubmissionGasHeadroomBps = 2_500 - -/** Reserve-swap writes and balance reads for one verified Ethereum outpost. */ -export class EthereumReserveSwapClient { - /** Create an Ethereum reserve-swap workflow bound to a verified deployment. */ - constructor( - private readonly reserveManager: ReserveManager, - private readonly connection: Provider | Signer - ) {} - - /** Escrow native ETH and return the confirmed protocol deposit id. */ - async requestNative( - request: ReserveSwapRequest - ): Promise { - assertReserveSwapRequest(request) - this.assertSigner() - const parameters = this.nativeParameters(request), - overrides = { value: request.sourceAmount } - - await this.reserveManager.requestSwap.staticCall(...parameters, overrides) - const estimatedGas = await this.reserveManager.requestSwap.estimateGas( - ...parameters, - overrides - ), - submissionOverrides = { - ...overrides, - gasLimit: - EthereumReserveSwapClient.addSubmissionGasHeadroom(estimatedGas) - } - - const transaction = await this.reserveManager.requestSwap( - ...parameters, - submissionOverrides - ), - receipt = await transaction.wait(ConfirmationCount) - return { - transactionId: transaction.hash, - sourceRequestId: EthereumReserveSwapClient.parseSourceRequestId( - receipt?.logs - ) - } - } - - /** Approve and escrow an ERC-20 source amount, then return its deposit id. */ - async requestErc20WithApproval( - request: ReserveSwapRequest, - tokenAddress: string - ): Promise { - assertReserveSwapRequest(request) - const signer = this.assertSigner(), - owner = await signer.getAddress(), - token = new Contract(tokenAddress, Erc20Interface, signer), - reserveManagerAddress = await this.reserveManager.getAddress(), - allowance = await token.allowance(owner, reserveManagerAddress) - - await EthereumReserveSwapClient.approvalAmounts( - allowance, - request.sourceAmount - ).reduce>(async (previousApproval, amount) => { - await previousApproval - const approval = await token.approve(reserveManagerAddress, amount) - await approval.wait(ConfirmationCount) - }, Promise.resolve()) - - const arguments_ = this.swapArguments(request) - await this.reserveManager.requestSwapErc20WithApproval.staticCall( - arguments_ - ) - const estimatedGas = - await this.reserveManager.requestSwapErc20WithApproval.estimateGas( - arguments_ - ), - overrides = { - gasLimit: - EthereumReserveSwapClient.addSubmissionGasHeadroom(estimatedGas) - } - const transaction = await this.reserveManager.requestSwapErc20WithApproval( - arguments_, - overrides - ), - receipt = await transaction.wait(ConfirmationCount) - return { - transactionId: transaction.hash, - sourceRequestId: EthereumReserveSwapClient.parseSourceRequestId( - receipt?.logs - ) - } - } - - /** Read the native balance of an Ethereum account. */ - async nativeBalance(address: string): Promise { - return ethereumProvider(this.connection).getBalance(address) - } - - /** Read the ERC-20 balance of an Ethereum account. */ - async erc20Balance(tokenAddress: string, address: string): Promise { - const token = new Contract(tokenAddress, Erc20Interface, this.connection) - return getBigInt(await token.balanceOf(address)) - } - - private assertSigner(): Signer { - return assertEthereumSigner(this.connection, "Ethereum reserve swap") - } - - private nativeParameters(request: ReserveSwapRequest) { - return [ - request.sourceTokenCode, - request.sourceReserveCode, - request.targetChainCode, - request.targetTokenCode, - request.targetReserveCode, - request.targetRecipient, - request.targetAmount, - request.targetToleranceBps - ] as const - } - - private swapArguments( - request: ReserveSwapRequest - ): ReserveManagerLib.SwapArgsStruct { - return { - sourceTokenCode: request.sourceTokenCode, - sourceReserveCode: request.sourceReserveCode, - sourceAmount: request.sourceAmount, - targetChainCode: request.targetChainCode, - targetTokenCode: request.targetTokenCode, - targetReserveCode: request.targetReserveCode, - targetRecipient: request.targetRecipient, - targetAmount: request.targetAmount, - targetToleranceBps: request.targetToleranceBps - } - } - - /** Add bounded headroom to estimates that traverse OPP delegate calls. */ - static addSubmissionGasHeadroom(estimatedGas: BigNumberish): bigint { - const gas = getBigInt(estimatedGas), - denominator = BigInt(BasisPointDenominator) - return ( - (gas * BigInt(BasisPointDenominator + SubmissionGasHeadroomBps) + - denominator - - 1n) / - denominator - ) - } - - /** Return the safe approval sequence for zero-first ERC-20 implementations. */ - static approvalAmounts( - currentAllowance: BigNumberish, - requiredAllowance: BigNumberish - ): readonly bigint[] { - const current = getBigInt(currentAllowance), - required = getBigInt(requiredAllowance) - if (current >= required) return [] - return current === 0n ? [required] : [0n, required] - } - - /** Parse the canonical deposit id emitted by `requestSwap*`. */ - static parseSourceRequestId( - events: readonly (EventLog | Log)[] | undefined - ): bigint { - const event = events?.find( - candidate => - "eventName" in candidate && candidate.eventName === "SwapDeposit" - ), - id = event != null && "args" in event ? event.args[0] : null - if (id == null) { - throw new Error( - "Confirmed Ethereum reserve swap did not emit SwapDeposit." - ) - } - return BigInt(id.toString()) - } -} diff --git a/packages/sdk-outpost/src/clients/ethereum/Types.ts b/packages/sdk-outpost/src/clients/ethereum/Types.ts index 001d764c..214f8453 100644 --- a/packages/sdk-outpost/src/clients/ethereum/Types.ts +++ b/packages/sdk-outpost/src/clients/ethereum/Types.ts @@ -1,10 +1,4 @@ -import type { - BAR, - OPP, - OPPInbound, - OperatorRegistry, - ReserveManager -} from "@wireio/outpost-ethereum-artifacts" +import type { BAR, OPP, OPPInbound } from "@wireio/outpost-ethereum-artifacts" import type { Provider, Signer } from "ethers" import type { OutpostDeploymentProfile } from "../../deployments/index.js" @@ -26,8 +20,4 @@ export interface EthereumContractMap { [EthereumContractName.OPP]: OPP /** Inbound OPP endpoint. */ [EthereumContractName.OPPInbound]: OPPInbound - /** Operator collateral registry. */ - [EthereumContractName.OperatorRegistry]: OperatorRegistry - /** Reserve custody manager. */ - [EthereumContractName.ReserveManager]: ReserveManager } diff --git a/packages/sdk-outpost/src/clients/ethereum/index.ts b/packages/sdk-outpost/src/clients/ethereum/index.ts index 7f8f194b..12b0c269 100644 --- a/packages/sdk-outpost/src/clients/ethereum/index.ts +++ b/packages/sdk-outpost/src/clients/ethereum/index.ts @@ -1,4 +1,2 @@ -export * from "./EthereumReserveSwapClient.js" -export * from "./EthereumReserveClient.js" export * from "./EthereumNodeOwnerClient.js" export * from "./Types.js" diff --git a/packages/sdk-outpost/src/clients/solana/SolanaOutpostClient.ts b/packages/sdk-outpost/src/clients/solana/SolanaOutpostClient.ts index 01f05665..044be38b 100644 --- a/packages/sdk-outpost/src/clients/solana/SolanaOutpostClient.ts +++ b/packages/sdk-outpost/src/clients/solana/SolanaOutpostClient.ts @@ -12,8 +12,6 @@ import { } from "../../deployments/index.js" import { OutpostDeploymentVerifier } from "../../verification/index.js" import { SolanaOutpostClientOptions, SolanaProgramMap } from "./Types.js" -import { SolanaReserveClient } from "./SolanaReserveClient.js" -import { SolanaReserveSwapClient } from "./SolanaReserveSwapClient.js" /** Strictly typed access to one verified Solana outpost deployment. */ export class SolanaOutpostClient { @@ -50,16 +48,8 @@ export class SolanaOutpostClient { }, options.provider ) - this.reserves = new SolanaReserveClient(options.provider, this.liqsolCore) - this.swaps = new SolanaReserveSwapClient(options.provider, this.liqsolCore) } - /** Reserve creation, cancellation, and reads for this verified outpost. */ - readonly reserves: SolanaReserveClient - - /** Reserve-swap writes and balance reads for this verified outpost. */ - readonly swaps: SolanaReserveSwapClient - /** Provider verified against the configured Solana cluster. */ get provider(): SolanaOutpostClientOptions["provider"] { return this.options.provider diff --git a/packages/sdk-outpost/src/clients/solana/SolanaReserveAddresses.ts b/packages/sdk-outpost/src/clients/solana/SolanaReserveAddresses.ts deleted file mode 100644 index 464e2ad7..00000000 --- a/packages/sdk-outpost/src/clients/solana/SolanaReserveAddresses.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { BN } from "@coral-xyz/anchor" -import { PublicKey } from "@solana/web3.js" - -import { - assertReserveUnsigned64, - type OutpostReserveIdentity -} from "../../reserves/index.js" - -const SolanaReserveSeed = { - outpostConfig: Buffer.from("outpost_config"), - outboundMessageBuffer: Buffer.from("outbound_message_buffer"), - reserve: Buffer.from("reserve"), - reserveVault: Buffer.from("reserve_vault") - } as const, - Unsigned64ByteLength = 8 - -/** Canonical PDA derivation for Solana reserve lifecycle and swap clients. */ -export class SolanaReserveAddresses { - /** Bind reserve address derivation to one verified program deployment. */ - constructor(private readonly programId: PublicKey) {} - - /** Derive the singleton outpost configuration PDA. */ - outpostConfig(): PublicKey { - return this.derive([SolanaReserveSeed.outpostConfig]) - } - - /** Derive the singleton outbound message-buffer PDA. */ - outboundMessageBuffer(): PublicKey { - return this.derive([SolanaReserveSeed.outboundMessageBuffer]) - } - - /** Derive a reserve account PDA. */ - reserve(identity: OutpostReserveIdentity): PublicKey { - return this.reserveAddress(SolanaReserveSeed.reserve, identity) - } - - /** Derive a reserve custody-vault PDA. */ - reserveVault(identity: OutpostReserveIdentity): PublicKey { - return this.reserveAddress(SolanaReserveSeed.reserveVault, identity) - } - - /** Convert an SDK reserve integer to Anchor's u64 representation. */ - unsigned64( - value: OutpostReserveIdentity["tokenCode"], - field: string - ): BN { - return new BN(assertReserveUnsigned64(value, field).toString()) - } - - private derive(seeds: Buffer[]): PublicKey { - return PublicKey.findProgramAddressSync(seeds, this.programId)[0] - } - - private reserveAddress( - seed: Buffer, - identity: OutpostReserveIdentity - ): PublicKey { - return this.derive([ - seed, - this.unsigned64Seed(identity.tokenCode, "tokenCode"), - this.unsigned64Seed(identity.reserveCode, "reserveCode") - ]) - } - - private unsigned64Seed( - value: OutpostReserveIdentity["tokenCode"], - field: string - ): Buffer { - return this.unsigned64(value, field).toArrayLike( - Buffer, - "le", - Unsigned64ByteLength - ) - } -} diff --git a/packages/sdk-outpost/src/clients/solana/SolanaReserveClient.ts b/packages/sdk-outpost/src/clients/solana/SolanaReserveClient.ts deleted file mode 100644 index d52f8bd3..00000000 --- a/packages/sdk-outpost/src/clients/solana/SolanaReserveClient.ts +++ /dev/null @@ -1,258 +0,0 @@ -import { - type AnchorProvider, - type IdlAccounts, - type Program -} from "@coral-xyz/anchor" -import { - createAssociatedTokenAccountIdempotentInstruction, - getAssociatedTokenAddressSync, - TOKEN_PROGRAM_ID -} from "@solana/spl-token" -import { - PublicKey, - SYSVAR_RENT_PUBKEY, - SystemProgram, - Transaction, - type TransactionInstruction -} from "@solana/web3.js" -import { match } from "ts-pattern" - -import type { LiqsolCore } from "@wireio/outpost-solana-artifacts" -import { - assertReserveCreateDefinition, - assertReserveUnsigned64, - OutpostReserveStatus, - type OutpostReserveIdentity, - type OutpostReserveSubmission, - type SolanaConfiguredReserveToken, - type SolanaReserveCreateRequest, - type SolanaReserveRecord -} from "../../reserves/index.js" -import { SolanaReserveAddresses } from "./SolanaReserveAddresses.js" - -const PublicKeyByteLength = 32, - NativeSolanaDecimals = 9, - NativeTokenMarker = new PublicKey(new Uint8Array(PublicKeyByteLength)) - -type LiqsolCoreAccounts = IdlAccounts - -/** Reserve creation, cancellation, and reads for one verified Solana outpost. */ -export class SolanaReserveClient { - private readonly addresses: SolanaReserveAddresses - - /** Bind reserve lifecycle operations to a generated Anchor program client. */ - constructor( - private readonly provider: AnchorProvider, - private readonly program: Program - ) { - this.addresses = new SolanaReserveAddresses(program.programId) - } - - /** List token routes configured by the deployed outpost. */ - async getConfiguredTokens(): Promise { - const account = await this.provider.connection.getAccountInfo( - this.addresses.outpostConfig() - ) - if (account == null) { - throw new Error("Solana outpost configuration is unavailable.") - } - const config = this.program.coder.accounts.decode< - LiqsolCoreAccounts["outpostConfig"] - >("outpostConfig", account.data), - precisionByTokenCode = new Map( - config.precisionByTokenCode.map(entry => [ - entry.tokenCode.toString(), - entry.decimals - ]) - ) - - return config.tokenAddressesByCode.map(entry => { - const tokenCode = entry.tokenCode.toString(), - isNative = entry.mint.equals(NativeTokenMarker), - configuredDecimals = precisionByTokenCode.get(tokenCode) - if (!isNative && configuredDecimals == null) { - throw new Error( - `Solana reserve token ${tokenCode} has no configured precision.` - ) - } - return { - tokenCode: BigInt(tokenCode), - mint: entry.mint, - isNative, - decimals: isNative ? NativeSolanaDecimals : configuredDecimals - } - }) - } - - /** Derive the local outpost account for one reserve identity. */ - deriveAddress(identity: OutpostReserveIdentity): PublicKey { - return this.addresses.reserve(identity) - } - - /** Build reserve-creation instructions without signing or submitting. */ - async createInstructions( - request: SolanaReserveCreateRequest - ): Promise { - assertReserveCreateDefinition(request) - assertReserveUnsigned64(request.externalTokenAmount, "externalTokenAmount") - if (request.mint.equals(NativeTokenMarker)) { - throw new Error( - "Native SOL reserve creation requires a real placeholder SPL mint and creator token account; the all-zero native marker is configuration metadata only." - ) - } - const creator = this.assertWallet(), - { - creatorTokenAccount = getAssociatedTokenAddressSync( - request.mint, - creator, - false, - TOKEN_PROGRAM_ID - ) - } = request, - createReserve = await this.program.methods - .createReserve( - this.addresses.unsigned64(request.tokenCode, "tokenCode"), - this.addresses.unsigned64(request.reserveCode, "reserveCode"), - this.addresses.unsigned64( - request.externalTokenAmount, - "externalTokenAmount" - ), - this.addresses.unsigned64( - request.requestedWireAmount, - "requestedWireAmount" - ), - request.connectorWeightBps, - request.name, - request.description, - request.isPrivate - ) - .accounts({ - creator, - config: this.addresses.outpostConfig(), - reserve: this.addresses.reserve(request), - reserveVault: this.addresses.reserveVault(request), - mint: request.mint, - creatorAta: creatorTokenAccount, - outboundMessageBuffer: this.addresses.outboundMessageBuffer(), - tokenProgram: TOKEN_PROGRAM_ID, - systemProgram: SystemProgram.programId, - rent: SYSVAR_RENT_PUBKEY - }) - .instruction() - - if ( - request.ensureCreatorTokenAccount === false || - request.creatorTokenAccount != null - ) { - return [createReserve] - } - - return [ - createAssociatedTokenAccountIdempotentInstruction( - creator, - creatorTokenAccount, - creator, - request.mint, - TOKEN_PROGRAM_ID - ), - createReserve - ] - } - - /** Create a pending external reserve. */ - async create( - request: SolanaReserveCreateRequest - ): Promise { - const transactionId = await this.provider.sendAndConfirm( - new Transaction().add(...(await this.createInstructions(request))) - ) - return { transactionId } - } - - /** Build a creator-authorized pending-reserve cancellation instruction. */ - async cancelInstruction( - identity: OutpostReserveIdentity - ): Promise { - const creator = this.assertWallet() - return this.program.methods - .cancelCreateReserve( - this.addresses.unsigned64(identity.tokenCode, "tokenCode"), - this.addresses.unsigned64(identity.reserveCode, "reserveCode") - ) - .accounts({ - creator, - config: this.addresses.outpostConfig(), - reserve: this.addresses.reserve(identity), - outboundMessageBuffer: this.addresses.outboundMessageBuffer() - }) - .instruction() - } - - /** Request cancellation and refund of a pending reserve. */ - async cancel( - identity: OutpostReserveIdentity - ): Promise { - const transactionId = await this.provider.sendAndConfirm( - new Transaction().add(await this.cancelInstruction(identity)) - ) - return { transactionId } - } - - /** Read and normalize one local reserve account. */ - async get( - identity: OutpostReserveIdentity - ): Promise { - const address = this.addresses.reserve(identity), - account = await this.provider.connection.getAccountInfo(address) - if (account == null) return null - const reserve = this.program.coder.accounts.decode< - LiqsolCoreAccounts["reserve"] - >("reserve", account.data) - - return { - address, - vaultAddress: this.addresses.reserveVault(identity), - tokenCode: BigInt(reserve.tokenCode.toString()), - reserveCode: BigInt(reserve.reserveCode.toString()), - externalTokenAmount: BigInt(reserve.externalTokenAmount.toString()), - requestedWireAmount: BigInt(reserve.requestedWireAmount.toString()), - connectorWeightBps: reserve.connectorWeightBps, - status: match(reserve.status) - .when( - status => "pending" in status, - () => OutpostReserveStatus.pending - ) - .when( - status => "active" in status, - () => OutpostReserveStatus.active - ) - .when( - status => "cancelled" in status, - () => OutpostReserveStatus.cancelled - ) - .otherwise(() => { - throw new Error("Unsupported Solana reserve status.") - }), - creator: reserve.creator, - name: this.decodeFixedUtf8(reserve.nameBytes, reserve.nameLen), - description: this.decodeFixedUtf8( - reserve.descriptionBytes, - reserve.descriptionLen - ) - } - } - - private assertWallet(): PublicKey { - const publicKey = this.provider.wallet.publicKey - if (publicKey == null) { - throw new Error("Solana reserve operation requires a connected wallet.") - } - return publicKey - } - - private decodeFixedUtf8(value: ArrayLike, length: number): string { - return new TextDecoder().decode( - Uint8Array.from(value).slice(0, Number(length)) - ) - } -} diff --git a/packages/sdk-outpost/src/clients/solana/SolanaReserveSwapClient.ts b/packages/sdk-outpost/src/clients/solana/SolanaReserveSwapClient.ts deleted file mode 100644 index 2622e6d1..00000000 --- a/packages/sdk-outpost/src/clients/solana/SolanaReserveSwapClient.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { type AnchorProvider, type Program } from "@coral-xyz/anchor" -import { - getAssociatedTokenAddressSync, - TOKEN_PROGRAM_ID -} from "@solana/spl-token" -import { - PublicKey, - SystemProgram, - Transaction, - type TransactionInstruction, - type VersionedTransactionResponse -} from "@solana/web3.js" -import type { LiqsolCore } from "@wireio/outpost-solana-artifacts" -import { getBytes } from "ethers" - -import { - assertReserveSwapRequest, - type ReserveSwapRequest, - type ReserveSwapSubmission, - type SolanaSplReserveSwapRequest -} from "../../reserves/index.js" -import { SolanaReserveAddresses } from "./SolanaReserveAddresses.js" - -const ConfirmationCommitment = "confirmed", - ConfirmationPollIntervalMs = 1_500, - SolanaConfirmationStatus = { - confirmed: "confirmed", - finalized: "finalized" - } as const, - SwapDepositLog = /opp_outpost: SwapDeposit id=(\d+)\b/ - -/** Reserve-swap writes and balance reads for one verified Solana outpost. */ -export class SolanaReserveSwapClient { - private readonly addresses: SolanaReserveAddresses - - /** Create a Solana reserve-swap workflow bound to a verified deployment. */ - constructor( - private readonly provider: AnchorProvider, - private readonly program: Program - ) { - this.addresses = new SolanaReserveAddresses(program.programId) - } - - /** Build a native-SOL reserve-swap instruction without signing it. */ - async createNativeInstruction( - request: ReserveSwapRequest - ): Promise { - assertReserveSwapRequest(request) - const user = this.assertWallet() - return this.program.methods - .requestSwap(...this.instructionArguments(request)) - .accounts({ - user, - config: this.addresses.outpostConfig(), - reserve: this.addresses.reserve({ - tokenCode: request.sourceTokenCode, - reserveCode: request.sourceReserveCode - }), - outboundMessageBuffer: this.addresses.outboundMessageBuffer(), - systemProgram: SystemProgram.programId - }) - .instruction() - } - - /** Escrow native SOL and return the confirmed protocol deposit id. */ - async requestNative( - request: ReserveSwapRequest - ): Promise { - return this.submit(await this.createNativeInstruction(request)) - } - - /** Build a classic SPL reserve-swap instruction without signing it. */ - async createSplInstruction( - request: SolanaSplReserveSwapRequest - ): Promise { - assertReserveSwapRequest(request) - const user = this.assertWallet(), - { - userTokenAccount = getAssociatedTokenAddressSync( - request.mint, - user, - false, - TOKEN_PROGRAM_ID - ) - } = request - - return this.program.methods - .requestSwapSpl(...this.instructionArguments(request)) - .accounts({ - user, - config: this.addresses.outpostConfig(), - reserve: this.addresses.reserve({ - tokenCode: request.sourceTokenCode, - reserveCode: request.sourceReserveCode - }), - reserveVault: this.addresses.reserveVault({ - tokenCode: request.sourceTokenCode, - reserveCode: request.sourceReserveCode - }), - mint: request.mint, - userAta: userTokenAccount, - outboundMessageBuffer: this.addresses.outboundMessageBuffer(), - tokenProgram: TOKEN_PROGRAM_ID - }) - .instruction() - } - - /** Escrow a classic SPL token and return the confirmed protocol deposit id. */ - async requestSpl( - request: SolanaSplReserveSwapRequest - ): Promise { - return this.submit(await this.createSplInstruction(request)) - } - - /** Read the native SOL balance of one account. */ - async nativeBalance(owner = this.assertWallet()): Promise { - return BigInt( - await this.provider.connection.getBalance( - owner, - ConfirmationCommitment - ) - ) - } - - /** Read a classic SPL token balance, returning zero when the ATA is absent. */ - async splBalance( - mint: PublicKey, - owner = this.assertWallet() - ): Promise { - const tokenAccount = getAssociatedTokenAddressSync( - mint, - owner, - false, - TOKEN_PROGRAM_ID - ), - account = await this.provider.connection.getAccountInfo( - tokenAccount, - ConfirmationCommitment - ) - if (account == null) return 0n - const balance = await this.provider.connection.getTokenAccountBalance( - tokenAccount, - ConfirmationCommitment - ) - return BigInt(balance.value.amount) - } - - private assertWallet(): PublicKey { - const publicKey = this.provider.wallet.publicKey - if (publicKey == null) { - throw new Error("Solana reserve swap requires a connected wallet.") - } - return publicKey - } - - private instructionArguments(request: ReserveSwapRequest) { - return [ - this.unsigned64(request.sourceTokenCode, "sourceTokenCode"), - this.unsigned64(request.sourceReserveCode, "sourceReserveCode"), - this.unsigned64(request.sourceAmount, "sourceAmount"), - this.unsigned64(request.targetChainCode, "targetChainCode"), - this.unsigned64(request.targetTokenCode, "targetTokenCode"), - this.unsigned64(request.targetReserveCode, "targetReserveCode"), - Buffer.from(getBytes(request.targetRecipient)), - this.unsigned64(request.targetAmount, "targetAmount"), - request.targetToleranceBps - ] as const - } - - private unsigned64( - value: ReserveSwapRequest["sourceTokenCode"], - field: string - ) { - return this.addresses.unsigned64(value, field) - } - - private async submit( - instruction: TransactionInstruction - ): Promise { - const connection = this.provider.connection, - latestBlockhash = await connection.getLatestBlockhash( - ConfirmationCommitment - ), - transaction = new Transaction({ - feePayer: this.assertWallet(), - blockhash: latestBlockhash.blockhash, - lastValidBlockHeight: latestBlockhash.lastValidBlockHeight - }).add(instruction), - signedTransaction = await this.provider.wallet.signTransaction( - transaction - ), - transactionId = await connection.sendRawTransaction( - signedTransaction.serialize(), - { preflightCommitment: ConfirmationCommitment } - ), - confirmedTransaction = await this.waitForConfirmedTransaction( - transactionId, - latestBlockhash.lastValidBlockHeight - ), - sourceRequestId = SolanaReserveSwapClient.parseSourceRequestId( - confirmedTransaction.meta?.logMessages ?? [] - ) - return { transactionId, sourceRequestId } - } - - /** Poll one submitted signature until Solana records success or a terminal error. */ - private async waitForConfirmedTransaction( - transactionId: string, - lastValidBlockHeight: number - ): Promise { - const connection = this.provider.connection, - [statusResponse, blockHeight] = await Promise.all([ - connection.getSignatureStatuses([transactionId], { - searchTransactionHistory: true - }), - connection.getBlockHeight(ConfirmationCommitment) - ]), - status = statusResponse.value[0] - - if (status?.err != null) { - throw new Error( - `Solana reserve swap ${transactionId} failed: ${JSON.stringify(status.err)}` - ) - } - - const confirmed = - status?.confirmationStatus === SolanaConfirmationStatus.confirmed || - status?.confirmationStatus === SolanaConfirmationStatus.finalized - if (confirmed) { - const confirmedTransaction = await connection.getTransaction( - transactionId, - { - commitment: ConfirmationCommitment, - maxSupportedTransactionVersion: 0 - } - ) - if (confirmedTransaction != null) return confirmedTransaction - } else if (status == null && blockHeight > lastValidBlockHeight) { - throw new Error( - `Solana reserve swap ${transactionId} expired before it was recorded on chain.` - ) - } - - await new Promise(resolve => setTimeout(resolve, ConfirmationPollIntervalMs)) - return this.waitForConfirmedTransaction( - transactionId, - lastValidBlockHeight - ) - } - - /** Parse the canonical deposit id logged by `request_swap*`. */ - static parseSourceRequestId(logMessages: readonly string[]): bigint { - const match = logMessages - .map(message => message.match(SwapDepositLog)) - .find(candidate => candidate != null) - if (match == null) { - throw new Error("Confirmed Solana reserve swap did not log SwapDeposit.") - } - return BigInt(match[1]) - } -} diff --git a/packages/sdk-outpost/src/clients/solana/index.ts b/packages/sdk-outpost/src/clients/solana/index.ts index 3bd9d25d..e99823c0 100644 --- a/packages/sdk-outpost/src/clients/solana/index.ts +++ b/packages/sdk-outpost/src/clients/solana/index.ts @@ -1,4 +1 @@ -export * from "./SolanaReserveSwapClient.js" -export * from "./SolanaReserveAddresses.js" -export * from "./SolanaReserveClient.js" export * from "./Types.js" diff --git a/packages/sdk-outpost/src/deployments/Schema.ts b/packages/sdk-outpost/src/deployments/Schema.ts index 9a50a127..7b5e00cb 100644 --- a/packages/sdk-outpost/src/deployments/Schema.ts +++ b/packages/sdk-outpost/src/deployments/Schema.ts @@ -63,10 +63,6 @@ export const OutpostDeploymentProfileSchema = z EthereumContractDeploymentProfileSchema.optional(), [EthereumContractName.OPP]: EthereumContractDeploymentProfileSchema, [EthereumContractName.OPPInbound]: - EthereumContractDeploymentProfileSchema, - [EthereumContractName.OperatorRegistry]: - EthereumContractDeploymentProfileSchema, - [EthereumContractName.ReserveManager]: EthereumContractDeploymentProfileSchema }) }), diff --git a/packages/sdk-outpost/src/deployments/Types.ts b/packages/sdk-outpost/src/deployments/Types.ts index 33abb78e..e9433412 100644 --- a/packages/sdk-outpost/src/deployments/Types.ts +++ b/packages/sdk-outpost/src/deployments/Types.ts @@ -8,9 +8,7 @@ export enum OutpostChainFamily { export enum EthereumContractName { BAR = "BAR", OPP = "OPP", - OPPInbound = "OPPInbound", - OperatorRegistry = "OperatorRegistry", - ReserveManager = "ReserveManager" + OPPInbound = "OPPInbound" } /** Solana programs owned by the current outpost deployment. */ diff --git a/packages/sdk-outpost/src/index.ts b/packages/sdk-outpost/src/index.ts index 974408ce..9f43ee00 100644 --- a/packages/sdk-outpost/src/index.ts +++ b/packages/sdk-outpost/src/index.ts @@ -1,5 +1,4 @@ export * from "./clients/index.js" export * from "./artifacts/index.js" export * from "./deployments/index.js" -export * from "./reserves/index.js" export * from "./verification/index.js" diff --git a/packages/sdk-outpost/src/reserves/Types.ts b/packages/sdk-outpost/src/reserves/Types.ts deleted file mode 100644 index 15955652..00000000 --- a/packages/sdk-outpost/src/reserves/Types.ts +++ /dev/null @@ -1,155 +0,0 @@ -import type { PublicKey } from "@solana/web3.js" -import type { ReserveManagerLib } from "@wireio/outpost-ethereum-artifacts" -import type { BigNumberish, BytesLike } from "ethers" - -/** Two-part identity shared by external-chain reserve custody clients. */ -export interface OutpostReserveIdentity { - /** Packed external token slug. */ - tokenCode: BigNumberish - /** Packed reserve discriminator slug. */ - reserveCode: BigNumberish -} - -/** Portable reserve fields validated before any external wallet prompt. */ -export interface ReserveCreateDefinition extends OutpostReserveIdentity { - /** External-chain amount escrowed by the creator. */ - externalTokenAmount: BigNumberish - /** Exact WIRE amount required to activate the reserve. */ - requestedWireAmount: BigNumberish - /** Bancor connector weight in basis points. */ - connectorWeightBps: number - /** User-facing reserve name. */ - name: string - /** User-facing reserve description. */ - description: string - /** Whether Wire restricts routing to a same-owner external counterpart. */ - isPrivate: boolean -} - -/** Ethereum reserve-creation request with the creator's AuthEx public key. */ -export interface EthereumReserveCreateRequest extends ReserveCreateDefinition { - /** Compressed secp256k1 public key that derives to the connected signer. */ - creatorPubKey: BytesLike -} - -/** Confirmed external reserve lifecycle submission. */ -export interface OutpostReserveSubmission { - /** External-chain transaction hash or signature. */ - transactionId: string -} - -/** Chain-neutral lifecycle states exposed by external reserve clients. */ -export enum OutpostReserveStatus { - pending = "pending", - active = "active", - cancelled = "cancelled" -} - -/** Normalized Ethereum ReserveManager record. */ -export interface EthereumReserveRecord { - /** Packed external token slug. */ - tokenCode: bigint - /** Packed reserve discriminator slug. */ - reserveCode: bigint - /** Raw external amount committed at creation. */ - externalTokenAmount: bigint - /** Exact WIRE amount requested from the matcher. */ - requestedWireAmount: bigint - /** Connector weight in basis points. */ - connectorWeightBps: number - /** Local outpost lifecycle state. */ - status: OutpostReserveStatus - /** Ethereum creator address. */ - creator: string - /** Whether the record exists. */ - exists: boolean -} - -/** Solana reserve-creation request for the permissionless outpost path. */ -export interface SolanaReserveCreateRequest extends ReserveCreateDefinition { - /** Custody mint for SPL reserves, or a real placeholder SPL mint for native SOL. */ - mint: PublicKey - /** Creator token-account override. Defaults to the canonical ATA. */ - creatorTokenAccount?: PublicKey - /** Add an idempotent ATA instruction when no override is supplied. */ - ensureCreatorTokenAccount?: boolean -} - -/** Normalized Solana outpost reserve account. */ -export interface SolanaReserveRecord { - /** Reserve account PDA. */ - address: PublicKey - /** Reserve vault PDA. */ - vaultAddress: PublicKey - /** Packed external token slug. */ - tokenCode: bigint - /** Packed reserve discriminator slug. */ - reserveCode: bigint - /** Raw external amount committed at creation. */ - externalTokenAmount: bigint - /** Exact WIRE amount requested from the matcher. */ - requestedWireAmount: bigint - /** Connector weight in basis points. */ - connectorWeightBps: number - /** Local outpost lifecycle state. */ - status: OutpostReserveStatus - /** Solana wallet that created and can cancel the reserve. */ - creator: PublicKey - /** UTF-8 reserve display name. */ - name: string - /** UTF-8 reserve description. */ - description: string -} - -/** Token route configured by the Solana outpost authority. */ -export interface SolanaConfiguredReserveToken { - /** Packed token slug used in reserve instructions. */ - tokenCode: bigint - /** Configured SPL mint, or the all-zero native marker. */ - mint: PublicKey - /** Whether the token route represents native SOL. */ - isNative: boolean - /** Chain-side decimal precision used at the depot boundary. */ - decimals: number -} - -/** Permit signature accepted by Ethereum ReserveManager. */ -export type EthereumReservePermitSignature = ReserveManagerLib.PermitSigStruct - -/** Confirmed source-outpost submission used to correlate a swap with Wire. */ -export interface ReserveSwapSubmission { - /** External-chain transaction signature or hash. */ - transactionId: string - /** Protocol deposit id copied into `sysio.uwrit::uwreqs.source_tx_id`. */ - sourceRequestId: bigint -} - -/** Reserve-swap request shared by Ethereum and Solana outposts. */ -export interface ReserveSwapRequest { - /** Packed source token slug. */ - sourceTokenCode: BigNumberish - /** Packed source reserve discriminator. */ - sourceReserveCode: BigNumberish - /** Escrowed source amount in external-chain base units. */ - sourceAmount: BigNumberish - /** Packed destination chain slug. */ - targetChainCode: BigNumberish - /** Packed destination token slug. */ - targetTokenCode: BigNumberish - /** Packed destination reserve discriminator or WIRE sentinel. */ - targetReserveCode: BigNumberish - /** Recipient bytes interpreted by the destination chain. */ - targetRecipient: BytesLike - /** Current destination quote in depot units. */ - targetAmount: BigNumberish - /** Maximum accepted quote drift in basis points. */ - targetToleranceBps: number -} - -/** Classic SPL source details for a Solana reserve swap. */ -export interface SolanaSplReserveSwapRequest extends ReserveSwapRequest { - /** SPL mint configured for the source token code. */ - mint: PublicKey - /** Optional source token account; the wallet ATA is used when omitted. */ - userTokenAccount?: PublicKey -} diff --git a/packages/sdk-outpost/src/reserves/Validation.ts b/packages/sdk-outpost/src/reserves/Validation.ts deleted file mode 100644 index a0c653fb..00000000 --- a/packages/sdk-outpost/src/reserves/Validation.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { getBigInt, getBytes, isBytesLike, toUtf8Bytes } from "ethers" - -import type { - EthereumReserveCreateRequest, - ReserveCreateDefinition, - ReserveSwapRequest -} from "./Types.js" - -const MaximumUnsigned64 = 18_446_744_073_709_551_615n, - MinimumReserveValue = 1n, - MinimumConnectorWeightBps = 1, - MaximumConnectorWeightBps = 9999, - MinimumToleranceBps = 0, - MaximumToleranceBps = 10_000, - MaximumReserveNameBytes = 64, - MaximumReserveDescriptionBytes = 256, - CompressedSecp256k1PublicKeyBytes = 33, - CompressedSecp256k1PublicKeyPrefix = { - even: 2, - odd: 3 - } as const, - InvalidCompressedSecp256k1PublicKeyMessage = - "creatorPubKey must be a 33-byte compressed secp256k1 public key." - -/** Validate one value against the positive unsigned 64-bit protocol boundary. */ -export function assertReserveUnsigned64( - value: ReserveSwapRequest["sourceTokenCode"], - field: string -): bigint { - let parsed: bigint - try { - parsed = getBigInt(value) - } catch (error: unknown) { - throw new Error(`${field} must be an integer.`, { cause: error }) - } - if (parsed < MinimumReserveValue || parsed > MaximumUnsigned64) { - throw new Error(`${field} must be between 1 and uint64 max.`) - } - return parsed -} - -/** Validate portable reserve-creation fields before opening a wallet prompt. */ -export function assertReserveCreateDefinition( - definition: ReserveCreateDefinition -): void { - assertReserveUnsigned64(definition.tokenCode, "tokenCode") - assertReserveUnsigned64(definition.reserveCode, "reserveCode") - - let externalTokenAmount: bigint - try { - externalTokenAmount = getBigInt(definition.externalTokenAmount) - } catch (error: unknown) { - throw new Error("externalTokenAmount must be an integer.", { cause: error }) - } - if (externalTokenAmount < MinimumReserveValue) { - throw new Error("externalTokenAmount must be greater than zero.") - } - - assertReserveUnsigned64(definition.requestedWireAmount, "requestedWireAmount") - if ( - !Number.isInteger(definition.connectorWeightBps) || - definition.connectorWeightBps < MinimumConnectorWeightBps || - definition.connectorWeightBps > MaximumConnectorWeightBps - ) { - throw new Error( - `connectorWeightBps must be an integer from ${MinimumConnectorWeightBps} to ${MaximumConnectorWeightBps}.` - ) - } - - const nameBytes = toUtf8Bytes(definition.name).length - if (nameBytes === 0 || nameBytes > MaximumReserveNameBytes) { - throw new Error( - `name must contain 1 to ${MaximumReserveNameBytes} UTF-8 bytes.` - ) - } - - const descriptionBytes = toUtf8Bytes(definition.description).length - if (descriptionBytes > MaximumReserveDescriptionBytes) { - throw new Error( - `description must contain at most ${MaximumReserveDescriptionBytes} UTF-8 bytes.` - ) - } -} - -/** Validate Ethereum-specific reserve creation fields. */ -export function assertEthereumReserveCreateRequest( - request: EthereumReserveCreateRequest -): void { - assertReserveCreateDefinition(request) - if (!isBytesLike(request.creatorPubKey)) { - throw new Error(InvalidCompressedSecp256k1PublicKeyMessage) - } - const creatorPublicKey = getBytes(request.creatorPubKey) - if ( - creatorPublicKey.length !== CompressedSecp256k1PublicKeyBytes || - (creatorPublicKey[0] !== CompressedSecp256k1PublicKeyPrefix.even && - creatorPublicKey[0] !== CompressedSecp256k1PublicKeyPrefix.odd) - ) { - throw new Error(InvalidCompressedSecp256k1PublicKeyMessage) - } -} - -/** Validate portable reserve-swap fields before opening a wallet prompt. */ -export function assertReserveSwapRequest(request: ReserveSwapRequest): void { - assertReserveUnsigned64(request.sourceTokenCode, "sourceTokenCode") - assertReserveUnsigned64(request.sourceReserveCode, "sourceReserveCode") - assertReserveUnsigned64(request.sourceAmount, "sourceAmount") - assertReserveUnsigned64(request.targetChainCode, "targetChainCode") - assertReserveUnsigned64(request.targetTokenCode, "targetTokenCode") - assertReserveUnsigned64(request.targetReserveCode, "targetReserveCode") - assertReserveUnsigned64(request.targetAmount, "targetAmount") - - if ( - !Number.isInteger(request.targetToleranceBps) || - request.targetToleranceBps < MinimumToleranceBps || - request.targetToleranceBps > MaximumToleranceBps - ) { - throw new Error( - `targetToleranceBps must be between ${MinimumToleranceBps} and ${MaximumToleranceBps}.` - ) - } - if (getBytes(request.targetRecipient).length === 0) { - throw new Error("targetRecipient is required.") - } -} diff --git a/packages/sdk-outpost/src/reserves/index.ts b/packages/sdk-outpost/src/reserves/index.ts deleted file mode 100644 index 421334f2..00000000 --- a/packages/sdk-outpost/src/reserves/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./Types.js" -export * from "./Validation.js" diff --git a/packages/sdk-outpost/tests/assets/Artifacts.test.ts b/packages/sdk-outpost/tests/assets/Artifacts.test.ts index 9def5533..aa0324e2 100644 --- a/packages/sdk-outpost/tests/assets/Artifacts.test.ts +++ b/packages/sdk-outpost/tests/assets/Artifacts.test.ts @@ -3,8 +3,7 @@ import { BAR__factory, IERC1155__factory, OPP__factory, - OperatorRegistry__factory, - ReserveManager__factory + OPPInbound__factory } from "@wireio/outpost-ethereum-artifacts" import { liqsolCoreIdl, @@ -98,12 +97,12 @@ describe("source-owned outpost artifacts", () => { it("rejects a runtime deployment with an incompatible Ethereum ABI", () => { const profile = createOutpostDeploymentProfileFixture() - profile.ethereum.contracts[EthereumContractName.ReserveManager].abiSha256 = + profile.ethereum.contracts[EthereumContractName.OPPInbound].abiSha256 = "f".repeat(64) expect(() => assertOutpostArtifactCompatibility(profile, OutpostChainFamily.ethereum) - ).toThrow("Ethereum ReserveManager ABI interface mismatch") + ).toThrow("Ethereum OPPInbound ABI interface mismatch") }) it("rejects a runtime deployment with an incompatible Solana IDL", () => { @@ -116,28 +115,17 @@ describe("source-owned outpost artifacts", () => { ).toThrow("Solana liqsolCore IDL interface mismatch") }) - it("generates the callable swap and collateral surfaces", () => { + it("generates active transport and node-owner surfaces", () => { const accountNames: Array["account"]> = [ "outpostConfig", - "reserve" + "operatorRegistry" ] expect(OPP__factory.abi.length).toBeGreaterThan(0) expect( OPP__factory.createInterface().getFunction("addAttestation") ).toBeDefined() expect( - ReserveManager__factory.createInterface().getFunction("requestSwap") - ).toBeDefined() - expect( - ReserveManager__factory.createInterface().getFunction( - "requestSwapErc20WithApproval" - ) - ).toBeDefined() - expect( - OperatorRegistry__factory.createInterface().getFunction("deposit") - ).toBeDefined() - expect( - OperatorRegistry__factory.createInterface().getFunction("commit") + OPPInbound__factory.createInterface().getFunction("epochIn") ).toBeDefined() expect( BAR__factory.createInterface().getFunction("wireNodesContract") @@ -160,6 +148,6 @@ describe("source-owned outpost artifacts", () => { "commitUnderwrite" ]) ) - expect(accountNames).toEqual(["outpostConfig", "reserve"]) + expect(accountNames).toEqual(["outpostConfig", "operatorRegistry"]) }) }) diff --git a/packages/sdk-outpost/tests/assets/Registry.test.ts b/packages/sdk-outpost/tests/assets/Registry.test.ts index b3f00242..006f845f 100644 --- a/packages/sdk-outpost/tests/assets/Registry.test.ts +++ b/packages/sdk-outpost/tests/assets/Registry.test.ts @@ -1,4 +1,4 @@ -import { ReserveManager__factory } from "@wireio/outpost-ethereum-artifacts" +import { OPPInbound__factory } from "@wireio/outpost-ethereum-artifacts" import { liqsolCoreIdl } from "@wireio/outpost-solana-artifacts" import { @@ -18,15 +18,15 @@ describe("OutpostArtifactRegistry", () => { ) expect(suite).toBe(CurrentOutpostArtifactSuite) - expect(suite.ethereum.factories[EthereumContractName.ReserveManager]).toBe( - ReserveManager__factory + expect(suite.ethereum.factories[EthereumContractName.OPPInbound]).toBe( + OPPInbound__factory ) expect(suite.solana.idls[SolanaProgramName.liqsolCore]).toBe(liqsolCoreIdl) }) it("rejects an unregistered Ethereum interface", () => { const profile = createOutpostDeploymentProfileFixture() - profile.ethereum.contracts[EthereumContractName.ReserveManager].abiSha256 = + profile.ethereum.contracts[EthereumContractName.OPPInbound].abiSha256 = MismatchedInterfaceDigest expect(OutpostArtifactRegistry.candidates(profile)).toEqual([]) diff --git a/packages/sdk-outpost/tests/clients/OutpostClient.test.ts b/packages/sdk-outpost/tests/clients/OutpostClient.test.ts index 7c73b14a..a67f848f 100644 --- a/packages/sdk-outpost/tests/clients/OutpostClient.test.ts +++ b/packages/sdk-outpost/tests/clients/OutpostClient.test.ts @@ -23,7 +23,7 @@ describe("OutpostClient", () => { typedClient: EthereumOutpostClient = client expect(typedClient.profile).toBe(profile) - expect(typedClient.reserves).toBeDefined() + expect(typedClient.profile).toEqual(profile) }) it("preserves the precise Solana client type", async () => { @@ -38,6 +38,6 @@ describe("OutpostClient", () => { typedClient: SolanaOutpostClient = client expect(typedClient.profile).toBe(profile) - expect(typedClient.reserves).toBeDefined() + expect(typedClient.profile).toEqual(profile) }) }) diff --git a/packages/sdk-outpost/tests/clients/ethereum/EthereumOutpostClient.test.ts b/packages/sdk-outpost/tests/clients/ethereum/EthereumOutpostClient.test.ts index 7ee3a833..67bab9c6 100644 --- a/packages/sdk-outpost/tests/clients/ethereum/EthereumOutpostClient.test.ts +++ b/packages/sdk-outpost/tests/clients/ethereum/EthereumOutpostClient.test.ts @@ -1,22 +1,11 @@ -import { - getBytes, - hexlify, - Network, - sha256, - Wallet, - zeroPadValue, - type EventLog -} from "ethers" +import { getBytes, hexlify, Network, sha256, zeroPadValue } from "ethers" import { EthereumContractName, - EthereumReserveClient, - EthereumReserveSwapClient, OutpostChainFamily, OutpostClient, type EthereumOutpostClient, - type EthereumOutpostClientOptions, - type ReserveSwapRequest + type EthereumOutpostClientOptions } from "@wireio/sdk-outpost" import { createEthereumImplementationCode, @@ -35,72 +24,6 @@ function createEthereumClient( } describe("EthereumOutpostClient", () => { - it("submits native reserve swaps with estimated gas headroom", async () => { - const request: ReserveSwapRequest = { - sourceTokenCode: 1, - sourceReserveCode: 2, - sourceAmount: 3, - targetChainCode: 4, - targetTokenCode: 5, - targetReserveCode: 6, - targetRecipient: new Uint8Array([7]), - targetAmount: 8, - targetToleranceBps: 500 - }, - wait = jest.fn().mockResolvedValue({ - logs: [{ eventName: "SwapDeposit", args: [42n] } as unknown as EventLog] - }), - requestSwap = Object.assign( - jest.fn().mockResolvedValue({ hash: "0xabc", wait }), - { - staticCall: jest.fn().mockResolvedValue(null), - estimateGas: jest.fn().mockResolvedValue(100_000n) - } - ), - reserveManager = { - requestSwap - } as unknown as ConstructorParameters< - typeof EthereumReserveSwapClient - >[0], - client = new EthereumReserveSwapClient( - reserveManager, - Wallet.createRandom() - ) - - await expect(client.requestNative(request)).resolves.toEqual({ - transactionId: "0xabc", - sourceRequestId: 42n - }) - expect(requestSwap).toHaveBeenCalledWith( - request.sourceTokenCode, - request.sourceReserveCode, - request.targetChainCode, - request.targetTokenCode, - request.targetReserveCode, - request.targetRecipient, - request.targetAmount, - request.targetToleranceBps, - { - value: request.sourceAmount, - gasLimit: 125_000n - } - ) - expect(wait).toHaveBeenCalledWith(1) - }) - - it("adds 25% gas headroom to reserve swap submissions", () => { - expect(EthereumReserveSwapClient.addSubmissionGasHeadroom(789_767)).toEqual( - 987_209n - ) - expect(EthereumReserveSwapClient.addSubmissionGasHeadroom(1)).toEqual(2n) - }) - - it("resets nonzero ERC-20 allowances before increasing them", () => { - expect(EthereumReserveSwapClient.approvalAmounts(2, 3)).toEqual([0n, 3n]) - expect(EthereumReserveSwapClient.approvalAmounts(0, 3)).toEqual([3n]) - expect(EthereumReserveSwapClient.approvalAmounts(3, 3)).toEqual([]) - }) - it("verifies a profile and returns a generated contract type", async () => { const profile = createOutpostDeploymentProfileFixture(), provider = createEthereumProviderFixture(profile), @@ -108,13 +31,11 @@ describe("EthereumOutpostClient", () => { profile, connection: provider }), - reserveManager = client.contract(EthereumContractName.ReserveManager) + inbound = client.contract(EthereumContractName.OPPInbound) - expect(reserveManager.target).toBe( - profile.ethereum.contracts[EthereumContractName.ReserveManager].address + expect(inbound.target).toBe( + profile.ethereum.contracts[EthereumContractName.OPPInbound].address ) - expect(client.reserves).toBeInstanceOf(EthereumReserveClient) - expect(client.swaps).toBeInstanceOf(EthereumReserveSwapClient) expect(provider.getCode).toHaveBeenCalledTimes( Object.values(EthereumContractName).length * 2 ) @@ -132,25 +53,12 @@ describe("EthereumOutpostClient", () => { connection: provider }) - expect(client.reserves).toBeInstanceOf(EthereumReserveClient) - expect(client.swaps).toBeInstanceOf(EthereumReserveSwapClient) expect(() => client.nodeOwners).toThrow("has no BAR identity") expect(provider.getCode).toHaveBeenCalledTimes( (Object.values(EthereumContractName).length - 1) * 2 ) }) - it("parses the protocol deposit id from a confirmed receipt", () => { - const events = [ - { eventName: "SwapDeposit", args: [42n] } as unknown as EventLog - ] - - expect(EthereumReserveSwapClient.parseSourceRequestId(events)).toBe(42n) - expect(() => EthereumReserveSwapClient.parseSourceRequestId([])).toThrow( - "did not emit SwapDeposit" - ) - }) - it("rejects the wrong Ethereum chain", async () => { const profile = createOutpostDeploymentProfileFixture(), provider = createEthereumProviderFixture(profile) @@ -189,7 +97,7 @@ describe("EthereumOutpostClient", () => { const profile = createOutpostDeploymentProfileFixture(), provider = createEthereumProviderFixture(profile) profile.ethereum.contracts[ - EthereumContractName.ReserveManager + EthereumContractName.OPPInbound ].implementationCodeSha256 = "f".repeat(64) await expect( diff --git a/packages/sdk-outpost/tests/clients/ethereum/EthereumReserveClient.test.ts b/packages/sdk-outpost/tests/clients/ethereum/EthereumReserveClient.test.ts deleted file mode 100644 index c63a11d4..00000000 --- a/packages/sdk-outpost/tests/clients/ethereum/EthereumReserveClient.test.ts +++ /dev/null @@ -1,245 +0,0 @@ -import type { ReserveManager } from "@wireio/outpost-ethereum-artifacts" -import { - AbiCoder, - AbstractSigner, - JsonRpcProvider, - Wallet, - ZeroAddress, - ZeroHash, - type Provider, - type TransactionReceipt, - type TransactionRequest, - type TransactionResponse, - type TypedDataDomain, - type TypedDataField -} from "ethers" - -import { - EthereumReserveClient, - OutpostReserveStatus, - type EthereumReserveCreateRequest -} from "@wireio/sdk-outpost" - -const ReserveTransactionHash = `0x${"11".repeat(32)}`, - ApprovalTransactionHash = `0x${"22".repeat(32)}`, - ReserveManagerAddress = "0x18E317A7D70d8fBf8e6E893616b52390EbBdb629", - TokenAddress = "0x5c74c94173F05dA1720953407cbb920F3DF9f887", - CreatorAddress = "0x7412BC256355ABD22dD53De3a38E8995b5d4c1D1", - TransactionReceiptFixture = { - logs: [], - status: 1 - } as unknown as TransactionReceipt - -const request: EthereumReserveCreateRequest = { - tokenCode: 1, - reserveCode: 2, - externalTokenAmount: 3, - requestedWireAmount: 4, - connectorWeightBps: 5_000, - name: "Private ETH reserve", - description: "Same-owner external routing", - isPrivate: true, - creatorPubKey: `0x02${"11".repeat(32)}` -} - -/** Create one v6 transaction response fixture. */ -function transactionFixture( - hash = ReserveTransactionHash, - wait: TransactionResponse["wait"] = jest.fn( - async (): Promise => TransactionReceiptFixture - ) -): TransactionResponse { - return { hash, wait } as unknown as TransactionResponse -} - -/** Create one callable v6 contract method with a static preflight. */ -function contractMethodFixture(transaction: TransactionResponse) { - return Object.assign( - jest.fn(async () => transaction), - { - staticCall: jest.fn(async (): Promise => undefined) - } - ) -} - -/** Create the ReserveManager contract surface exercised by this client. */ -function reserveManagerFixture(configuredTokenAddress = TokenAddress) { - const transaction = transactionFixture(), - createReserve = contractMethodFixture(transaction), - createErc20WithApproval = contractMethodFixture(transaction), - createErc20WithPermit = contractMethodFixture(transaction), - reserveManager = { - target: ReserveManagerAddress, - getAddress: jest.fn(async () => ReserveManagerAddress), - create_reserve: createReserve, - requestReserveCreateErc20WithApproval: createErc20WithApproval, - requestReserveCreateErc20WithPermit: createErc20WithPermit, - cancel_create_reserve: jest.fn(async () => transaction), - tokenAddressesByCode: jest.fn(async () => configuredTokenAddress), - getReserve: jest.fn(async () => ({ - tokenCode: 1n, - reserveCode: 2n, - externalTokenAmount: 3n, - requestedWireAmount: 4n, - connectorWeightBps: 5_000n, - status: 1n, - creator: CreatorAddress, - exists: true - })) - } as unknown as ReserveManager - - return { reserveManager, transaction } -} - -/** Create a static v6 provider that confirms the mocked ERC-20 transaction. */ -function erc20Provider(): JsonRpcProvider { - const provider = new JsonRpcProvider(undefined, 31_337, { - staticNetwork: true - }) - jest - .spyOn(provider, "getTransactionReceipt") - .mockResolvedValue(TransactionReceiptFixture) - return provider -} - -/** Minimal ethers v6 signer used to observe ERC-20 calls and submissions. */ -class Erc20Signer extends AbstractSigner { - readonly approval = transactionFixture(ApprovalTransactionHash) - - constructor(provider: Provider = erc20Provider()) { - super(provider) - } - - async getAddress(): Promise { - return CreatorAddress - } - - async signMessage(): Promise { - return "0x" - } - - async signTransaction(): Promise { - return "0x" - } - - async signTypedData( - _domain: TypedDataDomain, - _types: Record>, - _value: Record - ): Promise { - return "0x" - } - - connect(provider: Provider): Erc20Signer { - return new Erc20Signer(provider) - } - - async call(): Promise { - return AbiCoder.defaultAbiCoder().encode(["uint256"], [0]) - } - - async sendTransaction( - _transaction: TransactionRequest - ): Promise { - return this.approval - } -} - -describe("EthereumReserveClient", () => { - it("creates a native pending reserve after static preflight", async () => { - const { reserveManager, transaction } = reserveManagerFixture(), - client = new EthereumReserveClient(reserveManager, Wallet.createRandom()) - - await expect(client.createNative(request)).resolves.toEqual({ - transactionId: ReserveTransactionHash - }) - expect(reserveManager.create_reserve.staticCall).toHaveBeenCalledTimes(1) - expect(reserveManager.create_reserve).toHaveBeenCalledTimes(1) - expect(transaction.wait).toHaveBeenCalledWith(1) - }) - - it("approves an ERC-20 before creating its pending reserve", async () => { - const { reserveManager } = reserveManagerFixture(), - signer = new Erc20Signer(), - client = new EthereumReserveClient(reserveManager, signer) - - const submission = await client.createErc20WithApproval( - request, - TokenAddress - ) - expect(submission).toEqual({ transactionId: ReserveTransactionHash }) - expect(signer.provider.getTransactionReceipt).toHaveBeenCalledWith( - ApprovalTransactionHash - ) - expect( - reserveManager.requestReserveCreateErc20WithApproval - ).toHaveBeenCalledTimes(1) - }) - - it("creates an ERC-20 reserve with a supplied permit", async () => { - const { reserveManager } = reserveManagerFixture(), - client = new EthereumReserveClient(reserveManager, Wallet.createRandom()) - - await expect( - client.createErc20WithPermit(request, { - deadline: 100, - v: 27, - r: ZeroHash, - s: ZeroHash - }) - ).resolves.toEqual({ transactionId: ReserveTransactionHash }) - expect( - reserveManager.requestReserveCreateErc20WithPermit.staticCall - ).toHaveBeenCalledTimes(1) - }) - - it("cancels a pending reserve and normalizes active local state", async () => { - const { reserveManager } = reserveManagerFixture(), - client = new EthereumReserveClient(reserveManager, Wallet.createRandom()) - - await expect( - client.cancel({ tokenCode: 1, reserveCode: 2 }) - ).resolves.toEqual({ transactionId: ReserveTransactionHash }) - await expect(client.get({ tokenCode: 1, reserveCode: 2 })).resolves.toEqual( - expect.objectContaining({ - tokenCode: 1n, - reserveCode: 2n, - status: OutpostReserveStatus.active, - creator: CreatorAddress, - exists: true - }) - ) - }) - - it("requires a signer and a configured ERC-20 route", async () => { - const { reserveManager } = reserveManagerFixture(), - provider = new JsonRpcProvider(), - providerClient = new EthereumReserveClient(reserveManager, provider) - - await expect(providerClient.createNative(request)).rejects.toThrow( - "requires a connected signer" - ) - - const { reserveManager: unconfiguredReserveManager } = - reserveManagerFixture(ZeroAddress), - signerClient = new EthereumReserveClient( - unconfiguredReserveManager, - new Erc20Signer() - ) - await expect(signerClient.createErc20WithApproval(request)).rejects.toThrow( - "No ERC-20 address is configured" - ) - }) - - it("rejects an ERC-20 address that differs from the configured route", async () => { - const { reserveManager } = reserveManagerFixture(), - signer = new Erc20Signer(), - client = new EthereumReserveClient(reserveManager, signer), - differentTokenAddress = Wallet.createRandom().address - - await expect( - client.createErc20WithApproval(request, differentTokenAddress) - ).rejects.toThrow("does not match the configured route") - expect(signer.provider.getTransactionReceipt).not.toHaveBeenCalled() - }) -}) diff --git a/packages/sdk-outpost/tests/clients/solana/SolanaOutpostClient.test.ts b/packages/sdk-outpost/tests/clients/solana/SolanaOutpostClient.test.ts index 55319dd1..11f13385 100644 --- a/packages/sdk-outpost/tests/clients/solana/SolanaOutpostClient.test.ts +++ b/packages/sdk-outpost/tests/clients/solana/SolanaOutpostClient.test.ts @@ -1,13 +1,10 @@ -import { Keypair, PublicKey, SystemProgram } from "@solana/web3.js" +import { PublicKey } from "@solana/web3.js" import { sha256 } from "ethers" import { OutpostChainFamily, OutpostClient, - type ReserveSwapRequest, SolanaProgramName, - SolanaReserveClient, - SolanaReserveSwapClient, SolanaUpgradeableLoaderProgramId, type SolanaOutpostClient, type SolanaOutpostClientOptions @@ -20,7 +17,6 @@ import { } from "../../Fixtures.js" const WrongProgramDataAddress = "SysvarRent111111111111111111111111111111111" -const SubmittedSignature = "3".repeat(64) const SolanaProgramDataMetadataByteLength = 45 /** Create the Solana client through the package's only public facade. */ @@ -33,24 +29,6 @@ function createSolanaClient( }) } -const reserveSwapRequest: ReserveSwapRequest = { - sourceTokenCode: 1, - sourceReserveCode: 2, - sourceAmount: 3, - targetChainCode: 4, - targetTokenCode: 5, - targetReserveCode: 6, - targetRecipient: Uint8Array.from([7]), - targetAmount: 8, - targetToleranceBps: 500 -} - -function unsigned64Seed(value: bigint): Buffer { - const seed = Buffer.alloc(8) - seed.writeBigUInt64LE(value) - return seed -} - describe("SolanaOutpostClient", () => { it("verifies a profile and returns its runtime program address", async () => { const profile = createOutpostDeploymentProfileFixture(), @@ -61,120 +39,6 @@ describe("SolanaOutpostClient", () => { expect(program.programId.toBase58()).toBe( profile.solana.programs[SolanaProgramName.liqsolCore].address ) - expect(client.reserves).toBeInstanceOf(SolanaReserveClient) - expect(client.swaps).toBeInstanceOf(SolanaReserveSwapClient) - }) - - it("parses the protocol deposit id from confirmed program logs", () => { - expect( - SolanaReserveSwapClient.parseSourceRequestId([ - "Program log: opp_outpost: SwapDeposit id=42 hash=abc" - ]) - ).toBe(42n) - expect(() => SolanaReserveSwapClient.parseSourceRequestId([])).toThrow( - "did not log SwapDeposit" - ) - }) - - it("derives native reserve accounts from the deployed program seeds", async () => { - const profile = createOutpostDeploymentProfileFixture(), - provider = createSolanaProviderFixture(profile), - client = await createSolanaClient({ profile, provider }), - instruction = await client.swaps.createNativeInstruction( - reserveSwapRequest - ), - programAddress = new PublicKey( - profile.solana.programs[SolanaProgramName.liqsolCore].address - ), - expectedReserve = PublicKey.findProgramAddressSync( - [ - Buffer.from("reserve"), - unsigned64Seed(1n), - unsigned64Seed(2n) - ], - programAddress - )[0] - - expect(instruction.keys[2].pubkey.equals(expectedReserve)).toBe(true) - }) - - it("derives SPL reserve vaults from the deployed program seeds", async () => { - const profile = createOutpostDeploymentProfileFixture(), - provider = createSolanaProviderFixture(profile), - client = await createSolanaClient({ profile, provider }), - instruction = await client.swaps.createSplInstruction({ - ...reserveSwapRequest, - mint: Keypair.generate().publicKey - }), - programAddress = new PublicKey( - profile.solana.programs[SolanaProgramName.liqsolCore].address - ), - expectedVault = PublicKey.findProgramAddressSync( - [ - Buffer.from("reserve_vault"), - unsigned64Seed(1n), - unsigned64Seed(2n) - ], - programAddress - )[0] - - expect(instruction.keys[3].pubkey.equals(expectedVault)).toBe(true) - }) - - it("polls a submitted reserve swap until Solana confirms it", async () => { - const profile = createOutpostDeploymentProfileFixture(), - provider = createSolanaProviderFixture(profile), - client = await createSolanaClient({ profile, provider }), - instruction = SystemProgram.transfer({ - fromPubkey: provider.wallet.publicKey, - toPubkey: provider.wallet.publicKey, - lamports: 1 - }) - jest.spyOn(client.swaps, "createNativeInstruction").mockResolvedValue(instruction) - jest.spyOn(provider.connection, "getLatestBlockhash").mockResolvedValue({ - blockhash: Keypair.generate().publicKey.toBase58(), - lastValidBlockHeight: 100 - }) - jest.spyOn(provider.connection, "sendRawTransaction").mockResolvedValue(SubmittedSignature) - jest.spyOn(provider.connection, "getSignatureStatuses").mockResolvedValue({ - context: { slot: 10 }, - value: [{ slot: 10, confirmations: 1, err: null, confirmationStatus: "confirmed" }] - }) - jest.spyOn(provider.connection, "getBlockHeight").mockResolvedValue(10) - jest.spyOn(provider.connection, "getTransaction").mockResolvedValue({ - meta: { logMessages: ["Program log: opp_outpost: SwapDeposit id=42 hash=abc"] } - } as never) - - await expect(client.swaps.requestNative(reserveSwapRequest)).resolves.toEqual({ - transactionId: SubmittedSignature, - sourceRequestId: 42n - }) - }) - - it("reports an explicit on-chain reserve swap failure", async () => { - const profile = createOutpostDeploymentProfileFixture(), - provider = createSolanaProviderFixture(profile), - client = await createSolanaClient({ profile, provider }), - instruction = SystemProgram.transfer({ - fromPubkey: provider.wallet.publicKey, - toPubkey: provider.wallet.publicKey, - lamports: 1 - }) - jest.spyOn(client.swaps, "createNativeInstruction").mockResolvedValue(instruction) - jest.spyOn(provider.connection, "getLatestBlockhash").mockResolvedValue({ - blockhash: Keypair.generate().publicKey.toBase58(), - lastValidBlockHeight: 100 - }) - jest.spyOn(provider.connection, "sendRawTransaction").mockResolvedValue(SubmittedSignature) - jest.spyOn(provider.connection, "getSignatureStatuses").mockResolvedValue({ - context: { slot: 10 }, - value: [{ slot: 10, confirmations: 1, err: { InstructionError: [2, "Custom"] }, confirmationStatus: "confirmed" }] - }) - jest.spyOn(provider.connection, "getBlockHeight").mockResolvedValue(10) - - await expect(client.swaps.requestNative(reserveSwapRequest)).rejects.toThrow( - `Solana reserve swap ${SubmittedSignature} failed` - ) }) it("rejects the wrong Solana cluster", async () => { @@ -184,9 +48,9 @@ describe("SolanaOutpostClient", () => { .spyOn(provider.connection, "getGenesisHash") .mockResolvedValue("9".repeat(32)) - await expect( - createSolanaClient({ profile, provider }) - ).rejects.toThrow("Solana genesis mismatch") + await expect(createSolanaClient({ profile, provider })).rejects.toThrow( + "Solana genesis mismatch" + ) }) it("rejects a configured program that is not executable", async () => { @@ -194,9 +58,9 @@ describe("SolanaOutpostClient", () => { provider = createSolanaProviderFixture(profile) jest.spyOn(provider.connection, "getAccountInfo").mockResolvedValue(null) - await expect( - createSolanaClient({ profile, provider }) - ).rejects.toThrow("is not executable") + await expect(createSolanaClient({ profile, provider })).rejects.toThrow( + "is not executable" + ) }) it("rejects a Program account pointing at another ProgramData account", async () => { @@ -210,9 +74,9 @@ describe("SolanaOutpostClient", () => { rentEpoch: 0 }) - await expect( - createSolanaClient({ profile, provider }) - ).rejects.toThrow("ProgramData mismatch") + await expect(createSolanaClient({ profile, provider })).rejects.toThrow( + "ProgramData mismatch" + ) }) it("rejects a ProgramData code mismatch", async () => { @@ -240,9 +104,9 @@ describe("SolanaOutpostClient", () => { } ) - await expect( - createSolanaClient({ profile, provider }) - ).rejects.toThrow("ProgramData mismatch") + await expect(createSolanaClient({ profile, provider })).rejects.toThrow( + "ProgramData mismatch" + ) }) it("rejects ProgramData executable bytes from another producer binary", async () => { @@ -272,8 +136,8 @@ describe("SolanaOutpostClient", () => { } ) - await expect( - createSolanaClient({ profile, provider }) - ).rejects.toThrow("artifact program mismatch") + await expect(createSolanaClient({ profile, provider })).rejects.toThrow( + "artifact program mismatch" + ) }) }) diff --git a/packages/sdk-outpost/tests/clients/solana/SolanaReserveAddresses.test.ts b/packages/sdk-outpost/tests/clients/solana/SolanaReserveAddresses.test.ts deleted file mode 100644 index 83d0a954..00000000 --- a/packages/sdk-outpost/tests/clients/solana/SolanaReserveAddresses.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Keypair, PublicKey } from "@solana/web3.js" - -import { SolanaReserveAddresses } from "@wireio/sdk-outpost" - -const Unsigned64ByteLength = 8 - -function unsigned64Seed(value: bigint): Buffer { - const seed = Buffer.alloc(Unsigned64ByteLength) - seed.writeBigUInt64LE(value) - return seed -} - -describe("SolanaReserveAddresses", () => { - it("derives every reserve lifecycle PDA from the deployed program", () => { - const programId = Keypair.generate().publicKey, - addresses = new SolanaReserveAddresses(programId), - identity = { tokenCode: 1n, reserveCode: 2n }, - expectedReserve = PublicKey.findProgramAddressSync( - [ - Buffer.from("reserve"), - unsigned64Seed(1n), - unsigned64Seed(2n) - ], - programId - )[0], - expectedVault = PublicKey.findProgramAddressSync( - [ - Buffer.from("reserve_vault"), - unsigned64Seed(1n), - unsigned64Seed(2n) - ], - programId - )[0] - - expect(addresses.reserve(identity).equals(expectedReserve)).toBe(true) - expect(addresses.reserveVault(identity).equals(expectedVault)).toBe(true) - expect( - addresses - .outpostConfig() - .equals( - PublicKey.findProgramAddressSync( - [Buffer.from("outpost_config")], - programId - )[0] - ) - ).toBe(true) - expect( - addresses - .outboundMessageBuffer() - .equals( - PublicKey.findProgramAddressSync( - [Buffer.from("outbound_message_buffer")], - programId - )[0] - ) - ).toBe(true) - }) - - it("rejects reserve identity values outside the protocol u64 range", () => { - const addresses = new SolanaReserveAddresses(Keypair.generate().publicKey) - - expect(() => addresses.unsigned64(0, "tokenCode")).toThrow( - "tokenCode must be between 1 and uint64 max." - ) - }) -}) diff --git a/packages/sdk-outpost/tests/clients/solana/SolanaReserveClient.test.ts b/packages/sdk-outpost/tests/clients/solana/SolanaReserveClient.test.ts deleted file mode 100644 index fd116187..00000000 --- a/packages/sdk-outpost/tests/clients/solana/SolanaReserveClient.test.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { BN, Program } from "@coral-xyz/anchor" -import { - liqsolCoreIdl, - type LiqsolCore -} from "@wireio/outpost-solana-artifacts" -import { ASSOCIATED_TOKEN_PROGRAM_ID } from "@solana/spl-token" -import { Keypair, PublicKey } from "@solana/web3.js" - -import { - OutpostReserveStatus, - type SolanaReserveCreateRequest, - SolanaReserveClient -} from "@wireio/sdk-outpost" -import { - createOutpostDeploymentProfileFixture, - createSolanaProviderFixture -} from "../../Fixtures.js" - -const SubmittedSignature = "4".repeat(64), - AccountData = Buffer.alloc(8), - NativeTokenMarker = new PublicKey(new Uint8Array(32)) - -const request: SolanaReserveCreateRequest = { - tokenCode: 1, - reserveCode: 2, - externalTokenAmount: 3, - requestedWireAmount: 4, - connectorWeightBps: 5_000, - name: "Private USDC reserve", - description: "Same-owner external routing", - isPrivate: true, - mint: Keypair.generate().publicKey -} - -function clientFixture() { - const profile = createOutpostDeploymentProfileFixture(), - provider = createSolanaProviderFixture(profile), - address = profile.solana.programs.liqsolCore.address, - program = new Program( - { ...liqsolCoreIdl, address }, - provider - ), - client = new SolanaReserveClient(provider, program) - - return { client, program, provider } -} - -describe("SolanaReserveClient", () => { - it("builds permissionless reserve creation with an idempotent creator ATA", async () => { - const { client, program, provider } = clientFixture(), - instructions = await client.createInstructions(request) - - expect(instructions).toHaveLength(2) - expect( - instructions[0].programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID) - ).toBe(true) - expect(instructions[1].programId.equals(program.programId)).toBe(true) - expect( - instructions[1].keys.some(key => - key.pubkey.equals(provider.wallet.publicKey) - ) - ).toBe(true) - }) - - it("uses an explicit creator token account without adding an ATA instruction", async () => { - const { client } = clientFixture(), - instructions = await client.createInstructions({ - ...request, - creatorTokenAccount: Keypair.generate().publicKey - }) - - expect(instructions).toHaveLength(1) - }) - - it("submits reserve creation and pending cancellation through the provider", async () => { - const { client, provider } = clientFixture(), - sendAndConfirm = jest - .spyOn(provider, "sendAndConfirm") - .mockResolvedValue(SubmittedSignature) - - await expect(client.create(request)).resolves.toEqual({ - transactionId: SubmittedSignature - }) - await expect( - client.cancel({ tokenCode: 1, reserveCode: 2 }) - ).resolves.toEqual({ transactionId: SubmittedSignature }) - expect(sendAndConfirm).toHaveBeenCalledTimes(2) - }) - - it("normalizes configured token routes and a local reserve record", async () => { - const { client, program, provider } = clientFixture(), - splMint = Keypair.generate().publicKey, - creator = Keypair.generate().publicKey - - jest.spyOn(provider.connection, "getAccountInfo").mockResolvedValue({ - data: AccountData, - executable: false, - lamports: 1, - owner: program.programId, - rentEpoch: 0 - }) - jest - .spyOn(program.coder.accounts, "decode") - .mockImplementation(accountName => - (accountName === "outpostConfig" - ? { - tokenAddressesByCode: [ - { tokenCode: new BN(1), mint: NativeTokenMarker }, - { tokenCode: new BN(2), mint: splMint } - ], - precisionByTokenCode: [ - { tokenCode: new BN(2), decimals: 6 } - ] - } - : { - tokenCode: new BN(2), - reserveCode: new BN(3), - externalTokenAmount: new BN(4), - requestedWireAmount: new BN(5), - connectorWeightBps: 5_000, - status: { active: {} }, - creator, - nameLen: 4, - nameBytes: [...Buffer.from("USDC"), ...new Uint8Array(60)], - descriptionLen: 7, - descriptionBytes: [ - ...Buffer.from("Private"), - ...new Uint8Array(249) - ] - }) as never - ) - - await expect(client.getConfiguredTokens()).resolves.toEqual([ - { - tokenCode: 1n, - mint: NativeTokenMarker, - isNative: true, - decimals: 9 - }, - { tokenCode: 2n, mint: splMint, isNative: false, decimals: 6 } - ]) - await expect( - client.get({ tokenCode: 2, reserveCode: 3 }) - ).resolves.toEqual( - expect.objectContaining({ - tokenCode: 2n, - reserveCode: 3n, - status: OutpostReserveStatus.active, - creator, - name: "USDC", - description: "Private" - }) - ) - }) - - it("returns null for an absent account and rejects invalid creation values", async () => { - const { client, provider } = clientFixture() - jest.spyOn(provider.connection, "getAccountInfo").mockResolvedValue(null) - - await expect( - client.get({ tokenCode: 1, reserveCode: 2 }) - ).resolves.toBeNull() - await expect( - client.createInstructions({ ...request, externalTokenAmount: 0 }) - ).rejects.toThrow("externalTokenAmount must be greater than zero.") - await expect( - client.createInstructions({ ...request, mint: NativeTokenMarker }) - ).rejects.toThrow("requires a real placeholder SPL mint") - }) - - it("rejects a configured SPL reserve route without chain precision", async () => { - const { client, program, provider } = clientFixture(), - splMint = Keypair.generate().publicKey - jest.spyOn(provider.connection, "getAccountInfo").mockResolvedValue({ - data: AccountData, - executable: false, - lamports: 1, - owner: program.programId, - rentEpoch: 0 - }) - jest.spyOn(program.coder.accounts, "decode").mockReturnValue({ - tokenAddressesByCode: [{ tokenCode: new BN(2), mint: splMint }], - precisionByTokenCode: [] - } as never) - - await expect(client.getConfiguredTokens()).rejects.toThrow( - "Solana reserve token 2 has no configured precision." - ) - }) -}) diff --git a/packages/sdk-outpost/tests/deployments/Schema.test.ts b/packages/sdk-outpost/tests/deployments/Schema.test.ts index 868ea698..d335eab1 100644 --- a/packages/sdk-outpost/tests/deployments/Schema.test.ts +++ b/packages/sdk-outpost/tests/deployments/Schema.test.ts @@ -14,10 +14,10 @@ describe("OutpostDeploymentProfileSchema", () => { `${profile.wire.chainId}-${profile.deploymentChecksum.slice(0, 12)}` ) expect( - profile.ethereum.contracts[EthereumContractName.ReserveManager].address + profile.ethereum.contracts[EthereumContractName.OPPInbound].address ).toBe( createOutpostDeploymentProfileFixture().ethereum.contracts[ - EthereumContractName.ReserveManager + EthereumContractName.OPPInbound ].address ) }) diff --git a/packages/sdk-outpost/tests/reserves/Validation.test.ts b/packages/sdk-outpost/tests/reserves/Validation.test.ts deleted file mode 100644 index 781fed49..00000000 --- a/packages/sdk-outpost/tests/reserves/Validation.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { - assertEthereumReserveCreateRequest, - assertReserveCreateDefinition, - assertReserveSwapRequest, - assertReserveUnsigned64, - type EthereumReserveCreateRequest, - type ReserveCreateDefinition, - type ReserveSwapRequest -} from "@wireio/sdk-outpost" - -const InvalidConnectorWeights = [0, 10_000] - -const reserveDefinition: ReserveCreateDefinition = { - tokenCode: 1, - reserveCode: 2, - externalTokenAmount: 3, - requestedWireAmount: 4, - connectorWeightBps: 5_000, - name: "Private ETH reserve", - description: "Same-owner external routing", - isPrivate: true -} - -const ethereumRequest: EthereumReserveCreateRequest = { - ...reserveDefinition, - creatorPubKey: `0x02${"11".repeat(32)}` -} - -const request: ReserveSwapRequest = { - sourceTokenCode: 1, - sourceReserveCode: 2, - sourceAmount: 3, - targetChainCode: 4, - targetTokenCode: 5, - targetReserveCode: 6, - targetRecipient: Uint8Array.from([7]), - targetAmount: 8, - targetToleranceBps: 500 -} - -describe("reserve swap validation", () => { - it("accepts portable and Ethereum reserve creation requests", () => { - expect(() => assertReserveCreateDefinition(reserveDefinition)).not.toThrow() - expect(() => - assertEthereumReserveCreateRequest(ethereumRequest) - ).not.toThrow() - }) - - it("rejects invalid reserve creation metadata and creator keys", () => { - InvalidConnectorWeights.forEach(connectorWeightBps => - expect(() => - assertReserveCreateDefinition({ - ...reserveDefinition, - connectorWeightBps - }) - ).toThrow("connectorWeightBps") - ) - expect(() => - assertReserveCreateDefinition({ ...reserveDefinition, name: "" }) - ).toThrow("name must contain") - expect(() => - assertEthereumReserveCreateRequest({ - ...ethereumRequest, - creatorPubKey: "0x02" - }) - ).toThrow("33-byte compressed") - expect(() => - assertEthereumReserveCreateRequest({ - ...ethereumRequest, - creatorPubKey: `0x04${"11".repeat(32)}` - }) - ).toThrow("33-byte compressed") - expect(() => - assertEthereumReserveCreateRequest({ - ...ethereumRequest, - creatorPubKey: "not-hex" - }) - ).toThrow("33-byte compressed") - }) - - it("accepts a portable positive request", () => { - expect(() => assertReserveSwapRequest(request)).not.toThrow() - expect(assertReserveUnsigned64(8, "value")).toBe(8n) - }) - - it("rejects an empty recipient and values outside uint64", () => { - expect(() => - assertReserveSwapRequest({ - ...request, - targetRecipient: new Uint8Array() - }) - ).toThrow("targetRecipient is required") - expect(() => assertReserveUnsigned64(0, "value")).toThrow( - "between 1 and uint64 max" - ) - }) -})