Skip to content

Commit

Permalink
Adjust asset transfer schema validation to avoid anys
Browse files Browse the repository at this point in the history
The new approach validates the response at the highest level and then
translates those types down into the remaining data handling.
  • Loading branch information
Shadowfiend committed Oct 13, 2021
1 parent 2fdd13d commit 1e1f46f
Showing 1 changed file with 36 additions and 24 deletions.
60 changes: 36 additions & 24 deletions background/lib/alchemy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,20 @@ const alchemyAssetTransferJTD = {
additionalProperties: true,
} as const

type AlchemyAssetTransferResponse = JTDDataType<typeof alchemyAssetTransferJTD>
const alchemyGetAssetTransfersJTD = {
properties: {
transfers: {
elements: alchemyAssetTransferJTD,
},
},
} as const

type AlchemyAssetTransferResponse = JTDDataType<
typeof alchemyGetAssetTransfersJTD
>

const isValidAlchemyAssetTransferResponse =
ajv.compile<AlchemyAssetTransferResponse>(alchemyAssetTransferJTD)
ajv.compile<AlchemyAssetTransferResponse>(alchemyGetAssetTransfersJTD)

/**
* Use Alchemy's getAssetTransfers call to get historical transfers for an
Expand Down Expand Up @@ -82,51 +92,53 @@ export async function getAssetTransfers(
]),
])

return rpcResponses[0].transfers
.concat(rpcResponses[1].transfers)
.map((json: unknown) => {
if (!isValidAlchemyAssetTransferResponse(json)) {
logger.warn(
"Alchemy asset transfer response didn't validate, did the API change?",
json
)
return null
return rpcResponses
.flatMap((jsonResponse: unknown) => {
if (isValidAlchemyAssetTransferResponse(jsonResponse)) {
return jsonResponse.transfers
}

logger.warn(
"Alchemy asset transfer response didn't validate, did the API change?",
jsonResponse
)
return []
})
.map((transfer) => {
// TODO handle NFT asset lookup properly
if (json.erc721TokenId) {
if (transfer.erc721TokenId) {
return null
}

// we don't care about 0-value transfers
// TODO handle nonfungible assets properly
// TODO handle assets with a contract address and no name
if (
!json.rawContract ||
!json.rawContract.value ||
!json.rawContract.decimal ||
!json.asset
!transfer.rawContract ||
!transfer.rawContract.value ||
!transfer.rawContract.decimal ||
!transfer.asset
) {
return null
}

const asset = !json.rawContract.address
const asset = !transfer.rawContract.address
? {
contractAddress: json.rawContract.address,
decimals: Number(BigInt(json.rawContract.decimal)),
symbol: json.asset,
contractAddress: transfer.rawContract.address,
decimals: Number(BigInt(transfer.rawContract.decimal)),
symbol: transfer.asset,
homeNetwork: ETHEREUM, // TODO is this true?
}
: ETH
return {
network: ETHEREUM, // TODO make this friendly across other networks
assetAmount: {
asset,
amount: BigInt(json.rawContract.value),
amount: BigInt(transfer.rawContract.value),
},
txHash: json.hash,
to: json.to,
from: json.from,
txHash: transfer.hash,
to: transfer.to,
from: transfer.from,
dataSource: "alchemy",
} as AssetTransfer
})
Expand Down

0 comments on commit 1e1f46f

Please sign in to comment.