@coinbase/agentkit 0.0.0-nightly-20250724210458 → 0.0.0-nightly-20250806210443
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/README.md +22 -0
- package/dist/action-providers/cdp/cdpApiActionProvider.js +2 -0
- package/dist/action-providers/index.d.ts +2 -0
- package/dist/action-providers/index.js +2 -0
- package/dist/action-providers/truemarkets/constants.d.ts +179 -0
- package/dist/action-providers/truemarkets/constants.js +46 -0
- package/dist/action-providers/truemarkets/index.d.ts +1 -0
- package/dist/action-providers/truemarkets/index.js +17 -0
- package/dist/action-providers/truemarkets/schemas.d.ts +21 -0
- package/dist/action-providers/truemarkets/schemas.js +29 -0
- package/dist/action-providers/truemarkets/truemarketsActionProvider.d.ts +51 -0
- package/dist/action-providers/truemarkets/truemarketsActionProvider.js +469 -0
- package/dist/action-providers/truemarkets/truemarketsActionProvider.test.d.ts +1 -0
- package/dist/action-providers/truemarkets/truemarketsActionProvider.test.js +217 -0
- package/dist/action-providers/truemarkets/utils.d.ts +10 -0
- package/dist/action-providers/truemarkets/utils.js +9 -0
- package/dist/action-providers/zora/index.d.ts +3 -0
- package/dist/action-providers/zora/index.js +19 -0
- package/dist/action-providers/zora/schemas.d.ts +29 -0
- package/dist/action-providers/zora/schemas.js +31 -0
- package/dist/action-providers/zora/utils.d.ts +28 -0
- package/dist/action-providers/zora/utils.js +200 -0
- package/dist/action-providers/zora/zoraActionProvider.d.ts +36 -0
- package/dist/action-providers/zora/zoraActionProvider.js +151 -0
- package/dist/action-providers/zora/zoraActionProvider.test.d.ts +1 -0
- package/dist/action-providers/zora/zoraActionProvider.test.js +205 -0
- package/dist/wallet-providers/cdpShared.d.ts +4 -0
- package/dist/wallet-providers/cdpSmartWalletProvider.d.ts +6 -0
- package/dist/wallet-providers/cdpSmartWalletProvider.js +15 -2
- package/package.json +2 -1
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const truemarketsActionProvider_1 = require("./truemarketsActionProvider");
|
|
4
|
+
const constants_1 = require("./constants");
|
|
5
|
+
const viem_1 = require("viem");
|
|
6
|
+
// Mock viem's createPublicClient
|
|
7
|
+
jest.mock("viem", () => {
|
|
8
|
+
const originalModule = jest.requireActual("viem");
|
|
9
|
+
return {
|
|
10
|
+
...originalModule,
|
|
11
|
+
createPublicClient: jest.fn().mockImplementation(() => ({
|
|
12
|
+
// Mock public client methods as needed
|
|
13
|
+
multicall: jest.fn().mockImplementation(({ contracts }) => {
|
|
14
|
+
// Create mock responses with success status
|
|
15
|
+
return contracts.map(() => ({
|
|
16
|
+
status: "success",
|
|
17
|
+
result: "mock result",
|
|
18
|
+
}));
|
|
19
|
+
}),
|
|
20
|
+
readContract: jest.fn(),
|
|
21
|
+
})),
|
|
22
|
+
http: jest.fn().mockImplementation(url => ({ url })),
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
describe("TrueMarketsActionProvider", () => {
|
|
26
|
+
let provider;
|
|
27
|
+
let mockWallet;
|
|
28
|
+
// Mock addresses and data for tests
|
|
29
|
+
const MOCK_MARKET_ADDRESS = "0x1234567890123456789012345678901234567890";
|
|
30
|
+
const MOCK_YES_POOL_ADDRESS = "0x2345678901234567890123456789012345678901";
|
|
31
|
+
const MOCK_NO_POOL_ADDRESS = "0x3456789012345678901234567890123456789012";
|
|
32
|
+
const MOCK_YES_TOKEN_ADDRESS = "0x4567890123456789012345678901234567890123";
|
|
33
|
+
const MOCK_NO_TOKEN_ADDRESS = "0x5678901234567890123456789012345678901234";
|
|
34
|
+
const MOCK_MARKET_QUESTION = "Will this test pass?";
|
|
35
|
+
const MOCK_ADDITIONAL_INFO = "Test additional info";
|
|
36
|
+
const MOCK_MARKET_SOURCE = "Test source";
|
|
37
|
+
const MOCK_STATUS_NUM = 0n; // Created status
|
|
38
|
+
const MOCK_END_OF_TRADING = 1717171717n; // Unix timestamp
|
|
39
|
+
describe("constructor", () => {
|
|
40
|
+
it("should use the provided RPC_URL for the public client", () => {
|
|
41
|
+
const customRpcUrl = "https://custom-rpc.example.com";
|
|
42
|
+
(0, truemarketsActionProvider_1.truemarketsActionProvider)({ RPC_URL: customRpcUrl });
|
|
43
|
+
// Verify createPublicClient was called with the correct URL
|
|
44
|
+
expect(viem_1.createPublicClient).toHaveBeenCalledWith(expect.objectContaining({
|
|
45
|
+
chain: expect.anything(),
|
|
46
|
+
transport: expect.objectContaining({ url: customRpcUrl }),
|
|
47
|
+
}));
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
jest.clearAllMocks();
|
|
52
|
+
provider = (0, truemarketsActionProvider_1.truemarketsActionProvider)();
|
|
53
|
+
mockWallet = {
|
|
54
|
+
readContract: jest.fn(),
|
|
55
|
+
getName: jest.fn().mockReturnValue("evm_wallet_provider"),
|
|
56
|
+
getNetwork: jest.fn().mockReturnValue({
|
|
57
|
+
networkId: "base-mainnet",
|
|
58
|
+
}),
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
jest.clearAllMocks();
|
|
63
|
+
});
|
|
64
|
+
describe("getPredictionMarkets", () => {
|
|
65
|
+
it("should successfully fetch active markets", async () => {
|
|
66
|
+
// Mock readContract calls
|
|
67
|
+
mockWallet.readContract
|
|
68
|
+
// First call: numberOfActiveMarkets
|
|
69
|
+
.mockResolvedValueOnce(2n);
|
|
70
|
+
// Create a spy on the actual implementation
|
|
71
|
+
const getPredictionMarketsSpy = jest.spyOn(provider, "getPredictionMarkets");
|
|
72
|
+
// Replace the original implementation with our mocked version to return JSON string
|
|
73
|
+
getPredictionMarketsSpy.mockImplementation(async () => {
|
|
74
|
+
return JSON.stringify({
|
|
75
|
+
success: true,
|
|
76
|
+
totalMarkets: 2,
|
|
77
|
+
markets: [
|
|
78
|
+
{
|
|
79
|
+
id: 1,
|
|
80
|
+
address: MOCK_MARKET_ADDRESS,
|
|
81
|
+
marketQuestion: MOCK_MARKET_QUESTION,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 0,
|
|
85
|
+
address: "0x6789012345678901234567890123456789012345",
|
|
86
|
+
marketQuestion: "Will this other test pass?",
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
const args = {
|
|
92
|
+
limit: 10,
|
|
93
|
+
offset: 0,
|
|
94
|
+
sortOrder: "desc",
|
|
95
|
+
};
|
|
96
|
+
const responseString = await provider.getPredictionMarkets(mockWallet, args);
|
|
97
|
+
const response = JSON.parse(responseString);
|
|
98
|
+
// Verify response contains expected data
|
|
99
|
+
expect(response.success).toBe(true);
|
|
100
|
+
expect(response.totalMarkets).toBe(2);
|
|
101
|
+
expect(response.markets.length).toBe(2);
|
|
102
|
+
expect(response.markets[0].marketQuestion).toBe(MOCK_MARKET_QUESTION);
|
|
103
|
+
expect(response.markets[0].address).toBe(MOCK_MARKET_ADDRESS);
|
|
104
|
+
// Restore the original implementation
|
|
105
|
+
getPredictionMarketsSpy.mockRestore();
|
|
106
|
+
});
|
|
107
|
+
it("should handle no active markets", async () => {
|
|
108
|
+
mockWallet.readContract.mockResolvedValueOnce(0n);
|
|
109
|
+
const args = {
|
|
110
|
+
limit: 10,
|
|
111
|
+
offset: 0,
|
|
112
|
+
sortOrder: "desc",
|
|
113
|
+
};
|
|
114
|
+
const responseString = await provider.getPredictionMarkets(mockWallet, args);
|
|
115
|
+
const response = JSON.parse(responseString);
|
|
116
|
+
expect(response.success).toBe(true);
|
|
117
|
+
expect(response.totalMarkets).toBe(0);
|
|
118
|
+
expect(response.markets.length).toBe(0);
|
|
119
|
+
});
|
|
120
|
+
it("should handle errors", async () => {
|
|
121
|
+
const error = new Error("Failed to fetch active markets");
|
|
122
|
+
mockWallet.readContract.mockRejectedValueOnce(error);
|
|
123
|
+
const args = {
|
|
124
|
+
limit: 10,
|
|
125
|
+
offset: 0,
|
|
126
|
+
sortOrder: "desc",
|
|
127
|
+
};
|
|
128
|
+
const responseString = await provider.getPredictionMarkets(mockWallet, args);
|
|
129
|
+
const response = JSON.parse(responseString);
|
|
130
|
+
expect(response.success).toBe(false);
|
|
131
|
+
expect(response.error).toBe("Error retrieving active markets: Error: Failed to fetch active markets");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
describe("getPredictionMarketDetails", () => {
|
|
135
|
+
let mockPublicClient;
|
|
136
|
+
beforeEach(() => {
|
|
137
|
+
// Access the mocked public client
|
|
138
|
+
mockPublicClient = viem_1.createPublicClient.mock.results[0].value;
|
|
139
|
+
// Setup multicall mock responses
|
|
140
|
+
mockPublicClient.multicall
|
|
141
|
+
// Basic info calls
|
|
142
|
+
.mockResolvedValueOnce([
|
|
143
|
+
{ status: "success", result: MOCK_MARKET_QUESTION },
|
|
144
|
+
{ status: "success", result: MOCK_ADDITIONAL_INFO },
|
|
145
|
+
{ status: "success", result: MOCK_MARKET_SOURCE },
|
|
146
|
+
{ status: "success", result: MOCK_STATUS_NUM },
|
|
147
|
+
{ status: "success", result: MOCK_END_OF_TRADING },
|
|
148
|
+
{ status: "success", result: [MOCK_YES_POOL_ADDRESS, MOCK_NO_POOL_ADDRESS] },
|
|
149
|
+
{ status: "success", result: 0n },
|
|
150
|
+
])
|
|
151
|
+
// Pool info calls
|
|
152
|
+
.mockResolvedValueOnce([
|
|
153
|
+
{ status: "success", result: constants_1.USDC_ADDRESS },
|
|
154
|
+
{ status: "success", result: MOCK_YES_TOKEN_ADDRESS },
|
|
155
|
+
{ status: "success", result: MOCK_NO_TOKEN_ADDRESS },
|
|
156
|
+
{ status: "success", result: constants_1.USDC_ADDRESS },
|
|
157
|
+
{ status: "success", result: [79228162514264337593543950336n, 0, 0, 0, 0, 0, true] },
|
|
158
|
+
{ status: "success", result: [79228162514264337593543950336n, 0, 0, 0, 0, 0, true] },
|
|
159
|
+
])
|
|
160
|
+
// Balance calls
|
|
161
|
+
.mockResolvedValueOnce([
|
|
162
|
+
{ status: "success", result: 1000000n },
|
|
163
|
+
{ status: "success", result: 500000000000000000000n },
|
|
164
|
+
{ status: "success", result: 2000000n },
|
|
165
|
+
{ status: "success", result: 1000000000000000000000n },
|
|
166
|
+
]);
|
|
167
|
+
});
|
|
168
|
+
it("should successfully fetch market details", async () => {
|
|
169
|
+
const args = MOCK_MARKET_ADDRESS;
|
|
170
|
+
const responseString = await provider.getPredictionMarketDetails(mockWallet, args);
|
|
171
|
+
const response = JSON.parse(responseString);
|
|
172
|
+
// Verify the expected JSON structure
|
|
173
|
+
expect(response.success).toBe(true);
|
|
174
|
+
expect(response.marketAddress).toBe(MOCK_MARKET_ADDRESS);
|
|
175
|
+
expect(response.question).toBe(MOCK_MARKET_QUESTION);
|
|
176
|
+
expect(response.additionalInfo).toBe(MOCK_ADDITIONAL_INFO);
|
|
177
|
+
expect(response.source).toBe(MOCK_MARKET_SOURCE);
|
|
178
|
+
expect(response.status).toBe(0);
|
|
179
|
+
// Verify tokens
|
|
180
|
+
expect(response.tokens.yes.lpAddress).toBe(MOCK_YES_POOL_ADDRESS);
|
|
181
|
+
expect(response.tokens.yes.tokenAddress).toBe(MOCK_YES_TOKEN_ADDRESS);
|
|
182
|
+
expect(response.tokens.no.lpAddress).toBe(MOCK_NO_POOL_ADDRESS);
|
|
183
|
+
expect(response.tokens.no.tokenAddress).toBe(MOCK_NO_TOKEN_ADDRESS);
|
|
184
|
+
// Verify prices and tvl exist
|
|
185
|
+
expect(typeof response.prices.yes).toBe("number");
|
|
186
|
+
expect(typeof response.prices.no).toBe("number");
|
|
187
|
+
expect(typeof response.tvl).toBe("number");
|
|
188
|
+
});
|
|
189
|
+
it("should handle errors", async () => {
|
|
190
|
+
const error = new Error("Failed to fetch market details");
|
|
191
|
+
mockWallet.readContract.mockReset();
|
|
192
|
+
mockPublicClient.multicall.mockReset();
|
|
193
|
+
mockPublicClient.multicall.mockRejectedValueOnce(error);
|
|
194
|
+
const args = MOCK_MARKET_ADDRESS;
|
|
195
|
+
const responseString = await provider.getPredictionMarketDetails(mockWallet, args);
|
|
196
|
+
const response = JSON.parse(responseString);
|
|
197
|
+
expect(response.success).toBe(false);
|
|
198
|
+
expect(response.error).toBe("Error retrieving market details: Error: Failed to fetch market details");
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
describe("supportsNetwork", () => {
|
|
202
|
+
it("should return true for base-mainnet", () => {
|
|
203
|
+
const network = {
|
|
204
|
+
networkId: "base-mainnet",
|
|
205
|
+
protocolFamily: "evm",
|
|
206
|
+
};
|
|
207
|
+
expect(provider.supportsNetwork(network)).toBe(true);
|
|
208
|
+
});
|
|
209
|
+
it("should return false for other networks", () => {
|
|
210
|
+
const network = {
|
|
211
|
+
networkId: "ethereum-mainnet",
|
|
212
|
+
protocolFamily: "evm",
|
|
213
|
+
};
|
|
214
|
+
expect(provider.supportsNetwork(network)).toBe(false);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type Slot0Result = readonly [bigint, number, number, number, number, number, boolean];
|
|
2
|
+
export declare const GetMarketStatus: Record<number, string>;
|
|
3
|
+
/**
|
|
4
|
+
* Interface representing a TruthMarket
|
|
5
|
+
*/
|
|
6
|
+
export interface TruthMarket {
|
|
7
|
+
id: number;
|
|
8
|
+
address: string;
|
|
9
|
+
marketQuestion: string;
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetMarketStatus = void 0;
|
|
4
|
+
const constants_1 = require("./constants");
|
|
5
|
+
// Create mapping for status lookup
|
|
6
|
+
exports.GetMarketStatus = Object.entries(constants_1.MarketStatus).reduce((acc, [key, value]) => {
|
|
7
|
+
acc[value] = key;
|
|
8
|
+
return acc;
|
|
9
|
+
}, {});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./zoraActionProvider"), exports);
|
|
18
|
+
__exportStar(require("./schemas"), exports);
|
|
19
|
+
__exportStar(require("./utils"), exports);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const CreateCoinSchema: z.ZodObject<{
|
|
3
|
+
name: z.ZodString;
|
|
4
|
+
symbol: z.ZodString;
|
|
5
|
+
description: z.ZodString;
|
|
6
|
+
image: z.ZodString;
|
|
7
|
+
category: z.ZodDefault<z.ZodString>;
|
|
8
|
+
payoutRecipient: z.ZodOptional<z.ZodString>;
|
|
9
|
+
platformReferrer: z.ZodOptional<z.ZodString>;
|
|
10
|
+
currency: z.ZodDefault<z.ZodEnum<["ZORA", "ETH"]>>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
symbol: string;
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
currency: "ETH" | "ZORA";
|
|
16
|
+
image: string;
|
|
17
|
+
category: string;
|
|
18
|
+
platformReferrer?: string | undefined;
|
|
19
|
+
payoutRecipient?: string | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
symbol: string;
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
image: string;
|
|
25
|
+
currency?: "ETH" | "ZORA" | undefined;
|
|
26
|
+
platformReferrer?: string | undefined;
|
|
27
|
+
category?: string | undefined;
|
|
28
|
+
payoutRecipient?: string | undefined;
|
|
29
|
+
}>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CreateCoinSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.CreateCoinSchema = zod_1.z
|
|
6
|
+
.object({
|
|
7
|
+
name: zod_1.z.string().describe("The name of the coin to create"),
|
|
8
|
+
symbol: zod_1.z.string().describe("The symbol of the coin to create"),
|
|
9
|
+
description: zod_1.z.string().describe("The description of the coin"),
|
|
10
|
+
image: zod_1.z.string().describe("Local image file path or URI (ipfs:// or https://)"),
|
|
11
|
+
category: zod_1.z
|
|
12
|
+
.string()
|
|
13
|
+
.default("social")
|
|
14
|
+
.describe("The category of the coin, optional, defaults to 'social'"),
|
|
15
|
+
payoutRecipient: zod_1.z
|
|
16
|
+
.string()
|
|
17
|
+
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format")
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("The address that will receive creator earnings, defaults to wallet address"),
|
|
20
|
+
platformReferrer: zod_1.z
|
|
21
|
+
.string()
|
|
22
|
+
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format")
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("The address that will receive platform referrer fees, optional"),
|
|
25
|
+
currency: zod_1.z
|
|
26
|
+
.enum(["ZORA", "ETH"])
|
|
27
|
+
.default("ZORA")
|
|
28
|
+
.describe("Currency to be used for the trading pair, optional, defaults to 'ZORA'."),
|
|
29
|
+
})
|
|
30
|
+
.strip()
|
|
31
|
+
.describe("Instructions for creating a new coin on Zora");
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for Pinata
|
|
3
|
+
*/
|
|
4
|
+
interface PinataConfig {
|
|
5
|
+
jwt: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parameters for generating token URI
|
|
9
|
+
*/
|
|
10
|
+
interface TokenUriParams {
|
|
11
|
+
name: string;
|
|
12
|
+
symbol: string;
|
|
13
|
+
description: string;
|
|
14
|
+
image: string;
|
|
15
|
+
category?: string;
|
|
16
|
+
pinataConfig: PinataConfig;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Generates a Zora token URI by handling local file or URI
|
|
20
|
+
*
|
|
21
|
+
* @param params - Parameters for generating the token URI
|
|
22
|
+
* @returns A promise that resolves to object containing the IPFS URI
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateZoraTokenUri(params: TokenUriParams): Promise<{
|
|
25
|
+
uri: string;
|
|
26
|
+
imageUri: string;
|
|
27
|
+
}>;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateZoraTokenUri = generateZoraTokenUri;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Reads a local file and converts it to base64
|
|
11
|
+
*
|
|
12
|
+
* @param imageFileName - Path to the local file
|
|
13
|
+
* @returns Base64 encoded file and mime type
|
|
14
|
+
*/
|
|
15
|
+
async function readFileAsBase64(imageFileName) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
fs_1.default.readFile(imageFileName, (err, data) => {
|
|
18
|
+
if (err) {
|
|
19
|
+
reject(new Error(`Failed to read file: ${err.message}`));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Determine mime type based on file extension
|
|
23
|
+
const extension = path_1.default.extname(imageFileName).toLowerCase();
|
|
24
|
+
let mimeType = "application/octet-stream"; // default
|
|
25
|
+
if (extension === ".png")
|
|
26
|
+
mimeType = "image/png";
|
|
27
|
+
else if (extension === ".jpg" || extension === ".jpeg")
|
|
28
|
+
mimeType = "image/jpeg";
|
|
29
|
+
else if (extension === ".gif")
|
|
30
|
+
mimeType = "image/gif";
|
|
31
|
+
else if (extension === ".svg")
|
|
32
|
+
mimeType = "image/svg+xml";
|
|
33
|
+
const base64 = data.toString("base64");
|
|
34
|
+
resolve({ base64, mimeType });
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Uploads a file to IPFS using Pinata
|
|
40
|
+
*
|
|
41
|
+
* @param params - Configuration and file data
|
|
42
|
+
* @param params.pinataConfig - Pinata configuration including JWT
|
|
43
|
+
* @param params.fileData - Base64 encoded file data
|
|
44
|
+
* @param params.fileName - Name for the uploaded file
|
|
45
|
+
* @param params.mimeType - MIME type of the file
|
|
46
|
+
* @returns Upload response with CID and other details
|
|
47
|
+
*/
|
|
48
|
+
async function uploadFileToIPFS(params) {
|
|
49
|
+
try {
|
|
50
|
+
const formData = new FormData();
|
|
51
|
+
// Convert base64 to Blob and then to File
|
|
52
|
+
const byteCharacters = atob(params.fileData);
|
|
53
|
+
const byteArrays = [];
|
|
54
|
+
for (let offset = 0; offset < byteCharacters.length; offset += 1024) {
|
|
55
|
+
const slice = byteCharacters.slice(offset, offset + 1024);
|
|
56
|
+
const byteNumbers = new Array(slice.length);
|
|
57
|
+
for (let i = 0; i < slice.length; i++) {
|
|
58
|
+
byteNumbers[i] = slice.charCodeAt(i);
|
|
59
|
+
}
|
|
60
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
61
|
+
byteArrays.push(byteArray);
|
|
62
|
+
}
|
|
63
|
+
const blob = new Blob(byteArrays, { type: params.mimeType });
|
|
64
|
+
const file = new File([blob], params.fileName, { type: params.mimeType });
|
|
65
|
+
formData.append("file", file);
|
|
66
|
+
const pinataMetadata = {
|
|
67
|
+
name: params.fileName,
|
|
68
|
+
};
|
|
69
|
+
formData.append("pinataMetadata", JSON.stringify(pinataMetadata));
|
|
70
|
+
const pinataOptions = {
|
|
71
|
+
cidVersion: 1,
|
|
72
|
+
};
|
|
73
|
+
formData.append("pinataOptions", JSON.stringify(pinataOptions));
|
|
74
|
+
const response = await fetch("https://api.pinata.cloud/pinning/pinFileToIPFS", {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: {
|
|
77
|
+
Authorization: `Bearer ${params.pinataConfig.jwt}`,
|
|
78
|
+
},
|
|
79
|
+
body: formData,
|
|
80
|
+
});
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
const error = await response.json();
|
|
83
|
+
throw new Error(`Failed to upload file to IPFS: ${error.message || response.statusText}`);
|
|
84
|
+
}
|
|
85
|
+
const data = await response.json();
|
|
86
|
+
return {
|
|
87
|
+
IpfsHash: data.IpfsHash,
|
|
88
|
+
PinSize: data.PinSize,
|
|
89
|
+
Timestamp: data.Timestamp,
|
|
90
|
+
isDuplicate: data.isDuplicate || false,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
if (error instanceof Error) {
|
|
95
|
+
throw new Error(`Failed to upload file to IPFS: ${error.message}`);
|
|
96
|
+
}
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Uploads JSON data to IPFS using Pinata
|
|
102
|
+
*
|
|
103
|
+
* @param params - Configuration and JSON data
|
|
104
|
+
* @param params.pinataConfig - Pinata configuration including JWT
|
|
105
|
+
* @param params.json - JSON data to upload
|
|
106
|
+
* @returns Upload response with CID and other details
|
|
107
|
+
*/
|
|
108
|
+
async function uploadJsonToIPFS(params) {
|
|
109
|
+
try {
|
|
110
|
+
const requestBody = {
|
|
111
|
+
pinataOptions: {
|
|
112
|
+
cidVersion: 1,
|
|
113
|
+
},
|
|
114
|
+
pinataMetadata: {
|
|
115
|
+
name: `${params.json.name}-metadata.json`,
|
|
116
|
+
},
|
|
117
|
+
pinataContent: params.json,
|
|
118
|
+
};
|
|
119
|
+
const response = await fetch("https://api.pinata.cloud/pinning/pinJSONToIPFS", {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: {
|
|
122
|
+
Authorization: `Bearer ${params.pinataConfig.jwt}`,
|
|
123
|
+
"Content-Type": "application/json",
|
|
124
|
+
},
|
|
125
|
+
body: JSON.stringify(requestBody),
|
|
126
|
+
});
|
|
127
|
+
if (!response.ok) {
|
|
128
|
+
const error = await response.json();
|
|
129
|
+
throw new Error(`Failed to upload JSON to IPFS: ${error.message || response.statusText}`);
|
|
130
|
+
}
|
|
131
|
+
const data = await response.json();
|
|
132
|
+
return {
|
|
133
|
+
IpfsHash: data.IpfsHash,
|
|
134
|
+
PinSize: data.PinSize,
|
|
135
|
+
Timestamp: data.Timestamp,
|
|
136
|
+
isDuplicate: data.isDuplicate || false,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
if (error instanceof Error) {
|
|
141
|
+
throw new Error(`Failed to upload JSON to IPFS: ${error.message}`);
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Generates a Zora token URI by handling local file or URI
|
|
148
|
+
*
|
|
149
|
+
* @param params - Parameters for generating the token URI
|
|
150
|
+
* @returns A promise that resolves to object containing the IPFS URI
|
|
151
|
+
*/
|
|
152
|
+
async function generateZoraTokenUri(params) {
|
|
153
|
+
try {
|
|
154
|
+
let imageUri;
|
|
155
|
+
// Check if image is already a URI (ipfs:// or https://)
|
|
156
|
+
if (params.image.startsWith("ipfs://") || params.image.startsWith("https://")) {
|
|
157
|
+
imageUri = params.image;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// Handle local file
|
|
161
|
+
const { base64, mimeType } = await readFileAsBase64(params.image);
|
|
162
|
+
const fileName = path_1.default.basename(params.image);
|
|
163
|
+
const imageRes = await uploadFileToIPFS({
|
|
164
|
+
pinataConfig: params.pinataConfig,
|
|
165
|
+
fileData: base64,
|
|
166
|
+
fileName,
|
|
167
|
+
mimeType,
|
|
168
|
+
});
|
|
169
|
+
imageUri = `ipfs://${imageRes.IpfsHash}`;
|
|
170
|
+
}
|
|
171
|
+
// Create and upload the metadata
|
|
172
|
+
const metadata = {
|
|
173
|
+
name: params.name,
|
|
174
|
+
description: params.description,
|
|
175
|
+
symbol: params.symbol,
|
|
176
|
+
image: imageUri,
|
|
177
|
+
content: {
|
|
178
|
+
uri: imageUri,
|
|
179
|
+
mime: imageUri.startsWith("ipfs://") || imageUri.startsWith("https://")
|
|
180
|
+
? "image/*"
|
|
181
|
+
: "image/png",
|
|
182
|
+
},
|
|
183
|
+
properties: {
|
|
184
|
+
category: params.category || "social",
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
const metadataRes = await uploadJsonToIPFS({
|
|
188
|
+
pinataConfig: params.pinataConfig,
|
|
189
|
+
json: metadata,
|
|
190
|
+
});
|
|
191
|
+
const uri = `ipfs://${metadataRes.IpfsHash}`;
|
|
192
|
+
return { uri, imageUri };
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
if (error instanceof Error) {
|
|
196
|
+
throw new Error(`Failed to generate Zora token URI: ${error.message}`);
|
|
197
|
+
}
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ActionProvider } from "../actionProvider";
|
|
3
|
+
import { EvmWalletProvider } from "../../wallet-providers/evmWalletProvider";
|
|
4
|
+
import { CreateCoinSchema } from "./schemas";
|
|
5
|
+
import { Network } from "../../network";
|
|
6
|
+
/**
|
|
7
|
+
* ZoraActionProvider provides actions for interacting with the Zora protocol.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ZoraActionProvider extends ActionProvider<EvmWalletProvider> {
|
|
10
|
+
#private;
|
|
11
|
+
/**
|
|
12
|
+
* Constructor for the ZoraActionProvider.
|
|
13
|
+
*/
|
|
14
|
+
constructor();
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new Zora coin.
|
|
17
|
+
*
|
|
18
|
+
* @param walletProvider - The wallet provider to use for the transaction.
|
|
19
|
+
* @param args - The input arguments for the action.
|
|
20
|
+
* @returns A message containing the coin creation details.
|
|
21
|
+
*/
|
|
22
|
+
createCoin(walletProvider: EvmWalletProvider, args: z.infer<typeof CreateCoinSchema>): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Checks if the Zora action provider supports the given network.
|
|
25
|
+
*
|
|
26
|
+
* @param network - The network to check.
|
|
27
|
+
* @returns True if the Zora action provider supports the network, false otherwise.
|
|
28
|
+
*/
|
|
29
|
+
supportsNetwork: (network: Network) => boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Factory function to create a new ZoraActionProvider instance.
|
|
33
|
+
*
|
|
34
|
+
* @returns A new ZoraActionProvider instance
|
|
35
|
+
*/
|
|
36
|
+
export declare const zoraActionProvider: () => ZoraActionProvider;
|