drip-web3-sdk 0.1.0

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.
@@ -0,0 +1,65 @@
1
+ import { ethers } from "ethers";
2
+ export interface Plan {
3
+ planId: bigint;
4
+ token: string;
5
+ amount: bigint;
6
+ interval: bigint;
7
+ merchant: string;
8
+ active: boolean;
9
+ }
10
+ export interface Subscription {
11
+ subscriptionId: bigint;
12
+ planId: bigint;
13
+ subscriber: string;
14
+ nextPayment: bigint;
15
+ active: boolean;
16
+ }
17
+ export interface DripConfig {
18
+ contractAddress: string;
19
+ signer: ethers.Signer;
20
+ }
21
+ export interface SubscribeOptions {
22
+ autoApprove?: boolean;
23
+ approvalAmount?: bigint;
24
+ }
25
+ export declare class Drip {
26
+ private contract;
27
+ private signer;
28
+ contractAddress: string;
29
+ constructor(config: DripConfig);
30
+ createPlan(tokenAddress: string, amount: bigint, intervalSeconds: bigint): Promise<{
31
+ planId: bigint;
32
+ tx: ethers.TransactionResponse;
33
+ }>;
34
+ getPlan(planId: bigint): Promise<Plan>;
35
+ cancelPlan(planId: bigint): Promise<ethers.TransactionResponse>;
36
+ subscribe(planId: bigint, options?: SubscribeOptions): Promise<{
37
+ subscriptionId: bigint;
38
+ tx: ethers.TransactionResponse;
39
+ }>;
40
+ getSubscription(subscriptionId: bigint): Promise<Subscription>;
41
+ cancelSubscription(subscriptionId: bigint): Promise<ethers.TransactionResponse>;
42
+ cancelSubscriptionAsMerchant(subscriptionId: bigint): Promise<ethers.TransactionResponse>;
43
+ executePayment(subscriptionId: bigint): Promise<ethers.TransactionResponse>;
44
+ approveToken(tokenAddress: string, amount: bigint): Promise<ethers.TransactionResponse | null>;
45
+ getTokenInfo(tokenAddress: string): Promise<{
46
+ symbol: string;
47
+ decimals: number;
48
+ balance: bigint;
49
+ }>;
50
+ getStats(): Promise<{
51
+ planCount: bigint;
52
+ subscriptionCount: bigint;
53
+ feeBps: bigint;
54
+ feeRecipient: string;
55
+ }>;
56
+ }
57
+ export declare const INTERVALS: {
58
+ readonly DAILY: bigint;
59
+ readonly WEEKLY: bigint;
60
+ readonly MONTHLY: bigint;
61
+ readonly YEARLY: bigint;
62
+ };
63
+ export declare const DEPLOYMENTS: Record<string, string>;
64
+ export default Drip;
65
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAgChC,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,IAAI;IACf,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,MAAM,CAAgB;IACvB,eAAe,EAAE,MAAM,CAAC;gBAEnB,MAAM,EAAE,UAAU;IAYxB,UAAU,CACd,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC,mBAAmB,CAAA;KAAE,CAAC;IA0BxD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC;IAM/D,SAAS,CACb,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC,mBAAmB,CAAA;KAAE,CAAC;IAiChE,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAW9D,kBAAkB,CACtB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC;IAIhC,4BAA4B,CAChC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC;IAIhC,cAAc,CAClB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC;IAMhC,YAAY,CAChB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAavC,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAChD,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IAaI,QAAQ,IAAI,OAAO,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;QAClB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CAUH;AAID,eAAO,MAAM,SAAS;;;;;CAKZ,CAAC;AAEX,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAG9C,CAAC;AAEF,eAAe,IAAI,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEPLOYMENTS = exports.INTERVALS = exports.Drip = void 0;
4
+ const ethers_1 = require("ethers");
5
+ const DRIP_ABI = [
6
+ "function createPlan(address token, uint256 amount, uint256 interval) external returns (uint256)",
7
+ "function subscribe(uint256 planId) external returns (uint256)",
8
+ "function cancelSubscription(uint256 subscriptionId) external",
9
+ "function cancelPlan(uint256 planId) external",
10
+ "function cancelSubscriptionAsMerchant(uint256 subscriptionId) external",
11
+ "function executePayment(uint256 subscriptionId) external",
12
+ "function plans(uint256) external view returns (address token, uint256 amount, uint256 interval, address merchant, bool active)",
13
+ "function subscriptions(uint256) external view returns (uint256 planId, address subscriber, uint256 nextPayment, bool active)",
14
+ "function subscriptionCount() external view returns (uint256)",
15
+ "function planCount() external view returns (uint256)",
16
+ "function feeBps() external view returns (uint256)",
17
+ "function feeRecipient() external view returns (address)",
18
+ "event PlanCreated(uint256 indexed planId, address indexed merchant, address token, uint256 amount, uint256 interval)",
19
+ "event Subscribed(uint256 indexed subscriptionId, uint256 indexed planId, address indexed subscriber)",
20
+ "event PaymentExecuted(uint256 indexed subscriptionId, uint256 amount, uint256 fee)",
21
+ "event SubscriptionCancelled(uint256 indexed subscriptionId)",
22
+ "event PlanCancelled(uint256 indexed planId)"
23
+ ];
24
+ const ERC20_ABI = [
25
+ "function approve(address spender, uint256 amount) external returns (bool)",
26
+ "function allowance(address owner, address spender) external view returns (uint256)",
27
+ "function balanceOf(address account) external view returns (uint256)",
28
+ "function decimals() external view returns (uint8)",
29
+ "function symbol() external view returns (string)"
30
+ ];
31
+ const MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
32
+ class Drip {
33
+ constructor(config) {
34
+ this.contractAddress = config.contractAddress;
35
+ this.signer = config.signer;
36
+ this.contract = new ethers_1.ethers.Contract(config.contractAddress, DRIP_ABI, config.signer);
37
+ }
38
+ // ─── Plans ───────────────────────────────────────────────
39
+ async createPlan(tokenAddress, amount, intervalSeconds) {
40
+ const tx = await this.contract.createPlan(tokenAddress, amount, intervalSeconds);
41
+ const receipt = await tx.wait();
42
+ const event = receipt.logs
43
+ .map((log) => {
44
+ try {
45
+ return this.contract.interface.parseLog(log);
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ })
51
+ .find((e) => e?.name === "PlanCreated");
52
+ if (!event || !event.args) {
53
+ throw new Error("PlanCreated event not found in transaction receipt — refetch planCount to get your planId");
54
+ }
55
+ return { planId: event.args.planId, tx };
56
+ }
57
+ async getPlan(planId) {
58
+ const result = await this.contract.plans(planId);
59
+ return {
60
+ planId,
61
+ token: result.token,
62
+ amount: result.amount,
63
+ interval: result.interval,
64
+ merchant: result.merchant,
65
+ active: result.active,
66
+ };
67
+ }
68
+ async cancelPlan(planId) {
69
+ return await this.contract.cancelPlan(planId);
70
+ }
71
+ // ─── Subscriptions ───────────────────────────────────────
72
+ async subscribe(planId, options = {}) {
73
+ const { autoApprove = true, approvalAmount } = options;
74
+ if (autoApprove) {
75
+ const plan = await this.getPlan(planId);
76
+ const amount = approvalAmount ?? MAX_UINT256;
77
+ const approveTx = await this.approveToken(plan.token, amount);
78
+ if (approveTx) {
79
+ await approveTx.wait();
80
+ }
81
+ }
82
+ const tx = await this.contract.subscribe(planId);
83
+ const receipt = await tx.wait();
84
+ const event = receipt.logs
85
+ .map((log) => {
86
+ try {
87
+ return this.contract.interface.parseLog(log);
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ })
93
+ .find((e) => e?.name === "Subscribed");
94
+ if (!event || !event.args) {
95
+ throw new Error("Subscribed event not found in transaction receipt — refetch subscriptionCount to get your subscriptionId");
96
+ }
97
+ return { subscriptionId: event.args.subscriptionId, tx };
98
+ }
99
+ async getSubscription(subscriptionId) {
100
+ const result = await this.contract.subscriptions(subscriptionId);
101
+ return {
102
+ subscriptionId,
103
+ planId: result.planId,
104
+ subscriber: result.subscriber,
105
+ nextPayment: result.nextPayment,
106
+ active: result.active,
107
+ };
108
+ }
109
+ async cancelSubscription(subscriptionId) {
110
+ return await this.contract.cancelSubscription(subscriptionId);
111
+ }
112
+ async cancelSubscriptionAsMerchant(subscriptionId) {
113
+ return await this.contract.cancelSubscriptionAsMerchant(subscriptionId);
114
+ }
115
+ async executePayment(subscriptionId) {
116
+ return await this.contract.executePayment(subscriptionId);
117
+ }
118
+ // ─── Token helpers ───────────────────────────────────────
119
+ async approveToken(tokenAddress, amount) {
120
+ const token = new ethers_1.ethers.Contract(tokenAddress, ERC20_ABI, this.signer);
121
+ const signerAddress = await this.signer.getAddress();
122
+ const allowance = await token.allowance(signerAddress, this.contractAddress);
123
+ if (allowance >= amount) {
124
+ return null;
125
+ }
126
+ return await token.approve(this.contractAddress, amount);
127
+ }
128
+ async getTokenInfo(tokenAddress) {
129
+ const token = new ethers_1.ethers.Contract(tokenAddress, ERC20_ABI, this.signer);
130
+ const signerAddress = await this.signer.getAddress();
131
+ const [symbol, decimals, balance] = await Promise.all([
132
+ token.symbol(),
133
+ token.decimals(),
134
+ token.balanceOf(signerAddress),
135
+ ]);
136
+ return { symbol, decimals, balance };
137
+ }
138
+ // ─── Protocol stats ──────────────────────────────────────
139
+ async getStats() {
140
+ const [planCount, subscriptionCount, feeBps, feeRecipient] = await Promise.all([
141
+ this.contract.planCount(),
142
+ this.contract.subscriptionCount(),
143
+ this.contract.feeBps(),
144
+ this.contract.feeRecipient(),
145
+ ]);
146
+ return { planCount, subscriptionCount, feeBps, feeRecipient };
147
+ }
148
+ }
149
+ exports.Drip = Drip;
150
+ // ─── Convenience constants ───────────────────────────────
151
+ exports.INTERVALS = {
152
+ DAILY: BigInt(86400),
153
+ WEEKLY: BigInt(604800),
154
+ MONTHLY: BigInt(2592000),
155
+ YEARLY: BigInt(31536000),
156
+ };
157
+ exports.DEPLOYMENTS = {
158
+ "base-sepolia": "0x1ad2FC3469dB1625730B4401E5717B741526B6af",
159
+ "base": "0x1ad2FC3469dB1625730B4401E5717B741526B6af",
160
+ };
161
+ exports.default = Drip;
162
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "drip-web3-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Recurring payment protocol for Web3",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "dev": "ts-node src/index.ts"
10
+ },
11
+ "keywords": ["web3", "payments", "subscriptions", "defi", "base"],
12
+ "license": "MIT",
13
+ "dependencies": {
14
+ "ethers": "^6.0.0"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^20.0.0",
18
+ "ts-node": "^10.0.0",
19
+ "typescript": "^5.0.0"
20
+ }
21
+ }
package/src/index.ts ADDED
@@ -0,0 +1,256 @@
1
+ import { ethers } from "ethers";
2
+
3
+ const DRIP_ABI = [
4
+ "function createPlan(address token, uint256 amount, uint256 interval) external returns (uint256)",
5
+ "function subscribe(uint256 planId) external returns (uint256)",
6
+ "function cancelSubscription(uint256 subscriptionId) external",
7
+ "function cancelPlan(uint256 planId) external",
8
+ "function cancelSubscriptionAsMerchant(uint256 subscriptionId) external",
9
+ "function executePayment(uint256 subscriptionId) external",
10
+ "function plans(uint256) external view returns (address token, uint256 amount, uint256 interval, address merchant, bool active)",
11
+ "function subscriptions(uint256) external view returns (uint256 planId, address subscriber, uint256 nextPayment, bool active)",
12
+ "function subscriptionCount() external view returns (uint256)",
13
+ "function planCount() external view returns (uint256)",
14
+ "function feeBps() external view returns (uint256)",
15
+ "function feeRecipient() external view returns (address)",
16
+ "event PlanCreated(uint256 indexed planId, address indexed merchant, address token, uint256 amount, uint256 interval)",
17
+ "event Subscribed(uint256 indexed subscriptionId, uint256 indexed planId, address indexed subscriber)",
18
+ "event PaymentExecuted(uint256 indexed subscriptionId, uint256 amount, uint256 fee)",
19
+ "event SubscriptionCancelled(uint256 indexed subscriptionId)",
20
+ "event PlanCancelled(uint256 indexed planId)"
21
+ ];
22
+
23
+ const ERC20_ABI = [
24
+ "function approve(address spender, uint256 amount) external returns (bool)",
25
+ "function allowance(address owner, address spender) external view returns (uint256)",
26
+ "function balanceOf(address account) external view returns (uint256)",
27
+ "function decimals() external view returns (uint8)",
28
+ "function symbol() external view returns (string)"
29
+ ];
30
+
31
+ const MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
32
+
33
+ export interface Plan {
34
+ planId: bigint;
35
+ token: string;
36
+ amount: bigint;
37
+ interval: bigint;
38
+ merchant: string;
39
+ active: boolean;
40
+ }
41
+
42
+ export interface Subscription {
43
+ subscriptionId: bigint;
44
+ planId: bigint;
45
+ subscriber: string;
46
+ nextPayment: bigint;
47
+ active: boolean;
48
+ }
49
+
50
+ export interface DripConfig {
51
+ contractAddress: string;
52
+ signer: ethers.Signer;
53
+ }
54
+
55
+ export interface SubscribeOptions {
56
+ autoApprove?: boolean;
57
+ approvalAmount?: bigint;
58
+ }
59
+
60
+ export class Drip {
61
+ private contract: ethers.Contract;
62
+ private signer: ethers.Signer;
63
+ public contractAddress: string;
64
+
65
+ constructor(config: DripConfig) {
66
+ this.contractAddress = config.contractAddress;
67
+ this.signer = config.signer;
68
+ this.contract = new ethers.Contract(
69
+ config.contractAddress,
70
+ DRIP_ABI,
71
+ config.signer
72
+ );
73
+ }
74
+
75
+ // ─── Plans ───────────────────────────────────────────────
76
+
77
+ async createPlan(
78
+ tokenAddress: string,
79
+ amount: bigint,
80
+ intervalSeconds: bigint
81
+ ): Promise<{ planId: bigint; tx: ethers.TransactionResponse }> {
82
+ const tx = await this.contract.createPlan(
83
+ tokenAddress,
84
+ amount,
85
+ intervalSeconds
86
+ );
87
+ const receipt = await tx.wait();
88
+ const event = receipt.logs
89
+ .map((log: ethers.Log) => {
90
+ try {
91
+ return this.contract.interface.parseLog(log);
92
+ } catch {
93
+ return null;
94
+ }
95
+ })
96
+ .find((e: ethers.LogDescription | null) => e?.name === "PlanCreated");
97
+
98
+ if (!event || !event.args) {
99
+ throw new Error(
100
+ "PlanCreated event not found in transaction receipt — refetch planCount to get your planId"
101
+ );
102
+ }
103
+
104
+ return { planId: event.args.planId, tx };
105
+ }
106
+
107
+ async getPlan(planId: bigint): Promise<Plan> {
108
+ const result = await this.contract.plans(planId);
109
+ return {
110
+ planId,
111
+ token: result.token,
112
+ amount: result.amount,
113
+ interval: result.interval,
114
+ merchant: result.merchant,
115
+ active: result.active,
116
+ };
117
+ }
118
+
119
+ async cancelPlan(planId: bigint): Promise<ethers.TransactionResponse> {
120
+ return await this.contract.cancelPlan(planId);
121
+ }
122
+
123
+ // ─── Subscriptions ───────────────────────────────────────
124
+
125
+ async subscribe(
126
+ planId: bigint,
127
+ options: SubscribeOptions = {}
128
+ ): Promise<{ subscriptionId: bigint; tx: ethers.TransactionResponse }> {
129
+ const { autoApprove = true, approvalAmount } = options;
130
+
131
+ if (autoApprove) {
132
+ const plan = await this.getPlan(planId);
133
+ const amount = approvalAmount ?? MAX_UINT256;
134
+ const approveTx = await this.approveToken(plan.token, amount);
135
+ if (approveTx) {
136
+ await approveTx.wait();
137
+ }
138
+ }
139
+
140
+ const tx = await this.contract.subscribe(planId);
141
+ const receipt = await tx.wait();
142
+ const event = receipt.logs
143
+ .map((log: ethers.Log) => {
144
+ try {
145
+ return this.contract.interface.parseLog(log);
146
+ } catch {
147
+ return null;
148
+ }
149
+ })
150
+ .find((e: ethers.LogDescription | null) => e?.name === "Subscribed");
151
+
152
+ if (!event || !event.args) {
153
+ throw new Error(
154
+ "Subscribed event not found in transaction receipt — refetch subscriptionCount to get your subscriptionId"
155
+ );
156
+ }
157
+
158
+ return { subscriptionId: event.args.subscriptionId, tx };
159
+ }
160
+
161
+ async getSubscription(subscriptionId: bigint): Promise<Subscription> {
162
+ const result = await this.contract.subscriptions(subscriptionId);
163
+ return {
164
+ subscriptionId,
165
+ planId: result.planId,
166
+ subscriber: result.subscriber,
167
+ nextPayment: result.nextPayment,
168
+ active: result.active,
169
+ };
170
+ }
171
+
172
+ async cancelSubscription(
173
+ subscriptionId: bigint
174
+ ): Promise<ethers.TransactionResponse> {
175
+ return await this.contract.cancelSubscription(subscriptionId);
176
+ }
177
+
178
+ async cancelSubscriptionAsMerchant(
179
+ subscriptionId: bigint
180
+ ): Promise<ethers.TransactionResponse> {
181
+ return await this.contract.cancelSubscriptionAsMerchant(subscriptionId);
182
+ }
183
+
184
+ async executePayment(
185
+ subscriptionId: bigint
186
+ ): Promise<ethers.TransactionResponse> {
187
+ return await this.contract.executePayment(subscriptionId);
188
+ }
189
+
190
+ // ─── Token helpers ───────────────────────────────────────
191
+
192
+ async approveToken(
193
+ tokenAddress: string,
194
+ amount: bigint
195
+ ): Promise<ethers.TransactionResponse | null> {
196
+ const token = new ethers.Contract(tokenAddress, ERC20_ABI, this.signer);
197
+ const signerAddress = await this.signer.getAddress();
198
+ const allowance = await token.allowance(
199
+ signerAddress,
200
+ this.contractAddress
201
+ );
202
+ if (allowance >= amount) {
203
+ return null;
204
+ }
205
+ return await token.approve(this.contractAddress, amount);
206
+ }
207
+
208
+ async getTokenInfo(tokenAddress: string): Promise<{
209
+ symbol: string;
210
+ decimals: number;
211
+ balance: bigint;
212
+ }> {
213
+ const token = new ethers.Contract(tokenAddress, ERC20_ABI, this.signer);
214
+ const signerAddress = await this.signer.getAddress();
215
+ const [symbol, decimals, balance] = await Promise.all([
216
+ token.symbol(),
217
+ token.decimals(),
218
+ token.balanceOf(signerAddress),
219
+ ]);
220
+ return { symbol, decimals, balance };
221
+ }
222
+
223
+ // ─── Protocol stats ──────────────────────────────────────
224
+
225
+ async getStats(): Promise<{
226
+ planCount: bigint;
227
+ subscriptionCount: bigint;
228
+ feeBps: bigint;
229
+ feeRecipient: string;
230
+ }> {
231
+ const [planCount, subscriptionCount, feeBps, feeRecipient] =
232
+ await Promise.all([
233
+ this.contract.planCount(),
234
+ this.contract.subscriptionCount(),
235
+ this.contract.feeBps(),
236
+ this.contract.feeRecipient(),
237
+ ]);
238
+ return { planCount, subscriptionCount, feeBps, feeRecipient };
239
+ }
240
+ }
241
+
242
+ // ─── Convenience constants ───────────────────────────────
243
+
244
+ export const INTERVALS = {
245
+ DAILY: BigInt(86400),
246
+ WEEKLY: BigInt(604800),
247
+ MONTHLY: BigInt(2592000),
248
+ YEARLY: BigInt(31536000),
249
+ } as const;
250
+
251
+ export const DEPLOYMENTS: Record<string, string> = {
252
+ "base-sepolia": "0x1ad2FC3469dB1625730B4401E5717B741526B6af",
253
+ "base": "0x1ad2FC3469dB1625730B4401E5717B741526B6af",
254
+ };
255
+
256
+ export default Drip;
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "declaration": true,
12
+ "declarationMap": true,
13
+ "sourceMap": true
14
+ },
15
+ "include": ["src/**/*"],
16
+ "exclude": ["node_modules", "dist"]
17
+ }