Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ofac implementation #96

Merged
merged 30 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
82279bb
new ofac implementation
wainola Aug 4, 2023
72a9b9d
removing model and adding status to transfer schema
wainola Aug 6, 2023
b06d4ff
linting errors
wainola Aug 6, 2023
2c2b4cf
removing unsued type
wainola Aug 6, 2023
4be5b37
restoring account schema and adding logic to store it
wainola Aug 9, 2023
cf55809
fixing type errors for transfer services and adapting to the changes …
wainola Aug 9, 2023
476a1ee
updating lock
wainola Aug 9, 2023
8bbd9c2
removing lock file
wainola Aug 9, 2023
4f48bdc
restoring lock file
wainola Aug 9, 2023
2c2ac69
pr review
wainola Aug 11, 2023
aef8a76
update lock file
wainola Aug 11, 2023
ade11a1
Merge branch 'main' into fea/ofac-impl
wainola Aug 11, 2023
6caa9ae
pr review, schema formatting, adding new function to get transfers by…
wainola Aug 17, 2023
4856952
rebase with main
wainola Aug 17, 2023
ae9b17d
account repository and saving account before transfer insertion
wainola Aug 17, 2023
021e678
removing logs
wainola Aug 18, 2023
5055063
ofac status as enum
wainola Aug 18, 2023
7e4c07f
fixing lint issues
wainola Aug 18, 2023
27afaae
storing address for substrate
wainola Aug 18, 2023
da92dde
account repository for substrate class
wainola Aug 18, 2023
429776f
fixing account insertion for substrate
wainola Aug 24, 2023
43bdf4a
fixin test
wainola Aug 24, 2023
1c36e9f
Merge branch 'main' into fea/ofac-impl
wainola Aug 24, 2023
be75e8a
test passing after rebase with main
wainola Aug 24, 2023
565c2e7
adding try catch block
wainola Aug 24, 2023
0c0b790
rebase with main
wainola Aug 24, 2023
dc91842
fix on passing parameters
wainola Aug 24, 2023
af1aa35
pr review last comments
wainola Aug 30, 2023
f56104b
fixing linter detail
wainola Aug 30, 2023
8c9eff8
solve conflict
wainola Sep 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,22 @@ generator client {

model Transfer {
id String @id @default(auto()) @map("_id") @db.ObjectId
depositNonce Int
depositNonce Int
resource Resource? @relation(fields: [resourceID], references: [id])
resourceID String?
fromDomain Domain @relation(name: "fromDomainRelation", fields: [fromDomainId], references: [id])
fromDomainId Int
fromDomainId Int
toDomain Domain? @relation(name: "toDomainRelation", fields: [toDomainId], references: [id])
toDomainId Int?
sender String?
destination String?
amount String?
timestamp DateTime?
status TransferStatus
deposit Deposit?
execution Execution?
fee Fee?
account Account? @relation(name: "accountRelation", fields: [accountId], references: [id])
accountId String?

@@unique(fields: [depositNonce, fromDomainId, toDomainId], name: "transferId")
}
Expand All @@ -37,14 +38,20 @@ enum TransferStatus {
failed
}

model Account {
id String @id @map("_id")
addressStatus String
Transfer Transfer[] @relation(name: "accountRelation")
}

model Resource {
id String @id @map("_id")
type String
transfers Transfer[]
}

model Domain {
id Int @id @map("_id")
id Int @id @map("_id")
name String

lastIndexedBlock String
Expand Down
6 changes: 6 additions & 0 deletions src/Interfaces/TransfersInterfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,11 @@ export type IncludedQueryParams = {
blockNumber: boolean
}
}
account: {
select: {
address: boolean
addressStatus: boolean
}
}
}
}
13 changes: 12 additions & 1 deletion src/indexer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import ExecutionRepository from "./repository/execution"
import FeeRepository from "./repository/fee"
import ResourceRepository from "./repository/resource"
import { healthcheckRoute } from "./healthcheck"
import { OfacComplianceService } from "./services/evmIndexer/ofac"

interface DomainIndexer {
listenToEvents(): Promise<void>
Expand Down Expand Up @@ -38,6 +39,7 @@ init()

async function init(): Promise<Array<DomainIndexer>> {
const sharedConfig = await getSharedConfig(process.env.SHARED_CONFIG_URL!)
const ofacComplianceService = new OfacComplianceService(process.env.CHAIN_ANALYSIS_URL!, process.env.CHAIN_ANALYSIS_API_KEY!)

const domainRepository = new DomainRepository()
const depositRepository = new DepositRepository()
Expand Down Expand Up @@ -79,7 +81,16 @@ async function init(): Promise<Array<DomainIndexer>> {
}
} else if (domain.type == DomainTypes.EVM) {
try {
const evmIndexer = new EvmIndexer(domain, rpcURL, domainRepository, depositRepository, transferRepository, executionRepository, feeRepository)
const evmIndexer = new EvmIndexer(
domain,
rpcURL,
domainRepository,
depositRepository,
transferRepository,
executionRepository,
feeRepository,
ofacComplianceService,
)
domainIndexers.push(evmIndexer)
} catch (err) {
logger.error(`error on domain: ${domain.id}... skipping`)
Expand Down
73 changes: 60 additions & 13 deletions src/indexer/repository/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,31 @@ import { PrismaClient, Transfer, TransferStatus } from "@prisma/client"
import { ObjectId } from "mongodb"
import { DecodedDepositLog, DecodedFailedHandlerExecution, DecodedProposalExecutionLog } from "../services/evmIndexer/evmTypes"

export type TransferMetadataeta = {
export type TransferMetadata = {
id: string
depositNonce: number
sender: string
amount: string
destination: string
fromDomainId: string
toDomainId: string
resourceID: string

timestamp: Date
resource: {
connect: {
id: string
}
}
fromDomain: {
connect: {
id: string
id: number
}
}
toDomain: {
connect: {
id: number
}
}
account?: {
connect: {
id: string
}
Expand All @@ -31,11 +35,9 @@ export type TransferMetadataeta = {
class TransferRepository {
public transfer = new PrismaClient().transfer

public async insertDepositTransfer(decodedLog: DecodedDepositLog): Promise<Transfer> {
public async insertDepositTransfer(decodedLog: DecodedDepositLog, senderStatus: string): Promise<Transfer> {
const transferData = {
id: new ObjectId().toString(),
wainola marked this conversation as resolved.
Show resolved Hide resolved
depositNonce: decodedLog.depositNonce,
sender: decodedLog.sender,
amount: decodedLog.amount,
destination: decodedLog.destination,
status: TransferStatus.pending,
Expand All @@ -56,7 +58,39 @@ class TransferRepository {
},
timestamp: new Date(decodedLog.timestamp * 1000), // this is only being used by evm service
}
return await this.transfer.create({ data: transferData })

return await this.transfer.upsert({
where: {
transferId: {
depositNonce: decodedLog.depositNonce,
fromDomainId: Number(decodedLog.fromDomainId),
toDomainId: Number(decodedLog.toDomainId),
},
},
update: {
...transferData,
account: {
connect: {
id: decodedLog.sender,
},
},
},
create: {
id: new ObjectId().toString(),
...transferData,
account: {
connectOrCreate: {
where: {
id: decodedLog.sender,
},
create: {
id: decodedLog.sender,
addressStatus: senderStatus,
},
},
},
},
})
}

public async insertSubstrateDepositTransfer(
Expand Down Expand Up @@ -106,7 +140,6 @@ class TransferRepository {
id: new ObjectId().toString(),
depositNonce: depositNonce,
status: TransferStatus.executed,
sender: null,
destination: null,
amount: null,
resource: resourceID !== null ? resourceID : undefined,
Expand Down Expand Up @@ -152,19 +185,21 @@ class TransferRepository {
public async updateTransfer(
{
depositNonce,
sender,
amount,
destination,
resourceID,
fromDomainId,
toDomainId,
timestamp,
}: Pick<DecodedDepositLog, "depositNonce" | "sender" | "amount" | "destination" | "resourceID" | "fromDomainId" | "toDomainId" | "timestamp">,
}: Pick<
DecodedDepositLog,
"depositNonce" | "amount" | "destination" | "resourceID" | "fromDomainId" | "toDomainId" | "timestamp" | "senderStatus"
>,
id: string,
accountId?: string,
): Promise<Transfer> {
const transferData = {
let transferData = {
depositNonce: depositNonce,
sender: sender,
amount: amount,
destination: destination,
resource: {
Expand All @@ -183,7 +218,19 @@ class TransferRepository {
},
},
timestamp: new Date(timestamp),
} as Pick<TransferMetadata, "depositNonce" | "amount" | "destination" | "resource" | "fromDomain" | "toDomain" | "timestamp" | "account">

if (accountId) {
wainola marked this conversation as resolved.
Show resolved Hide resolved
transferData = {
...transferData,
account: {
connect: {
id: accountId,
},
},
}
}

return await this.transfer.update({ where: { id: id }, data: transferData })
}

Expand Down
8 changes: 7 additions & 1 deletion src/indexer/services/evmIndexer/evmIndexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import FeeRepository from "../../repository/fee"
import { logger } from "../../../utils/logger"
import { getLogs } from "./evmfilter"
import { decodeLogs } from "./evmEventParser"
import { OfacComplianceService } from "./ofac"

const BLOCK_TIME = 15000

Expand All @@ -27,6 +28,7 @@ export class EvmIndexer {
private domain: Domain
private resourceMap: Map<string, EvmResource>
private stopped = false
private ofacComplianceService: OfacComplianceService

constructor(
domain: Domain,
Expand All @@ -36,6 +38,7 @@ export class EvmIndexer {
transferRepository: TransferRepository,
executionRepository: ExecutionRepository,
feeRepository: FeeRepository,
ofacComplianceService: OfacComplianceService,
) {
this.provider = new ethers.JsonRpcProvider(rpcURL)
this.domainRepository = domainRepository
Expand All @@ -44,6 +47,7 @@ export class EvmIndexer {
this.transferRepository = transferRepository
this.executionRepository = executionRepository
this.feeRepository = feeRepository
this.ofacComplianceService = ofacComplianceService

this.resourceMap = new Map<string, EvmResource>()
domain.resources.map((resource: EvmResource) => this.resourceMap.set(resource.resourceId, resource))
Expand Down Expand Up @@ -98,7 +102,9 @@ export class EvmIndexer {

const transferMap = new Map<string, string>()
await Promise.all(
decodedLogs.deposit.map(async decodedLog => saveDepositLogs(decodedLog, this.transferRepository, this.depositRepository, transferMap)),
decodedLogs.deposit.map(async decodedLog =>
saveDepositLogs(decodedLog, this.transferRepository, this.depositRepository, transferMap, this.ofacComplianceService),
),
)

await Promise.all(decodedLogs.feeCollected.map(async fee => saveFeeLogs(fee, transferMap, this.feeRepository)))
Expand Down
1 change: 1 addition & 0 deletions src/indexer/services/evmIndexer/evmTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type DecodedDepositLog = {
handlerResponse: string
transferType: string
amount: string
senderStatus?: string
}

export type DecodedProposalExecutionLog = {
Expand Down
34 changes: 34 additions & 0 deletions src/indexer/services/evmIndexer/ofac/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import url from "url"

type ChainAnalysisIdentIfication = {
category: string
name: string
description: string
url: string
}

type ChainAnalysisResponse = {
identifications: Array<ChainAnalysisIdentIfication> | []
}

export class OfacComplianceService {
private chainAnalisysUrl: string
private chainAnalisysApiKey: string

constructor(chainAnalysisUrl: string, chainAnalisysApiKey: string) {
this.chainAnalisysUrl = chainAnalysisUrl
this.chainAnalisysApiKey = chainAnalisysApiKey
}

public async checkSanctionedAddress(address: string): Promise<string> {
wainola marked this conversation as resolved.
Show resolved Hide resolved
const urlToUse = url.resolve(this.chainAnalisysUrl, address)
const response = await fetch(urlToUse, {
headers: {
"X-API-Key": `${this.chainAnalisysApiKey}`,
Accept: "application/json",
},
})
const data = (await response.json()) as ChainAnalysisResponse
return data.identifications.length ? "ofac" : ""
}
}
11 changes: 9 additions & 2 deletions src/indexer/utils/evm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
import { getERC20Contract } from "../../services/contract"
import FeeRepository from "../../repository/fee"
import ExecutionRepository from "../../repository/execution"
import { OfacComplianceService } from "../../services/evmIndexer/ofac"

export const nativeTokenAddress = "0x0000000000000000000000000000000000000000"

Expand Down Expand Up @@ -196,16 +197,22 @@ export async function saveDepositLogs(
transferRepository: TransferRepository,
depositRepository: DepositRepository,
transferMap: Map<string, string>,
ofacComplianceService: OfacComplianceService,
): Promise<void> {
let transfer = await transferRepository.findTransfer(decodedLog.depositNonce, Number(decodedLog.fromDomainId), Number(decodedLog.toDomainId))

const { sender } = decodedLog

const senderStatus = await ofacComplianceService.checkSanctionedAddress(sender)

if (!transfer) {
transfer = await transferRepository.insertDepositTransfer(decodedLog)
transfer = await transferRepository.insertDepositTransfer(decodedLog, senderStatus)
wainola marked this conversation as resolved.
Show resolved Hide resolved
} else {
const dataToSave = {
...decodedLog,
timestamp: decodedLog.timestamp * 1000,
}
await transferRepository.updateTransfer(dataToSave, transfer.id)
await transferRepository.updateTransfer(dataToSave, transfer.id, transfer.accountId!)
}

const deposit = {
Expand Down
1 change: 0 additions & 1 deletion src/indexer/utils/substrate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export async function saveDeposit(
if (transfer) {
const dataTransferToUpdate = {
depositNonce: Number(depositNonce),
wainola marked this conversation as resolved.
Show resolved Hide resolved
sender,
amount: decodedAmount,
resourceID: resourceId,
fromDomainId: originDomainId.toString(),
Expand Down
Loading
Loading