Skip to content

Commit

Permalink
Add Kado
Browse files Browse the repository at this point in the history
  • Loading branch information
paullinator committed Mar 9, 2024
1 parent 2ea8e41 commit b621be8
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# edge-reports-server

## Unreleased

- added: Kado reporting
4 changes: 4 additions & 0 deletions src/demo/partners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ export default {
type: 'fiat',
color: '#6381F5'
},
kado: {
type: 'fiat',
color: '#9AB4F9'
},
letsexchange: {
type: 'swap',
color: '#1A1438'
Expand Down
210 changes: 210 additions & 0 deletions src/partners/kado.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import {
asArray,
asBoolean,
asDate,
asMaybe,
asNumber,
asObject,
asOptional,
asString,
asValue
} from 'cleaners'

import {
asStandardPluginParams,
PartnerPlugin,
PluginParams,
PluginResult,
StandardTx,
Status
} from '../types'
import { datelog, retryFetch, smartIsoDateFromTimestamp, snooze } from '../util'

// Define cleaner for individual transactions in onRamps and offRamps
const asTxType = asValue('buy', 'sell')

const asTransaction = asObject({
_id: asString,
walletAddress: asString,
createdAt: asDate,
type: asTxType,
walletType: asString,
cryptoCurrency: asString,
network: asString
})

const asOnRampTx = asObject({
...asTransaction.shape,
receiveUnitCount: asNumber,
paidAmountUsd: asNumber,
paymentMethod: asString
})

const asOffRampTx = asObject({
...asTransaction.shape,
depositUnitCount: asNumber,
receiveUsd: asNumber
// disburseMethod: asString
})

// Define cleaner for the main data structure
const asResponse = asObject({
success: asBoolean,
// message: asString,
data: asObject({
onRamps: asArray(asOnRampTx),
offRamps: asArray(asOffRampTx)
})
})

const MAX_RETRIES = 5
const QUERY_LOOKBACK = 1000 * 60 * 60 * 24 * 30 // 30 days
const QUERY_TIME_BLOCK_MS = QUERY_LOOKBACK

// const statusMap: { [key in PartnerStatuses]: Status } = {
// DONE: 'complete',
// other: 'other'
// }

export async function queryKado(
pluginParams: PluginParams
): Promise<PluginResult> {
const { settings, apiKeys } = asStandardPluginParams(pluginParams)
const { apiKey } = apiKeys
let { latestIsoDate } = settings

// API doesn't currently support paging by date but leave this in here
// for when it does
if (latestIsoDate === '2018-01-01T00:00:00.000Z') {
latestIsoDate = new Date('2024-01-01T00:00:00.000Z').toISOString()
}

let lastCheckedTimestamp = new Date(latestIsoDate).getTime() - QUERY_LOOKBACK
if (lastCheckedTimestamp < 0) lastCheckedTimestamp = 0

const ssFormatTxs: StandardTx[] = []
let retry = 0
let startTime = lastCheckedTimestamp

// No looping since all txs are returned in one call for now
// while (true)
{
const endTime = startTime + QUERY_TIME_BLOCK_MS
const now = Date.now()

const startTimeS = startTime / 1000
const endTimeS = endTime / 1000

const url = `https://api.kado.money/v2/organizations/${apiKey}/orders`
try {
const response = await retryFetch(url)
if (!response.ok) {
const text = await response.text()
throw new Error(text)
}
const jsonObj = await response.json()
const transferResults = asResponse(jsonObj)
const { onRamps, offRamps } = transferResults.data
for (const tx of onRamps) {
const {
_id,
createdAt,
cryptoCurrency,
paidAmountUsd,
receiveUnitCount,
walletAddress
} = tx
const { isoDate, timestamp } = smartIsoDateFromTimestamp(
createdAt.toISOString()
)
const ssTx: StandardTx = {
status: 'complete',
orderId: _id,
depositTxid: undefined,
depositAddress: undefined,
depositCurrency: 'USD',
depositAmount: paidAmountUsd,
payoutTxid: undefined,
payoutAddress: walletAddress,
payoutCurrency: cryptoCurrency,
payoutAmount: receiveUnitCount,
timestamp,
isoDate,
usdValue: paidAmountUsd,
rawTx: tx
}
ssFormatTxs.push(ssTx)
if (ssTx.isoDate > latestIsoDate) {
latestIsoDate = ssTx.isoDate
}
}
for (const tx of offRamps) {
const {
_id,
createdAt,
cryptoCurrency,
depositUnitCount,
receiveUsd
} = tx
const { isoDate, timestamp } = smartIsoDateFromTimestamp(
createdAt.toISOString()
)
const ssTx: StandardTx = {
status: 'complete',
orderId: _id,
depositTxid: undefined,
depositAddress: undefined,
depositCurrency: cryptoCurrency,
depositAmount: depositUnitCount,
payoutTxid: undefined,
payoutAddress: undefined,
payoutCurrency: 'USD',
payoutAmount: receiveUsd,
timestamp,
isoDate,
usdValue: receiveUsd,
rawTx: tx
}
ssFormatTxs.push(ssTx)
if (ssTx.isoDate > latestIsoDate) {
latestIsoDate = ssTx.isoDate
}
}
const endDate = new Date(endTime)
startTime = endDate.getTime()
datelog(
`Kado endDate:${new Date(
endDate
).toISOString()} latestIsoDate:${latestIsoDate}`
)
if (endTime > now) {
// break
}
retry = 0
} catch (e) {
datelog(e)
// Retry a few times with time delay to prevent throttling
retry++
if (retry <= MAX_RETRIES) {
datelog(`Snoozing ${60 * retry}s`)
await snooze(61000 * retry)
} else {
// We can safely save our progress since we go from oldest to newest.
// break
}
}
// await snooze(3000)
}

const out = {
settings: { latestIsoDate },
transactions: ssFormatTxs
}
return out
}

export const kado: PartnerPlugin = {
queryFunc: queryKado,
pluginName: 'Kado',
pluginId: 'kado'
}
2 changes: 2 additions & 0 deletions src/queryEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { gebo } from './partners/gebo'
import { godex } from './partners/godex'
import { ioniaGiftCards } from './partners/ioniagiftcard'
import { ioniaVisaRewards } from './partners/ioniavisarewards'
import { kado } from './partners/kado'
import { letsexchange } from './partners/letsexchange'
import { libertyx } from './partners/libertyx'
import { moonpay } from './partners/moonpay'
Expand Down Expand Up @@ -50,6 +51,7 @@ const plugins = [
godex,
ioniaVisaRewards,
ioniaGiftCards,
kado,
letsexchange,
libertyx,
moonpay,
Expand Down

0 comments on commit b621be8

Please sign in to comment.