@develit-services/blockchain 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/database/schema.cjs +2 -1
- package/dist/database/schema.d.cts +1 -1
- package/dist/database/schema.d.mts +1 -1
- package/dist/database/schema.d.ts +1 -1
- package/dist/database/schema.mjs +1 -1
- package/dist/export/worker.cjs +100 -7
- package/dist/export/worker.d.cts +4 -5
- package/dist/export/worker.d.mts +4 -5
- package/dist/export/worker.d.ts +4 -5
- package/dist/export/worker.mjs +100 -7
- package/dist/export/workflows.cjs +124 -45
- package/dist/export/workflows.mjs +125 -46
- package/dist/export/wrangler.cjs +8 -4
- package/dist/export/wrangler.d.cts +7 -4
- package/dist/export/wrangler.d.mts +7 -4
- package/dist/export/wrangler.d.ts +7 -4
- package/dist/export/wrangler.mjs +8 -4
- package/dist/shared/blockchain.0tUJ62WT.mjs +6 -0
- package/dist/shared/blockchain.4Hzh__vM.d.ts +61 -0
- package/dist/shared/blockchain.B49xpPZ0.cjs +36 -0
- package/dist/shared/blockchain.BBvwu2_7.cjs +39 -0
- package/dist/shared/blockchain.BDDFE27V.d.mts +61 -0
- package/dist/shared/blockchain.B_Tqqlia.mjs +31 -0
- package/dist/shared/{blockchain.BOT9dDRh.d.cts → blockchain.C1Jdisxn.d.cts} +9 -4
- package/dist/shared/{blockchain.BOT9dDRh.d.mts → blockchain.C1Jdisxn.d.mts} +9 -4
- package/dist/shared/{blockchain.BOT9dDRh.d.ts → blockchain.C1Jdisxn.d.ts} +9 -4
- package/dist/shared/blockchain.Cx60lJ0c.d.cts +566 -0
- package/dist/shared/blockchain.Cx60lJ0c.d.mts +566 -0
- package/dist/shared/blockchain.Cx60lJ0c.d.ts +566 -0
- package/dist/shared/blockchain.DN735AwB.cjs +8 -0
- package/dist/shared/blockchain.DbsOmkkX.d.cts +61 -0
- package/dist/shared/blockchain._wwKu1qP.mjs +35 -0
- package/dist/types.cjs +4 -1
- package/dist/types.d.cts +35 -2
- package/dist/types.d.mts +35 -2
- package/dist/types.d.ts +35 -2
- package/dist/types.mjs +2 -1
- package/package.json +1 -1
- package/dist/shared/blockchain.55Jm5hWs.mjs +0 -11
- package/dist/shared/blockchain.D63utaAU.cjs +0 -14
- package/dist/shared/blockchain.DmhmTTL_.mjs +0 -17
- package/dist/shared/blockchain.JxC5JMLI.cjs +0 -20
- package/dist/shared/blockchain.QCUmm8Hp.d.cts +0 -12
- package/dist/shared/blockchain.QCUmm8Hp.d.mts +0 -12
- package/dist/shared/blockchain.QCUmm8Hp.d.ts +0 -12
- package/dist/shared/blockchain.f4eN2PFQ.d.cts +0 -97
- package/dist/shared/blockchain.f4eN2PFQ.d.mts +0 -97
- package/dist/shared/blockchain.f4eN2PFQ.d.ts +0 -97
package/dist/database/schema.cjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const database_schema = require('../shared/blockchain.
|
|
3
|
+
const database_schema = require('../shared/blockchain.BBvwu2_7.cjs');
|
|
4
4
|
require('@develit-io/backend-sdk');
|
|
5
5
|
require('drizzle-orm/sqlite-core');
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
exports.address = database_schema.address;
|
|
10
|
+
exports.transaction = database_schema.transaction;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { a as address } from '../shared/blockchain.
|
|
1
|
+
export { a as address, t as transaction } from '../shared/blockchain.Cx60lJ0c.cjs';
|
|
2
2
|
import 'drizzle-orm/sqlite-core';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { a as address } from '../shared/blockchain.
|
|
1
|
+
export { a as address, t as transaction } from '../shared/blockchain.Cx60lJ0c.mjs';
|
|
2
2
|
import 'drizzle-orm/sqlite-core';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { a as address } from '../shared/blockchain.
|
|
1
|
+
export { a as address, t as transaction } from '../shared/blockchain.Cx60lJ0c.js';
|
|
2
2
|
import 'drizzle-orm/sqlite-core';
|
package/dist/database/schema.mjs
CHANGED
package/dist/export/worker.cjs
CHANGED
|
@@ -3,15 +3,89 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
const backendSdk = require('@develit-io/backend-sdk');
|
|
6
|
-
const
|
|
7
|
-
require('
|
|
8
|
-
const syncAddress = require('../shared/blockchain.
|
|
6
|
+
const viem = require('viem');
|
|
7
|
+
const drizzle = require('../shared/blockchain.DN735AwB.cjs');
|
|
8
|
+
const syncAddress = require('../shared/blockchain.B49xpPZ0.cjs');
|
|
9
9
|
const cloudflare_workers = require('cloudflare:workers');
|
|
10
10
|
const d1 = require('drizzle-orm/d1');
|
|
11
|
+
require('../shared/blockchain.BBvwu2_7.cjs');
|
|
11
12
|
require('drizzle-orm/sqlite-core');
|
|
13
|
+
require('drizzle-orm');
|
|
12
14
|
require('zod');
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
class IBlockchainConnector {
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class AlchemyConnector extends IBlockchainConnector {
|
|
20
|
+
constructor(config) {
|
|
21
|
+
super();
|
|
22
|
+
this.connectorKey = "ALCHEMY";
|
|
23
|
+
this.client = null;
|
|
24
|
+
this.rpcUrl = config.rpcUrl;
|
|
25
|
+
}
|
|
26
|
+
createClient() {
|
|
27
|
+
if (!this.client) {
|
|
28
|
+
this.client = viem.createPublicClient({
|
|
29
|
+
transport: viem.http(this.rpcUrl)
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return this.client;
|
|
33
|
+
}
|
|
34
|
+
async getTransaction(txHash) {
|
|
35
|
+
const client = this.createClient();
|
|
36
|
+
const [tx, txError] = await backendSdk.useResult(
|
|
37
|
+
client.getTransaction({ hash: txHash })
|
|
38
|
+
);
|
|
39
|
+
if (txError || !tx) {
|
|
40
|
+
throw backendSdk.createInternalError(txError);
|
|
41
|
+
}
|
|
42
|
+
let status = "pending";
|
|
43
|
+
let gasUsed = null;
|
|
44
|
+
let timestamp = null;
|
|
45
|
+
if (tx.blockNumber) {
|
|
46
|
+
const [receipt, receiptError] = await backendSdk.useResult(
|
|
47
|
+
client.getTransactionReceipt({ hash: txHash })
|
|
48
|
+
);
|
|
49
|
+
if (receiptError || !receipt) {
|
|
50
|
+
throw backendSdk.createInternalError(receiptError);
|
|
51
|
+
}
|
|
52
|
+
const [block, blockError] = await backendSdk.useResult(
|
|
53
|
+
client.getBlock({ blockNumber: tx.blockNumber })
|
|
54
|
+
);
|
|
55
|
+
if (blockError || !block) {
|
|
56
|
+
throw backendSdk.createInternalError(blockError);
|
|
57
|
+
}
|
|
58
|
+
status = receipt.status === "success" ? "success" : "reverted";
|
|
59
|
+
gasUsed = receipt.gasUsed.toString();
|
|
60
|
+
timestamp = Number(block.timestamp) * 1e3;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
hash: tx.hash,
|
|
64
|
+
from: tx.from,
|
|
65
|
+
to: tx.to,
|
|
66
|
+
value: tx.value.toString(),
|
|
67
|
+
blockNumber: tx.blockNumber?.toString() ?? null,
|
|
68
|
+
blockHash: tx.blockHash ?? null,
|
|
69
|
+
gasPrice: tx.gasPrice?.toString() ?? null,
|
|
70
|
+
gas: tx.gas.toString(),
|
|
71
|
+
nonce: tx.nonce,
|
|
72
|
+
transactionIndex: tx.transactionIndex,
|
|
73
|
+
status,
|
|
74
|
+
gasUsed,
|
|
75
|
+
timestamp
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async getTransactionReceipt(txHash) {
|
|
79
|
+
const client = this.createClient();
|
|
80
|
+
const [receipt, error] = await backendSdk.useResult(
|
|
81
|
+
client.getTransactionReceipt({ hash: txHash })
|
|
82
|
+
);
|
|
83
|
+
if (error || !receipt) {
|
|
84
|
+
throw backendSdk.createInternalError(error);
|
|
85
|
+
}
|
|
86
|
+
return receipt;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
15
89
|
|
|
16
90
|
var __defProp = Object.defineProperty;
|
|
17
91
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -28,20 +102,36 @@ let BlockchainServiceBase = class extends backendSdk.develitWorker(
|
|
|
28
102
|
) {
|
|
29
103
|
constructor(ctx, env) {
|
|
30
104
|
super(ctx, env);
|
|
31
|
-
this.db = d1.drizzle(this.env.BLOCKCHAIN_D1, { schema: tables });
|
|
105
|
+
this.db = d1.drizzle(this.env.BLOCKCHAIN_D1, { schema: drizzle.tables });
|
|
32
106
|
}
|
|
33
107
|
async syncAddress(input) {
|
|
34
108
|
return this.handleAction(
|
|
35
109
|
{ data: input, schema: syncAddress.syncAddressInputSchema },
|
|
36
110
|
{ successMessage: "Address sync workflow started" },
|
|
37
111
|
async ({ addressId }) => {
|
|
38
|
-
await this.env.SYNC_ADDRESS_TRANSACTIONS_WORKFLOW.create({
|
|
112
|
+
const instance = await this.env.SYNC_ADDRESS_TRANSACTIONS_WORKFLOW.create({
|
|
39
113
|
id: addressId,
|
|
40
114
|
params: {
|
|
41
115
|
addressId
|
|
42
116
|
}
|
|
43
117
|
});
|
|
44
|
-
return {
|
|
118
|
+
return {
|
|
119
|
+
instanceId: instance.id,
|
|
120
|
+
details: await instance.status()
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
async getTransaction(input) {
|
|
126
|
+
return this.handleAction(
|
|
127
|
+
{ data: input, schema: syncAddress.getTransactionInputSchema },
|
|
128
|
+
{ successMessage: "Transaction retrieved successfully." },
|
|
129
|
+
async ({ txHash }) => {
|
|
130
|
+
const rpcUrl = (await this.env.SECRETS_STORE.get({
|
|
131
|
+
secretName: "BLOCKCHAIN_SERVICE_RPC_URL"
|
|
132
|
+
})).data?.secretValue || "";
|
|
133
|
+
const connector = new AlchemyConnector({ rpcUrl });
|
|
134
|
+
return connector.getTransaction(txHash);
|
|
45
135
|
}
|
|
46
136
|
);
|
|
47
137
|
}
|
|
@@ -49,6 +139,9 @@ let BlockchainServiceBase = class extends backendSdk.develitWorker(
|
|
|
49
139
|
__decorateClass([
|
|
50
140
|
backendSdk.action("sync-address")
|
|
51
141
|
], BlockchainServiceBase.prototype, "syncAddress", 1);
|
|
142
|
+
__decorateClass([
|
|
143
|
+
backendSdk.action("get-transaction")
|
|
144
|
+
], BlockchainServiceBase.prototype, "getTransaction", 1);
|
|
52
145
|
BlockchainServiceBase = __decorateClass([
|
|
53
146
|
backendSdk.service("blockchain")
|
|
54
147
|
], BlockchainServiceBase);
|
package/dist/export/worker.d.cts
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import * as _develit_io_backend_sdk from '@develit-io/backend-sdk';
|
|
2
2
|
import { IRPCResponse } from '@develit-io/backend-sdk';
|
|
3
|
-
import {
|
|
4
|
-
import { S as SyncAddressInput, a as SyncAddressOutput } from '../shared/blockchain.QCUmm8Hp.cjs';
|
|
3
|
+
import { t as tables, S as SyncAddressInput, a as SyncAddressOutput, G as GetTransactionInput, b as GetTransactionOutput } from '../shared/blockchain.DbsOmkkX.cjs';
|
|
5
4
|
import { WorkerEntrypoint } from 'cloudflare:workers';
|
|
6
5
|
import { DrizzleD1Database } from 'drizzle-orm/d1';
|
|
7
|
-
import 'drizzle-orm/sqlite-core';
|
|
8
6
|
import 'zod';
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
import '../shared/blockchain.Cx60lJ0c.cjs';
|
|
8
|
+
import 'drizzle-orm/sqlite-core';
|
|
11
9
|
|
|
12
10
|
declare const BlockchainServiceBase_base: (abstract new (ctx: ExecutionContext, env: BlockchainEnv) => WorkerEntrypoint<BlockchainEnv, {}>) & (abstract new (...args: any[]) => _develit_io_backend_sdk.DevelitWorkerMethods);
|
|
13
11
|
declare class BlockchainServiceBase extends BlockchainServiceBase_base {
|
|
14
12
|
readonly db: DrizzleD1Database<typeof tables>;
|
|
15
13
|
constructor(ctx: ExecutionContext, env: BlockchainEnv);
|
|
16
14
|
syncAddress(input: SyncAddressInput): Promise<IRPCResponse<SyncAddressOutput>>;
|
|
15
|
+
getTransaction(input: GetTransactionInput): Promise<IRPCResponse<GetTransactionOutput>>;
|
|
17
16
|
}
|
|
18
17
|
declare function defineBlockchainService(): new (ctx: ExecutionContext, env: BlockchainEnv) => BlockchainServiceBase;
|
|
19
18
|
|
package/dist/export/worker.d.mts
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import * as _develit_io_backend_sdk from '@develit-io/backend-sdk';
|
|
2
2
|
import { IRPCResponse } from '@develit-io/backend-sdk';
|
|
3
|
-
import {
|
|
4
|
-
import { S as SyncAddressInput, a as SyncAddressOutput } from '../shared/blockchain.QCUmm8Hp.mjs';
|
|
3
|
+
import { t as tables, S as SyncAddressInput, a as SyncAddressOutput, G as GetTransactionInput, b as GetTransactionOutput } from '../shared/blockchain.BDDFE27V.mjs';
|
|
5
4
|
import { WorkerEntrypoint } from 'cloudflare:workers';
|
|
6
5
|
import { DrizzleD1Database } from 'drizzle-orm/d1';
|
|
7
|
-
import 'drizzle-orm/sqlite-core';
|
|
8
6
|
import 'zod';
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
import '../shared/blockchain.Cx60lJ0c.mjs';
|
|
8
|
+
import 'drizzle-orm/sqlite-core';
|
|
11
9
|
|
|
12
10
|
declare const BlockchainServiceBase_base: (abstract new (ctx: ExecutionContext, env: BlockchainEnv) => WorkerEntrypoint<BlockchainEnv, {}>) & (abstract new (...args: any[]) => _develit_io_backend_sdk.DevelitWorkerMethods);
|
|
13
11
|
declare class BlockchainServiceBase extends BlockchainServiceBase_base {
|
|
14
12
|
readonly db: DrizzleD1Database<typeof tables>;
|
|
15
13
|
constructor(ctx: ExecutionContext, env: BlockchainEnv);
|
|
16
14
|
syncAddress(input: SyncAddressInput): Promise<IRPCResponse<SyncAddressOutput>>;
|
|
15
|
+
getTransaction(input: GetTransactionInput): Promise<IRPCResponse<GetTransactionOutput>>;
|
|
17
16
|
}
|
|
18
17
|
declare function defineBlockchainService(): new (ctx: ExecutionContext, env: BlockchainEnv) => BlockchainServiceBase;
|
|
19
18
|
|
package/dist/export/worker.d.ts
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import * as _develit_io_backend_sdk from '@develit-io/backend-sdk';
|
|
2
2
|
import { IRPCResponse } from '@develit-io/backend-sdk';
|
|
3
|
-
import {
|
|
4
|
-
import { S as SyncAddressInput, a as SyncAddressOutput } from '../shared/blockchain.QCUmm8Hp.js';
|
|
3
|
+
import { t as tables, S as SyncAddressInput, a as SyncAddressOutput, G as GetTransactionInput, b as GetTransactionOutput } from '../shared/blockchain.4Hzh__vM.js';
|
|
5
4
|
import { WorkerEntrypoint } from 'cloudflare:workers';
|
|
6
5
|
import { DrizzleD1Database } from 'drizzle-orm/d1';
|
|
7
|
-
import 'drizzle-orm/sqlite-core';
|
|
8
6
|
import 'zod';
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
import '../shared/blockchain.Cx60lJ0c.js';
|
|
8
|
+
import 'drizzle-orm/sqlite-core';
|
|
11
9
|
|
|
12
10
|
declare const BlockchainServiceBase_base: (abstract new (ctx: ExecutionContext, env: BlockchainEnv) => WorkerEntrypoint<BlockchainEnv, {}>) & (abstract new (...args: any[]) => _develit_io_backend_sdk.DevelitWorkerMethods);
|
|
13
11
|
declare class BlockchainServiceBase extends BlockchainServiceBase_base {
|
|
14
12
|
readonly db: DrizzleD1Database<typeof tables>;
|
|
15
13
|
constructor(ctx: ExecutionContext, env: BlockchainEnv);
|
|
16
14
|
syncAddress(input: SyncAddressInput): Promise<IRPCResponse<SyncAddressOutput>>;
|
|
15
|
+
getTransaction(input: GetTransactionInput): Promise<IRPCResponse<GetTransactionOutput>>;
|
|
17
16
|
}
|
|
18
17
|
declare function defineBlockchainService(): new (ctx: ExecutionContext, env: BlockchainEnv) => BlockchainServiceBase;
|
|
19
18
|
|
package/dist/export/worker.mjs
CHANGED
|
@@ -1,13 +1,87 @@
|
|
|
1
|
-
import { develitWorker, action, service } from '@develit-io/backend-sdk';
|
|
2
|
-
import {
|
|
3
|
-
import '
|
|
4
|
-
import { s as syncAddressInputSchema } from '../shared/blockchain.
|
|
1
|
+
import { useResult, createInternalError, develitWorker, action, service } from '@develit-io/backend-sdk';
|
|
2
|
+
import { createPublicClient, http } from 'viem';
|
|
3
|
+
import { t as tables } from '../shared/blockchain.0tUJ62WT.mjs';
|
|
4
|
+
import { s as syncAddressInputSchema, g as getTransactionInputSchema } from '../shared/blockchain.B_Tqqlia.mjs';
|
|
5
5
|
import { WorkerEntrypoint } from 'cloudflare:workers';
|
|
6
6
|
import { drizzle } from 'drizzle-orm/d1';
|
|
7
|
+
import '../shared/blockchain._wwKu1qP.mjs';
|
|
7
8
|
import 'drizzle-orm/sqlite-core';
|
|
9
|
+
import 'drizzle-orm';
|
|
8
10
|
import 'zod';
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
class IBlockchainConnector {
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class AlchemyConnector extends IBlockchainConnector {
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super();
|
|
18
|
+
this.connectorKey = "ALCHEMY";
|
|
19
|
+
this.client = null;
|
|
20
|
+
this.rpcUrl = config.rpcUrl;
|
|
21
|
+
}
|
|
22
|
+
createClient() {
|
|
23
|
+
if (!this.client) {
|
|
24
|
+
this.client = createPublicClient({
|
|
25
|
+
transport: http(this.rpcUrl)
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return this.client;
|
|
29
|
+
}
|
|
30
|
+
async getTransaction(txHash) {
|
|
31
|
+
const client = this.createClient();
|
|
32
|
+
const [tx, txError] = await useResult(
|
|
33
|
+
client.getTransaction({ hash: txHash })
|
|
34
|
+
);
|
|
35
|
+
if (txError || !tx) {
|
|
36
|
+
throw createInternalError(txError);
|
|
37
|
+
}
|
|
38
|
+
let status = "pending";
|
|
39
|
+
let gasUsed = null;
|
|
40
|
+
let timestamp = null;
|
|
41
|
+
if (tx.blockNumber) {
|
|
42
|
+
const [receipt, receiptError] = await useResult(
|
|
43
|
+
client.getTransactionReceipt({ hash: txHash })
|
|
44
|
+
);
|
|
45
|
+
if (receiptError || !receipt) {
|
|
46
|
+
throw createInternalError(receiptError);
|
|
47
|
+
}
|
|
48
|
+
const [block, blockError] = await useResult(
|
|
49
|
+
client.getBlock({ blockNumber: tx.blockNumber })
|
|
50
|
+
);
|
|
51
|
+
if (blockError || !block) {
|
|
52
|
+
throw createInternalError(blockError);
|
|
53
|
+
}
|
|
54
|
+
status = receipt.status === "success" ? "success" : "reverted";
|
|
55
|
+
gasUsed = receipt.gasUsed.toString();
|
|
56
|
+
timestamp = Number(block.timestamp) * 1e3;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
hash: tx.hash,
|
|
60
|
+
from: tx.from,
|
|
61
|
+
to: tx.to,
|
|
62
|
+
value: tx.value.toString(),
|
|
63
|
+
blockNumber: tx.blockNumber?.toString() ?? null,
|
|
64
|
+
blockHash: tx.blockHash ?? null,
|
|
65
|
+
gasPrice: tx.gasPrice?.toString() ?? null,
|
|
66
|
+
gas: tx.gas.toString(),
|
|
67
|
+
nonce: tx.nonce,
|
|
68
|
+
transactionIndex: tx.transactionIndex,
|
|
69
|
+
status,
|
|
70
|
+
gasUsed,
|
|
71
|
+
timestamp
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async getTransactionReceipt(txHash) {
|
|
75
|
+
const client = this.createClient();
|
|
76
|
+
const [receipt, error] = await useResult(
|
|
77
|
+
client.getTransactionReceipt({ hash: txHash })
|
|
78
|
+
);
|
|
79
|
+
if (error || !receipt) {
|
|
80
|
+
throw createInternalError(error);
|
|
81
|
+
}
|
|
82
|
+
return receipt;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
11
85
|
|
|
12
86
|
var __defProp = Object.defineProperty;
|
|
13
87
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -31,13 +105,29 @@ let BlockchainServiceBase = class extends develitWorker(
|
|
|
31
105
|
{ data: input, schema: syncAddressInputSchema },
|
|
32
106
|
{ successMessage: "Address sync workflow started" },
|
|
33
107
|
async ({ addressId }) => {
|
|
34
|
-
await this.env.SYNC_ADDRESS_TRANSACTIONS_WORKFLOW.create({
|
|
108
|
+
const instance = await this.env.SYNC_ADDRESS_TRANSACTIONS_WORKFLOW.create({
|
|
35
109
|
id: addressId,
|
|
36
110
|
params: {
|
|
37
111
|
addressId
|
|
38
112
|
}
|
|
39
113
|
});
|
|
40
|
-
return {
|
|
114
|
+
return {
|
|
115
|
+
instanceId: instance.id,
|
|
116
|
+
details: await instance.status()
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
async getTransaction(input) {
|
|
122
|
+
return this.handleAction(
|
|
123
|
+
{ data: input, schema: getTransactionInputSchema },
|
|
124
|
+
{ successMessage: "Transaction retrieved successfully." },
|
|
125
|
+
async ({ txHash }) => {
|
|
126
|
+
const rpcUrl = (await this.env.SECRETS_STORE.get({
|
|
127
|
+
secretName: "BLOCKCHAIN_SERVICE_RPC_URL"
|
|
128
|
+
})).data?.secretValue || "";
|
|
129
|
+
const connector = new AlchemyConnector({ rpcUrl });
|
|
130
|
+
return connector.getTransaction(txHash);
|
|
41
131
|
}
|
|
42
132
|
);
|
|
43
133
|
}
|
|
@@ -45,6 +135,9 @@ let BlockchainServiceBase = class extends develitWorker(
|
|
|
45
135
|
__decorateClass([
|
|
46
136
|
action("sync-address")
|
|
47
137
|
], BlockchainServiceBase.prototype, "syncAddress", 1);
|
|
138
|
+
__decorateClass([
|
|
139
|
+
action("get-transaction")
|
|
140
|
+
], BlockchainServiceBase.prototype, "getTransaction", 1);
|
|
48
141
|
BlockchainServiceBase = __decorateClass([
|
|
49
142
|
service("blockchain")
|
|
50
143
|
], BlockchainServiceBase);
|
|
@@ -1,42 +1,61 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const backendSdk = require('@develit-io/backend-sdk');
|
|
4
|
+
const drizzle = require('../shared/blockchain.DN735AwB.cjs');
|
|
5
|
+
const drizzleOrm = require('drizzle-orm');
|
|
3
6
|
const cloudflare_workers = require('cloudflare:workers');
|
|
4
7
|
const cloudflare_workflows = require('cloudflare:workflows');
|
|
8
|
+
const d1 = require('drizzle-orm/d1');
|
|
5
9
|
const viem = require('viem');
|
|
6
10
|
const chains = require('viem/chains');
|
|
11
|
+
require('../shared/blockchain.BBvwu2_7.cjs');
|
|
12
|
+
require('drizzle-orm/sqlite-core');
|
|
7
13
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
lastSyncedBlock: null
|
|
32
|
-
}
|
|
14
|
+
const updateAddressLastSyncCommand = (db, {
|
|
15
|
+
lastSyncAt,
|
|
16
|
+
addressId,
|
|
17
|
+
lastSyncMetadata
|
|
18
|
+
}) => {
|
|
19
|
+
const command = db.update(drizzle.tables.address).set({
|
|
20
|
+
lastSyncAt,
|
|
21
|
+
lastSyncMetadata
|
|
22
|
+
}).where(drizzleOrm.eq(drizzle.tables.address.id, addressId)).returning();
|
|
23
|
+
return {
|
|
24
|
+
command
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const getAddressById = async (db, id) => {
|
|
29
|
+
const address = await db.select().from(drizzle.tables.address).where(drizzleOrm.eq(drizzle.tables.address.id, id)).get();
|
|
30
|
+
return address;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const createTransactionCommand = (db, { transaction }) => {
|
|
34
|
+
const id = backendSdk.uuidv4();
|
|
35
|
+
const command = db.insert(drizzle.tables.transaction).values({ ...transaction, id }).returning();
|
|
36
|
+
return { command };
|
|
33
37
|
};
|
|
38
|
+
|
|
39
|
+
function pushToQueue(queue, message) {
|
|
40
|
+
if (!Array.isArray(message)) return queue.send(message, { contentType: "v8" });
|
|
41
|
+
return queue.sendBatch(
|
|
42
|
+
message.map((m) => ({
|
|
43
|
+
body: m,
|
|
44
|
+
contentType: "v8"
|
|
45
|
+
}))
|
|
46
|
+
);
|
|
47
|
+
}
|
|
34
48
|
class BlockchainSyncAddressTransactions extends cloudflare_workers.WorkflowEntrypoint {
|
|
35
49
|
async run(event, step) {
|
|
36
50
|
const { addressId } = event.payload;
|
|
51
|
+
const db = d1.drizzle(this.env.BLOCKCHAIN_D1, { schema: drizzle.tables });
|
|
52
|
+
if (!addressId) {
|
|
53
|
+
throw new cloudflare_workflows.NonRetryableError(`Haven't obtained addressId to load.`);
|
|
54
|
+
}
|
|
37
55
|
while (true) {
|
|
56
|
+
const now = /* @__PURE__ */ new Date();
|
|
38
57
|
const address = await step.do("load address", async () => {
|
|
39
|
-
const address2 =
|
|
58
|
+
const address2 = await getAddressById(db, addressId);
|
|
40
59
|
if (!address2) {
|
|
41
60
|
throw new cloudflare_workflows.NonRetryableError(
|
|
42
61
|
`Blockchain address not found: ${addressId}.`
|
|
@@ -44,32 +63,45 @@ class BlockchainSyncAddressTransactions extends cloudflare_workers.WorkflowEntry
|
|
|
44
63
|
}
|
|
45
64
|
return address2;
|
|
46
65
|
});
|
|
47
|
-
|
|
66
|
+
if (!address.lastSyncAt) {
|
|
67
|
+
throw new Error(`lastSyncedAt is not set for address: ${address}`);
|
|
68
|
+
}
|
|
69
|
+
const transactions = await step.do(
|
|
48
70
|
"fetch address transactions",
|
|
49
71
|
{
|
|
50
72
|
retries: { limit: 5, delay: 2e3, backoff: "constant" },
|
|
51
73
|
timeout: "30 seconds"
|
|
52
74
|
},
|
|
53
75
|
async () => {
|
|
76
|
+
const rpcUrl = (await this.env.SECRETS_STORE.get({
|
|
77
|
+
secretName: "BLOCKCHAIN_SERVICE_RPC_URL"
|
|
78
|
+
})).data?.secretValue || "";
|
|
54
79
|
const client = viem.createPublicClient({
|
|
55
|
-
chain: chains.
|
|
56
|
-
transport: viem.http()
|
|
80
|
+
chain: chains.gnosisChiado,
|
|
81
|
+
transport: viem.http(rpcUrl)
|
|
57
82
|
});
|
|
58
83
|
const currentBlock = await client.getBlockNumber();
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
console.log(
|
|
62
|
-
`\u{1F50D} Scanning blocks ${startBlock} to ${endBlock} for address ${address.address}`
|
|
84
|
+
const estimatedBlocksPerInterval = Math.ceil(
|
|
85
|
+
address.syncIntervalS * 1.5 / 5
|
|
63
86
|
);
|
|
87
|
+
const blocksToScan = Math.min(estimatedBlocksPerInterval, 1e3);
|
|
88
|
+
const startBlock = currentBlock - BigInt(blocksToScan);
|
|
89
|
+
const endBlock = currentBlock;
|
|
90
|
+
const lastSyncedTimestamp = address.lastSyncAt || 0;
|
|
64
91
|
const allTransactions = [];
|
|
65
92
|
for (let blockNum = startBlock; blockNum <= endBlock; blockNum++) {
|
|
66
93
|
const block = await client.getBlock({
|
|
67
94
|
blockNumber: blockNum,
|
|
68
95
|
includeTransactions: true
|
|
69
96
|
});
|
|
97
|
+
const blockTimestamp = Number(block.timestamp);
|
|
98
|
+
const lastSyncedTimestampNum = typeof lastSyncedTimestamp === "number" ? lastSyncedTimestamp : Number(lastSyncedTimestamp);
|
|
99
|
+
if (blockTimestamp <= lastSyncedTimestampNum) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
70
102
|
for (const tx of block.transactions) {
|
|
71
|
-
if (typeof tx === "string") continue;
|
|
72
|
-
if (tx.from.toLowerCase() === address.
|
|
103
|
+
if (typeof tx === "string" || !tx.to) continue;
|
|
104
|
+
if (tx.from.toLowerCase() === address.number.toLowerCase()) {
|
|
73
105
|
const receipt = await client.getTransactionReceipt({
|
|
74
106
|
hash: tx.hash
|
|
75
107
|
});
|
|
@@ -81,23 +113,70 @@ class BlockchainSyncAddressTransactions extends cloudflare_workers.WorkflowEntry
|
|
|
81
113
|
blockNumber: block.number.toString(),
|
|
82
114
|
blockHash: block.hash,
|
|
83
115
|
gasUsed: receipt.gasUsed.toString(),
|
|
84
|
-
gasPrice: tx.gasPrice?.toString(),
|
|
85
|
-
timestamp:
|
|
86
|
-
status: receipt.status
|
|
116
|
+
gasPrice: tx.gasPrice?.toString() ?? "",
|
|
117
|
+
timestamp: blockTimestamp,
|
|
118
|
+
status: receipt.status
|
|
87
119
|
});
|
|
88
120
|
}
|
|
89
121
|
}
|
|
90
122
|
}
|
|
91
|
-
console.log(`\u2705 Sync complete for ${address.address}`);
|
|
92
|
-
console.log(` Found ${allTransactions.length} transactions`);
|
|
93
|
-
console.log(` Blocks scanned: ${startBlock} to ${endBlock}`);
|
|
94
|
-
if (allTransactions.length > 0) {
|
|
95
|
-
console.log("Transactions:");
|
|
96
|
-
console.log(JSON.stringify(allTransactions));
|
|
97
|
-
}
|
|
98
123
|
return allTransactions;
|
|
99
124
|
}
|
|
100
125
|
);
|
|
126
|
+
if (transactions.length > 0) {
|
|
127
|
+
await step.do(
|
|
128
|
+
"process new transactions and update lastSyncAt",
|
|
129
|
+
async () => {
|
|
130
|
+
const createCommands = transactions.map(
|
|
131
|
+
(tx) => createTransactionCommand(db, { transaction: tx }).command
|
|
132
|
+
);
|
|
133
|
+
const eventsToEmit = transactions.map(
|
|
134
|
+
(tx) => ({
|
|
135
|
+
eventType: "BLOCKCHAIN_TRANSACTION",
|
|
136
|
+
blockchainTransaction: {
|
|
137
|
+
address: address.number,
|
|
138
|
+
hash: tx.hash,
|
|
139
|
+
from: tx.from,
|
|
140
|
+
to: tx.to,
|
|
141
|
+
value: tx.value,
|
|
142
|
+
blockNumber: tx.blockNumber,
|
|
143
|
+
blockHash: tx.blockHash,
|
|
144
|
+
gasUsed: tx.gasUsed,
|
|
145
|
+
gasPrice: tx.gasPrice,
|
|
146
|
+
timestamp: tx.timestamp,
|
|
147
|
+
status: tx.status
|
|
148
|
+
},
|
|
149
|
+
metadata: {
|
|
150
|
+
correlationId: backendSdk.uuidv4(),
|
|
151
|
+
entityId: backendSdk.uuidv4(),
|
|
152
|
+
timestamp: (/* @__PURE__ */ new Date()).toDateString()
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
);
|
|
156
|
+
const lastSyncMetadata = {
|
|
157
|
+
eventsEmitted: eventsToEmit.length
|
|
158
|
+
};
|
|
159
|
+
const updateLastSyncCommand = updateAddressLastSyncCommand(db, {
|
|
160
|
+
addressId: address.id,
|
|
161
|
+
lastSyncAt: now,
|
|
162
|
+
lastSyncMetadata
|
|
163
|
+
}).command;
|
|
164
|
+
if (eventsToEmit.length) {
|
|
165
|
+
await db.batch(
|
|
166
|
+
backendSdk.asNonEmpty([updateLastSyncCommand, ...createCommands])
|
|
167
|
+
);
|
|
168
|
+
await pushToQueue(
|
|
169
|
+
this.env.QUEUE_BUS_QUEUE,
|
|
170
|
+
eventsToEmit
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
...lastSyncMetadata,
|
|
175
|
+
newLastSyncAt: now
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
}
|
|
101
180
|
await step.sleep(
|
|
102
181
|
"sleep until next sync",
|
|
103
182
|
`${address.syncIntervalS} seconds`
|