/** @module-tag localnet */ import { waitForTransactionReceipt } from 'viem/actions' import { Actions, Addresses } from 'viem/tempo' import { TxEnvelopeTempo } from 'ox/tempo' import * as Runtime from '../../../test/runtime.js' import * as TestTempo from '../../../test/Tempo.js' import * as Subsidy from './Subsidy.js' const account = TestTempo.accounts[6]! const recipient = TestTempo.accounts[7]! const runtime = Runtime.get() const client = TestTempo.getClient() const settler = Subsidy.create({ account, getClient: TestTempo.readClient(), policy: { maxAmount: '10' }, }) beforeAll(async () => { await Actions.faucet.fundSync(client, { account, timeout: 60_000 }) }) describe.skipIf(runtime.mode !== 'localnet')('create', () => { test('transfers a pathUSD subsidy through a persisted signed transaction', async () => { const before = await Actions.token.getBalance(client, { account: recipient.address, decimals: 6, token: Addresses.pathUsd, }) const prepared = await settler.prepare({ amount: 100_000n, depositId: 'fdp_local_pathusd', recipient: recipient.address, token: Addresses.pathUsd, }) const envelope = TxEnvelopeTempo.deserialize(prepared.transaction as TxEnvelopeTempo.Serialized) expect({ nonceKey: envelope.nonceKey, validBefore: envelope.validBefore, }).toMatchInlineSnapshot(` { "nonceKey": 30469680684220070457389426308647765119962481996559904707083080710737939923517n, "validBefore": undefined, } `) await settler.broadcast(prepared) await waitForTransactionReceipt(client, { hash: prepared.hash }) await expect .poll(async () => (await settler.status({ hash: prepared.hash })).type) .toBe('success') const [after, status] = await Promise.all([ Actions.token.getBalance(client, { account: recipient.address, decimals: 6, token: Addresses.pathUsd, }), settler.status({ hash: prepared.hash }), ]) expect({ delivered: after.amount - before.amount, status }).toMatchInlineSnapshot( { status: { tempoGasPaid: expect.any(String) }, }, ` { "delivered": 100000n, "status": { "tempoGasPaid": Any, "type": "success", }, } `, ) }) test('buys the exact destination amount with pathUSD and transfers it atomically', async () => { const destinationToken = runtime.fixtures?.crossTokenTransfer?.destinationToken if (!destinationToken) throw new Error('Expected a seeded local DEX pair.') const before = await Actions.token.getBalance(client, { account: recipient.address, decimals: 6, token: destinationToken, }) const prepared = await settler.prepare({ amount: 100_000n, depositId: 'fdp_local_activity_usd', recipient: recipient.address, token: destinationToken, }) await settler.broadcast(prepared) await waitForTransactionReceipt(client, { hash: prepared.hash }) await expect .poll(async () => (await settler.status({ hash: prepared.hash })).type) .toBe('success') const [after, status] = await Promise.all([ Actions.token.getBalance(client, { account: recipient.address, decimals: 6, token: destinationToken, }), settler.status({ hash: prepared.hash }), ]) expect({ delivered: after.amount - before.amount, status }).toMatchInlineSnapshot( { status: { tempoGasPaid: expect.any(String) }, }, ` { "delivered": 100000n, "status": { "tempoGasPaid": Any, "type": "success", }, } `, ) }) test('reports unavailable native DEX liquidity', async () => { const { token } = await Actions.token.createSync(TestTempo.getClient({ account }), { currency: 'USD', name: 'Unlisted USD', symbol: 'UNLISTED', }) await expect( settler.prepare({ amount: 100_000n, depositId: 'fdp_local_unlisted', recipient: recipient.address, token, }), ).rejects.toThrowErrorMatchingInlineSnapshot(`[Funding.Subsidy.LiquidityUnavailableError]`) }) test('reports unavailable pathUSD balance from transaction simulation', async () => { await expect( settler.prepare({ amount: 2n ** 120n, depositId: 'fdp_local_insufficient_balance', recipient: recipient.address, token: Addresses.pathUsd, }), ).rejects.toThrowErrorMatchingInlineSnapshot(`[Funding.Subsidy.BalanceUnavailableError]`) }) })