diff --git a/db/migrations/0026_tempo_workspace_ousd.sql b/db/migrations/0026_tempo_workspace_ousd.sql new file mode 100644 index 0000000..b9ea308 --- /dev/null +++ b/db/migrations/0026_tempo_workspace_ousd.sql @@ -0,0 +1,8 @@ +-- Make OUSD the default tip token for Tempo's own Slack workspace (T098H03GGE6) on mainnet. +UPDATE "workspace" +SET + "default_token_address" = '0x20c0000000000000000000006a37DA5C996874BE', + "updated_at" = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') +WHERE "provider" = 'slack' + AND "provider_id" = 'T098H03GGE6' + AND "chain_id" = 4217; diff --git a/src/api.ts b/src/api.ts index ff9eb06..a1bc79a 100644 --- a/src/api.ts +++ b/src/api.ts @@ -115,7 +115,9 @@ export const api = new Hono<{ chainName: Tempo.getChainName(link.chain_id), expiresAt: link.expires_at, ok: true as const, - tokenAddress: Address.checksum(link.default_token_address ?? Tempo.addressLookup.pathUsd), + tokenAddress: Address.checksum( + link.default_token_address ?? Tempo.getDefaultTokenAddress(link.chain_id), + ), }) }) .post( @@ -176,7 +178,9 @@ export const api = new Hono<{ expiresAt: link.access_key_expires_at, keyAuthorization: body.keyAuthorization, rootAddress: body.address, - tokenAddress: Address.checksum(link.default_token_address ?? Tempo.addressLookup.pathUsd), + tokenAddress: Address.checksum( + link.default_token_address ?? Tempo.getDefaultTokenAddress(link.chain_id), + ), }) const now = new Date().toISOString() const existingAccount = await c.var.db @@ -252,7 +256,9 @@ export const api = new Hono<{ .where( 'token_address', '=', - Address.checksum(link.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + link.default_token_address ?? Tempo.getDefaultTokenAddress(link.chain_id), + ), ) .execute() await c.var.db @@ -274,7 +280,7 @@ export const api = new Hono<{ id: Nanoid.generate(), revoked_at: null, token_address: Address.checksum( - link.default_token_address ?? Tempo.addressLookup.pathUsd, + link.default_token_address ?? Tempo.getDefaultTokenAddress(link.chain_id), ), updated_at: now, }) diff --git a/src/api.workers.test.ts b/src/api.workers.test.ts index f59035c..c6c115d 100644 --- a/src/api.workers.test.ts +++ b/src/api.workers.test.ts @@ -1509,7 +1509,7 @@ describe('/api/account/link/:token', () => { accessKeyAddress: pending.accessKey.address, accessKeyPublicKey: pending.accessKey.publicKey, ok: true, - tokenAddress: Tempo.addressLookup.pathUsd, + tokenAddress: Tempo.getDefaultTokenAddress(pending.workspace.chain_id), }) }) @@ -1906,7 +1906,8 @@ describe('/api/confirm/:token', () => { recipientProviderUserId: 'twitter-confirm-recipient', senderProviderUserId: 'twitter-confirm-sender', source: 'mention', - tokenAddress: workspace.default_token_address ?? Tempo.addressLookup.pathUsd, + tokenAddress: + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id), workspaceId: workspace.id, }) @@ -1973,7 +1974,8 @@ describe('/api/confirm/:token', () => { recipientProviderUserId, senderProviderUserId, source: 'mention', - tokenAddress: workspace.default_token_address ?? Tempo.addressLookup.pathUsd, + tokenAddress: + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id), workspaceId: workspace.id, } satisfies Confirmation.Payload const token = await Confirmation.encrypt(env, payload) @@ -3100,7 +3102,8 @@ async function signKeyAuthorization( chainId: pending.workspace.chain_id, expiresAt: pending.link.access_key_expires_at, tokenAddress: Address.checksum( - pending.workspace.default_token_address ?? Tempo.addressLookup.pathUsd, + pending.workspace.default_token_address ?? + Tempo.getDefaultTokenAddress(pending.workspace.chain_id), ), }) } diff --git a/src/chat.ts b/src/chat.ts index 34a5209..4af4996 100644 --- a/src/chat.ts +++ b/src/chat.ts @@ -832,7 +832,8 @@ const actions = { } const reactionTipConfigs = await getReactionTipConfigs(DB.create(env.DB), workspace.id) - const tokenAddress = workspace.default_token_address ?? Tempo.addressLookup.pathUsd + const tokenAddress = + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id) const tokenOptions = workspaceTokenOptions(workspace.chain_id) const tokenValue = tokenOptions.find((option) => option.address.toLowerCase() === tokenAddress.toLowerCase()) @@ -1014,7 +1015,7 @@ const modalSubmits = { if (!creator) return const tokenAddress = Address.checksum( - workspace.default_token_address ?? Tempo.addressLookup.pathUsd, + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id), ) const balance = await Actions.token.getBalance( createClient({ @@ -1167,7 +1168,8 @@ const modalSubmits = { if (!installation) return const now = new Date() - const tokenAddress = workspace.default_token_address ?? Tempo.addressLookup.pathUsd + const tokenAddress = + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id) const tipRaffle = { chain_id: workspace.chain_id, created_at: now.toISOString(), @@ -1375,7 +1377,8 @@ const handlers = { return } - const tokenAddress = workspace.default_token_address ?? Tempo.addressLookup.pathUsd + const tokenAddress = + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id) const token = await Tapimo.getTokenMetadata(env, workspace.chain_id, tokenAddress) if (!('openModal' in event)) { await postPrivateReply( @@ -1451,7 +1454,8 @@ const handlers = { return } - const tokenAddress = workspace.default_token_address ?? Tempo.addressLookup.pathUsd + const tokenAddress = + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id) const token = await Tapimo.getTokenMetadata(env, workspace.chain_id, tokenAddress) if (!('openModal' in event)) return await event.openModal( @@ -1579,7 +1583,8 @@ const handlers = { provider_id: ctx.provider.id, provider_message_ts: 'pending', requester_member_id: requester.memberId, - token_address: workspace.default_token_address ?? Tempo.addressLookup.pathUsd, + token_address: + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id), updated_at: now, workspace_id: workspace.id, } satisfies DB_gen.Insertable.tip_ask @@ -2243,7 +2248,11 @@ const handlers = { } const tokenAddress = parsed.token - ? Tempo.getTokenAddress(workspace?.chain_id ?? Tempo.chainLookup.mainnet, parsed.token) + ? Tempo.getTokenAddress( + workspace?.chain_id ?? Tempo.chainLookup.mainnet, + parsed.token, + workspace?.default_token_address, + ) : null if (parsed.token && !tokenAddress) { await postPrivateReply( @@ -2590,6 +2599,7 @@ const tipRaffleDurationOptions = [ { label: '7 days', ms: 7 * 24 * 60 * 60 * 1000, value: '7d' }, // 7 days ] as const const tokenOptions = [ + { address: Tempo.addressLookup.ousd, label: 'OUSD', value: 'OUSD' }, { address: Tempo.addressLookup.pathUsd, label: 'PathUSD', value: 'pathUSD' }, { address: Tempo.addressLookup.usdcE, label: 'USDC.e', value: 'USDC.e' }, { address: Tempo.addressLookup.usdt0, label: 'USDT0', value: 'USDT0' }, @@ -4608,7 +4618,9 @@ async function sendTipRaffleEscrowPayout( feePayer: 'sender', isDefaultToken: Address.isEqual( Address.checksum(existing.token_address), - Address.checksum(existing.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + existing.default_token_address ?? Tempo.getDefaultTokenAddress(existing.chain_id), + ), ), memo: existing.memo, ok: true, @@ -4745,7 +4757,9 @@ async function sendTipRaffleEscrowPayout( feePayer: 'sender', isDefaultToken: Address.isEqual( Address.checksum(input.tokenAddress), - Address.checksum(workspace.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id), + ), ), memo: input.memo, ok: true, @@ -4890,7 +4904,10 @@ async function tipRaffleMessage(db: DB.Type, tipRaffle: TipRaffleMessageInput) { const value = formatAmount(amount) return Address.isEqual( Address.checksum(tipRaffle.token_address), - Address.checksum(tipRaffle.workspace_default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + tipRaffle.workspace_default_token_address ?? + Tempo.getDefaultTokenAddress(tipRaffle.chain_id), + ), ) ? formatCurrencyAmount(value, token.currency) : formatTipAmount(value, token.currency, token.symbol) @@ -4997,7 +5014,9 @@ async function tipAskMessage(db: DB.Type, tipAsk: TipAskMessageInput) { const value = formatAmount(amount) return Address.isEqual( Address.checksum(tipAsk.token_address), - Address.checksum(tipAsk.workspace_default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + tipAsk.workspace_default_token_address ?? Tempo.getDefaultTokenAddress(tipAsk.chain_id), + ), ) ? formatCurrencyAmount(value, token.currency) : formatTipAmount(value, token.currency, token.symbol) @@ -5312,7 +5331,7 @@ export async function updateReceiptBoostAggregate( const amount = formatAmount(group.amount) const displayAmount = Address.isEqual( Address.checksum(group.tokenAddress), - Address.checksum(group.defaultTokenAddress ?? Tempo.addressLookup.pathUsd), + Address.checksum(group.defaultTokenAddress ?? Tempo.getDefaultTokenAddress(group.chainId)), ) ? formatCurrencyAmount(amount, token.currency) : formatTipAmount(amount, token.currency, token.symbol) @@ -6056,7 +6075,9 @@ async function postConnectLink(event: TipEvent, ctx: HandlerContext) { (row) => !row.token_address || row.token_address.toLowerCase() === - (workspace.default_token_address ?? Tempo.addressLookup.pathUsd).toLowerCase(), + ( + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id) + ).toLowerCase(), ) if (accessKey && !ctx.forceConnectRefresh) { await postPrivateReply(event, event.user, 'Already connected', { threadTs: ctx.threadTs }) @@ -6801,7 +6822,7 @@ async function reactionTipAggregateText( const amount = formatAmount(row.amount) const displayAmount = Address.isEqual( Address.checksum(row.token_address), - Address.checksum(row.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum(row.default_token_address ?? Tempo.getDefaultTokenAddress(row.chain_id)), ) ? formatCurrencyAmount(amount, token.currency) : formatTipAmount(amount, token.currency, token.symbol) @@ -6819,7 +6840,7 @@ async function reactionTipAggregateText( const amount = formatAmount(row.amount) const displayAmount = Address.isEqual( Address.checksum(row.token_address), - Address.checksum(row.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum(row.default_token_address ?? Tempo.getDefaultTokenAddress(row.chain_id)), ) ? formatCurrencyAmount(amount, token.currency) : formatTipAmount(amount, token.currency, token.symbol) @@ -6844,7 +6865,7 @@ async function reactionTipAggregateText( const amount = formatAmount(row.amount) const displayAmount = Address.isEqual( Address.checksum(row.token_address), - Address.checksum(row.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum(row.default_token_address ?? Tempo.getDefaultTokenAddress(row.chain_id)), ) ? formatCurrencyAmount(amount, token.currency) : formatTipAmount(amount, token.currency, token.symbol) @@ -7036,7 +7057,9 @@ export async function updateSlackPendingTipMessage(db: DB.Type, result: Tip.Pend .executeTakeFirst() const amount = Address.isEqual( Address.checksum(result.pendingTip.token_address), - Address.checksum(workspace?.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + workspace?.default_token_address ?? Tempo.getDefaultTokenAddress(result.pendingTip.chain_id), + ), ) ? formatCurrencyAmount(formatAmount(result.pendingTip.amount), tokenMetadata.currency) : formatTipAmount( @@ -7320,7 +7343,8 @@ async function configCard( options?: { canEdit?: boolean; updated?: boolean }, ) { const reactionTipConfigs = await getReactionTipConfigs(db, workspace.id) - const tokenAddress = workspace.default_token_address ?? Tempo.addressLookup.pathUsd + const tokenAddress = + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id) const token = Tempo.getTokenMetadataFallback(tokenAddress) const networkLabel = workspace.chain_id === Tempo.chainLookup.mainnet ? 'Mainnet' : 'Testnet' return { @@ -7429,7 +7453,8 @@ function configFallbackText( reactionTipConfigs: ReactionTipConfig[], options?: { updated?: boolean }, ) { - const tokenAddress = workspace.default_token_address ?? Tempo.addressLookup.pathUsd + const tokenAddress = + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id) return `Setting Value\nNetwork ${configNetworkLabel(workspace)}\nDefault token ${configToken(workspace).symbol} ${Tempo.explorerLink(workspace.chain_id, tokenAddress)}\nDefault amount ${formatAmount(workspace.default_amount)}\nReaction tips ${reactionTipConfigsText(reactionTipConfigs)}${options?.updated ? '\nWorkspace settings updated' : ''}` } @@ -7439,7 +7464,7 @@ function configNetworkLabel(workspace: DB_gen.Selectable.workspace) { function configToken(workspace: DB_gen.Selectable.workspace) { return Tempo.getTokenMetadataFallback( - workspace.default_token_address ?? Tempo.addressLookup.pathUsd, + workspace.default_token_address ?? Tempo.getDefaultTokenAddress(workspace.chain_id), ) } diff --git a/src/chat.workers.test.ts b/src/chat.workers.test.ts index 60431a4..2dfd7d8 100644 --- a/src/chat.workers.test.ts +++ b/src/chat.workers.test.ts @@ -3463,7 +3463,9 @@ test('@Tipbot mention connect link completion connects local workspace account', accessKeyAddress: link.access_key_address, chainId: link.chain_id, expiresAt: link.access_key_expires_at, - tokenAddress: Address.checksum(link.default_token_address ?? Tempo.addressLookup.pathUsd), + tokenAddress: Address.checksum( + link.default_token_address ?? Tempo.getDefaultTokenAddress(link.chain_id), + ), }) const completeResponse = await client.api.account.link[':token'].$post({ @@ -3716,7 +3718,9 @@ test('@Tipbot mention connect link completion notifies Slack Connect external ac accessKeyAddress: link.access_key_address, chainId: link.chain_id, expiresAt: link.access_key_expires_at, - tokenAddress: Address.checksum(link.default_token_address ?? Tempo.addressLookup.pathUsd), + tokenAddress: Address.checksum( + link.default_token_address ?? Tempo.getDefaultTokenAddress(link.chain_id), + ), }) const completeResponse = await client.api.account.link[':token'].$post({ @@ -4527,7 +4531,9 @@ test('@Tipbot mention claims Slack Connect pending tip when recipient connects', accessKeyAddress: link.access_key_address, chainId: link.chain_id, expiresAt: link.access_key_expires_at, - tokenAddress: Address.checksum(link.default_token_address ?? Tempo.addressLookup.pathUsd), + tokenAddress: Address.checksum( + link.default_token_address ?? Tempo.getDefaultTokenAddress(link.chain_id), + ), }), }, param: { token }, @@ -7362,7 +7368,7 @@ describe('/tip config', () => { }, { timeout: 10_000 }, // 10 seconds ) - .toEqual(['pathUSD', 'USDC.e', 'USDT0']) + .toEqual(['OUSD', 'pathUSD', 'USDC.e', 'USDT0']) fetchSpy.mockRestore() }, 20_000) // 20 seconds diff --git a/src/lib/slack.ts b/src/lib/slack.ts index 5f5f3be..382158e 100644 --- a/src/lib/slack.ts +++ b/src/lib/slack.ts @@ -616,6 +616,7 @@ async function buildHomeView(input: { (async () => { // Fetch balances for every token allowed in this workspace, falling back to RPC. const tokens = [ + { address: Tempo.addressLookup.ousd, label: 'OUSD' }, { address: Tempo.addressLookup.pathUsd, label: 'PathUSD' }, { address: Tempo.addressLookup.usdcE, label: 'USDC.e' }, { address: Tempo.addressLookup.usdt0, label: 'USDT0' }, diff --git a/src/lib/tempo.test.ts b/src/lib/tempo.test.ts index e9ec5ca..75a5e0c 100644 --- a/src/lib/tempo.test.ts +++ b/src/lib/tempo.test.ts @@ -25,11 +25,21 @@ test('returns optional RPC URLs by chain', () => { expect(Tempo.getRpcUrl({}, 1)).toBe(undefined) }) +test('returns default token by chain', () => { + expect(Tempo.addressLookup.ousd).toBe('0x20c0000000000000000000006a37DA5C996874BE') + expect(Tempo.getDefaultTokenAddress(Tempo.chainLookup.mainnet)).toBe(Tempo.addressLookup.ousd) + expect(Tempo.getDefaultTokenAddress(Tempo.chainLookup.testnet)).toBe(Tempo.addressLookup.ousd) + expect(Tempo.getDefaultTokenAddress(Tempo.chainLookup.localnet)).toBe(Tempo.addressLookup.pathUsd) +}) + test('checks allowed tokens by chain', () => { + expect(Tempo.isAllowedToken(Tempo.chainLookup.mainnet, Tempo.addressLookup.ousd)).toBe(true) expect(Tempo.isAllowedToken(Tempo.chainLookup.mainnet, Tempo.addressLookup.pathUsd)).toBe(true) expect(Tempo.isAllowedToken(Tempo.chainLookup.mainnet, Tempo.addressLookup.usdcE)).toBe(true) expect(Tempo.isAllowedToken(Tempo.chainLookup.mainnet, Tempo.addressLookup.usdt0)).toBe(true) expect(Tempo.isAllowedToken(Tempo.chainLookup.mainnet, Tempo.addressLookup.alphaUsd)).toBe(false) + expect(Tempo.isAllowedToken(Tempo.chainLookup.testnet, Tempo.addressLookup.ousd)).toBe(true) + expect(Tempo.isAllowedToken(Tempo.chainLookup.localnet, Tempo.addressLookup.ousd)).toBe(false) expect(Tempo.isAllowedToken(Tempo.chainLookup.testnet, Tempo.addressLookup.pathUsd)).toBe(true) expect(Tempo.isAllowedToken(Tempo.chainLookup.testnet, Tempo.addressLookup.alphaUsd)).toBe(true) expect(Tempo.isAllowedToken(Tempo.chainLookup.testnet, Tempo.addressLookup.betaUsd)).toBe(true) @@ -39,6 +49,22 @@ test('checks allowed tokens by chain', () => { }) test('resolves supported token aliases', () => { + expect(Tempo.getTokenAddress(Tempo.chainLookup.mainnet, 'OUSD')).toBe(Tempo.addressLookup.ousd) + expect(Tempo.getTokenAddress(Tempo.chainLookup.mainnet, 'OpenUSD')).toBe(Tempo.addressLookup.ousd) + expect(Tempo.getTokenAddress(Tempo.chainLookup.testnet, 'ousd')).toBe(Tempo.addressLookup.ousd) + expect(Tempo.getTokenAddress(Tempo.chainLookup.localnet, 'ousd')).toBe(null) + expect(Tempo.getTokenAddress(Tempo.chainLookup.mainnet, 'usd')).toBe(Tempo.addressLookup.ousd) + expect(Tempo.getTokenAddress(Tempo.chainLookup.testnet, 'usd')).toBe(Tempo.addressLookup.ousd) + expect(Tempo.getTokenAddress(Tempo.chainLookup.localnet, 'usd')).toBe(Tempo.addressLookup.pathUsd) + expect(Tempo.getTokenAddress(Tempo.chainLookup.mainnet, 'usd', Tempo.addressLookup.pathUsd)).toBe( + Tempo.addressLookup.pathUsd, + ) + expect(Tempo.getTokenAddress(Tempo.chainLookup.mainnet, 'usd', Tempo.addressLookup.usdcE)).toBe( + Tempo.addressLookup.usdcE, + ) + expect(Tempo.getTokenAddress(Tempo.chainLookup.mainnet, 'pathUSD')).toBe( + Tempo.addressLookup.pathUsd, + ) expect(Tempo.getTokenAddress(Tempo.chainLookup.mainnet, 'USDC.e')).toBe(Tempo.addressLookup.usdcE) expect(Tempo.getTokenAddress(Tempo.chainLookup.mainnet, 'usdc')).toBe(Tempo.addressLookup.usdcE) expect(Tempo.getTokenAddress(Tempo.chainLookup.mainnet, 'USDT')).toBe(Tempo.addressLookup.usdt0) @@ -47,6 +73,10 @@ test('resolves supported token aliases', () => { }) test('formats Tempo token symbols and transaction links', () => { + expect(Tempo.getTokenMetadataFallback(Tempo.addressLookup.ousd)).toEqual({ + currency: 'USD', + symbol: 'OUSD', + }) expect(Tempo.getTokenMetadataFallback(Tempo.addressLookup.pathUsd)).toEqual({ currency: 'USD', symbol: 'PathUSD', diff --git a/src/lib/tempo.ts b/src/lib/tempo.ts index 8269263..4d99ef4 100644 --- a/src/lib/tempo.ts +++ b/src/lib/tempo.ts @@ -4,6 +4,7 @@ import { tempo, tempoLocalnet, tempoModerato } from 'viem/tempo/chains' export const addressLookup = { alphaUsd: Address.checksum('0x20c0000000000000000000000000000000000001'), betaUsd: Address.checksum('0x20c0000000000000000000000000000000000002'), + ousd: Address.checksum('0x20c0000000000000000000006a37DA5C996874BE'), pathUsd: Address.checksum('0x20c0000000000000000000000000000000000000'), thetaUsd: Address.checksum('0x20c0000000000000000000000000000000000003'), usdcE: Address.checksum('0x20C000000000000000000000b9537d11c60E8b50'), @@ -23,6 +24,11 @@ export function getChain(chainId: number) { throw new Error(`Unsupported Tempo chain ${chainId}.`) } +export function getDefaultTokenAddress(chainId: number) { + if (chainId === chainLookup.mainnet || chainId === chainLookup.testnet) return addressLookup.ousd + return addressLookup.pathUsd +} + export function getRpcUrl( env: Pick, chainId: number, @@ -63,10 +69,21 @@ export function explorerLink(chainId: number, address: string) { export function isAllowedToken(chainId: number, tokenAddress: string) { const token = Address.checksum(tokenAddress) if (chainId === chainLookup.mainnet) - return [addressLookup.pathUsd, addressLookup.usdcE, addressLookup.usdt0].some((allowed) => - Address.isEqual(token, allowed), - ) - if (chainId === chainLookup.testnet || chainId === chainLookup.localnet) + return [ + addressLookup.ousd, + addressLookup.pathUsd, + addressLookup.usdcE, + addressLookup.usdt0, + ].some((allowed) => Address.isEqual(token, allowed)) + if (chainId === chainLookup.testnet) + return [ + addressLookup.ousd, + addressLookup.pathUsd, + addressLookup.alphaUsd, + addressLookup.betaUsd, + addressLookup.thetaUsd, + ].some((allowed) => Address.isEqual(token, allowed)) + if (chainId === chainLookup.localnet) return [ addressLookup.pathUsd, addressLookup.alphaUsd, @@ -76,14 +93,22 @@ export function isAllowedToken(chainId: number, tokenAddress: string) { return false } -export function getTokenAddress(chainId: number, value: string) { +export function getTokenAddress( + chainId: number, + value: string, + defaultTokenAddress?: string | null, +) { const address = Address.validate(value) ? Address.checksum(value) : null if (address && isAllowedToken(chainId, address)) return address const normalized = value.toLowerCase().replace(/[.\-_\s]/g, '') const tokenAddress = (() => { - if (normalized === 'pathusd' || normalized === 'path' || normalized === 'usd') - return addressLookup.pathUsd + if (normalized === 'ousd' || normalized === 'openusd') return addressLookup.ousd + if (normalized === 'pathusd' || normalized === 'path') return addressLookup.pathUsd + if (normalized === 'usd') + return defaultTokenAddress + ? Address.checksum(defaultTokenAddress) + : getDefaultTokenAddress(chainId) if (normalized === 'usdce' || normalized === 'usdc') return addressLookup.usdcE if (normalized === 'usdt0' || normalized === 'usdt') return addressLookup.usdt0 if (normalized === 'alphausd' || normalized === 'alpha') return addressLookup.alphaUsd @@ -96,6 +121,8 @@ export function getTokenAddress(chainId: number, value: string) { } export function getTokenMetadataFallback(tokenAddress: string) { + if (Address.isEqual(Address.checksum(tokenAddress), addressLookup.ousd)) + return { currency: 'USD', symbol: 'OUSD' } if (Address.isEqual(Address.checksum(tokenAddress), addressLookup.pathUsd)) return { currency: 'USD', symbol: 'PathUSD' } if (Address.isEqual(Address.checksum(tokenAddress), addressLookup.alphaUsd)) diff --git a/src/lib/tip.ts b/src/lib/tip.ts index cd1bda2..c3c79e2 100644 --- a/src/lib/tip.ts +++ b/src/lib/tip.ts @@ -233,7 +233,9 @@ export async function handleTipRequest( const amount = input.amount ?? executionWorkspace.default_amount const tokenAddress = Address.checksum( - input.tokenAddress ?? executionWorkspace.default_token_address ?? Tempo.addressLookup.pathUsd, + input.tokenAddress ?? + executionWorkspace.default_token_address ?? + Tempo.getDefaultTokenAddress(executionWorkspace.chain_id), ) if (!Tempo.isAllowedToken(executionWorkspace.chain_id, tokenAddress)) return { @@ -431,7 +433,9 @@ export async function handleTipBatchRequest( if (!Number.isSafeInteger(authorizedTotalAmount) || authorizedTotalAmount <= 0) return { code: 'failed', message: 'Payment amount is too large.', ok: false } const tokenAddress = Address.checksum( - input.tokenAddress ?? executionWorkspace.default_token_address ?? Tempo.addressLookup.pathUsd, + input.tokenAddress ?? + executionWorkspace.default_token_address ?? + Tempo.getDefaultTokenAddress(executionWorkspace.chain_id), ) if (!Tempo.isAllowedToken(executionWorkspace.chain_id, tokenAddress)) return { @@ -547,7 +551,10 @@ export async function handleTipBatchRequest( chainId: executionWorkspace.chain_id, isDefaultToken: Address.isEqual( Address.checksum(tokenAddress), - Address.checksum(executionWorkspace.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + executionWorkspace.default_token_address ?? + Tempo.getDefaultTokenAddress(executionWorkspace.chain_id), + ), ), memo: input.memo, ok: true, @@ -1373,7 +1380,10 @@ async function createPendingTip( chainId: input.workspace.chain_id, isDefaultToken: Address.isEqual( Address.checksum(input.tokenAddress), - Address.checksum(input.workspace.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + input.workspace.default_token_address ?? + Tempo.getDefaultTokenAddress(input.workspace.chain_id), + ), ), memo: input.memo, ok: true, @@ -1418,7 +1428,10 @@ async function createQueuedBatchTips( recipientProviderUserId: recipient.recipientProviderUserId, senderProviderUserId: input.senderProviderUserId, }, - Address.checksum(input.workspace.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + input.workspace.default_token_address ?? + Tempo.getDefaultTokenAddress(input.workspace.chain_id), + ), ) const result = existing ?? @@ -1594,7 +1607,9 @@ async function getSentPendingTipResult( chainId: pendingTip.chain_id, isDefaultToken: Address.isEqual( Address.checksum(pendingTip.token_address), - Address.checksum(tip.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + tip.default_token_address ?? Tempo.getDefaultTokenAddress(pendingTip.chain_id), + ), ), memo: pendingTip.memo, ok: true, @@ -2086,7 +2101,10 @@ async function submitTipBatch( feePayer, isDefaultToken: Address.isEqual( Address.checksum(input.tokenAddress), - Address.checksum(input.workspace.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + input.workspace.default_token_address ?? + Tempo.getDefaultTokenAddress(input.workspace.chain_id), + ), ), memo: input.memo, ok: true, @@ -2208,7 +2226,10 @@ async function submitSignedTipBatch( idempotencyKey: input.idempotencyKey, senderProviderUserId: input.payload.senderProviderUserId, }, - Address.checksum(input.workspace.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + input.workspace.default_token_address ?? + Tempo.getDefaultTokenAddress(input.workspace.chain_id), + ), ) if (existing) return existing @@ -2343,7 +2364,10 @@ async function submitSignedTipBatch( feePayer: 'sender', isDefaultToken: Address.isEqual( Address.checksum(input.tokenAddress), - Address.checksum(input.workspace.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + input.workspace.default_token_address ?? + Tempo.getDefaultTokenAddress(input.workspace.chain_id), + ), ), memo: input.memo, ok: true, @@ -2516,7 +2540,10 @@ async function submitSignedTip( feePayer: 'sender', isDefaultToken: Address.isEqual( Address.checksum(input.tokenAddress), - Address.checksum(input.workspace.default_token_address ?? Tempo.addressLookup.pathUsd), + Address.checksum( + input.workspace.default_token_address ?? + Tempo.getDefaultTokenAddress(input.workspace.chain_id), + ), ), memo: input.memo, ok: true, diff --git a/src/lib/twitter.ts b/src/lib/twitter.ts index e6bb395..5b92028 100644 --- a/src/lib/twitter.ts +++ b/src/lib/twitter.ts @@ -1086,7 +1086,11 @@ export async function parseTwitterTip(env: Env, input: TwitterTweetInput) { let tokenAddress = null if (parsed.token) { const workspace = await ensureTwitterWorkspace(DB.create(env.DB), new Date().toISOString()) - tokenAddress = Tempo.getTokenAddress(workspace.chain_id, parsed.token) + tokenAddress = Tempo.getTokenAddress( + workspace.chain_id, + parsed.token, + workspace.default_token_address, + ) if (!tokenAddress) return null } if (Tip.isTransferMemoTooLong(parsed.memo)) return null