@medialane/sdk 0.2.0 → 0.2.2
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 +266 -215
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,48 +1,59 @@
|
|
|
1
|
-
<img width="1260" height="640" alt="
|
|
1
|
+
<img width="1260" height="640" alt="Medialane SDK" src="https://github.com/user-attachments/assets/a72bca86-bb82-42c4-8f61-9558484df5b9" />
|
|
2
2
|
|
|
3
|
-
#
|
|
3
|
+
# @medialane/sdk
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Framework-agnostic TypeScript SDK for the Medialane IP marketplace on Starknet**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The Medialane SDK provides a unified interface for interacting with the Medialane marketplace — both **on-chain operations** (create listings, make offers, fulfill orders, mint IP assets) and **REST API access** (search tokens, manage orders, upload metadata to IPFS). Built for [Medialane.io](https://medialane.io) and [Medialane.xyz](https://medialane.xyz).
|
|
8
|
+
|
|
9
|
+
---
|
|
8
10
|
|
|
9
11
|
## Features
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
**On-Chain Operations**
|
|
12
14
|
- Create listings (ERC-721 for sale)
|
|
13
15
|
- Make offers (bid with ERC-20)
|
|
14
16
|
- Fulfill orders (purchase NFTs)
|
|
15
17
|
- Cancel active orders
|
|
16
|
-
- Atomic multi-item checkout
|
|
18
|
+
- Atomic multi-item cart checkout
|
|
17
19
|
- Built-in approval checking
|
|
18
20
|
- SNIP-12 typed data signing
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
- Mint IP NFTs into any collection
|
|
22
|
+
- Deploy new ERC-721 collections
|
|
23
|
+
|
|
24
|
+
**REST API Client**
|
|
25
|
+
- Query orders, tokens, collections, and activities
|
|
26
|
+
- Full-text search across the marketplace
|
|
27
|
+
- Intent-based transaction orchestration
|
|
28
|
+
- Upload metadata and files to IPFS (Pinata)
|
|
29
|
+
- Tenant portal: API keys, webhooks, usage
|
|
30
|
+
|
|
31
|
+
**IP Metadata Types**
|
|
32
|
+
- `IpAttribute` — typed OpenSea ERC-721 attribute
|
|
33
|
+
- `IpNftMetadata` — full IPFS metadata shape with licensing fields
|
|
34
|
+
- `ApiTokenMetadata` — indexed token metadata with all licensing attributes
|
|
35
|
+
- Berne Convention-compatible licensing data model
|
|
36
|
+
|
|
37
|
+
**Developer-Friendly**
|
|
28
38
|
- Framework-agnostic TypeScript
|
|
29
|
-
- Dual ESM
|
|
30
|
-
- Zod schema validation
|
|
39
|
+
- Dual ESM + CJS builds
|
|
40
|
+
- Zod schema config validation
|
|
31
41
|
- Full type safety
|
|
32
|
-
- Zero runtime dependencies (except Zod)
|
|
33
42
|
- Peer dependency: `starknet >= 6.0.0`
|
|
34
43
|
|
|
44
|
+
---
|
|
45
|
+
|
|
35
46
|
## Installation
|
|
36
47
|
|
|
37
48
|
```bash
|
|
38
49
|
npm install @medialane/sdk starknet
|
|
39
50
|
# or
|
|
40
|
-
yarn add @medialane/sdk starknet
|
|
41
|
-
# or
|
|
42
51
|
bun add @medialane/sdk starknet
|
|
52
|
+
# or
|
|
53
|
+
yarn add @medialane/sdk starknet
|
|
43
54
|
```
|
|
44
55
|
|
|
45
|
-
|
|
56
|
+
---
|
|
46
57
|
|
|
47
58
|
## Quick Start
|
|
48
59
|
|
|
@@ -53,63 +64,43 @@ import { MedialaneClient } from "@medialane/sdk";
|
|
|
53
64
|
|
|
54
65
|
const client = new MedialaneClient({
|
|
55
66
|
network: "mainnet", // "mainnet" | "sepolia"
|
|
56
|
-
rpcUrl: "https://starknet-mainnet.public.blastapi.io", // optional;
|
|
57
|
-
backendUrl: "https://api.medialane.xyz", //
|
|
58
|
-
apiKey: "ml_live_...", //
|
|
67
|
+
rpcUrl: "https://starknet-mainnet.public.blastapi.io", // optional; defaults to BlastAPI
|
|
68
|
+
backendUrl: "https://api.medialane.xyz", // required for .api methods
|
|
69
|
+
apiKey: "ml_live_...", // from Medialane Portal
|
|
59
70
|
});
|
|
60
71
|
```
|
|
61
72
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
// Get active listings
|
|
66
|
-
const orders = await client.api.getOrders({
|
|
67
|
-
status: "active",
|
|
68
|
-
sort: "newest",
|
|
69
|
-
page: 1,
|
|
70
|
-
limit: 20,
|
|
71
|
-
});
|
|
73
|
+
---
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
const search = await client.api.search("vintage-nft", 10);
|
|
75
|
+
## Marketplace Operations (On-Chain)
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
const activities = await client.api.getActivities({
|
|
78
|
-
type: "sale",
|
|
79
|
-
page: 1
|
|
80
|
-
});
|
|
81
|
-
```
|
|
77
|
+
All methods require a `starknet.js` `AccountInterface`. Nonce management, SNIP-12 signing, and `waitForTransaction` are handled automatically.
|
|
82
78
|
|
|
83
|
-
### Create a Listing
|
|
79
|
+
### Create a Listing
|
|
84
80
|
|
|
85
81
|
```typescript
|
|
86
82
|
import { Account } from "starknet";
|
|
87
83
|
|
|
88
|
-
const account: Account = /* your starknet.js Account */;
|
|
89
|
-
|
|
90
84
|
const result = await client.marketplace.createListing(account, {
|
|
91
|
-
nftContract: "
|
|
85
|
+
nftContract: "0x05e73b7...",
|
|
92
86
|
tokenId: 42n,
|
|
93
|
-
currency: "USDC",
|
|
87
|
+
currency: "USDC",
|
|
94
88
|
price: "1000000", // 1 USDC (6 decimals)
|
|
95
|
-
endTime: Math.floor(Date.now() / 1000) + 86400 * 30, // 30 days
|
|
89
|
+
endTime: Math.floor(Date.now() / 1000) + 86400 * 30, // 30 days
|
|
96
90
|
});
|
|
97
|
-
|
|
98
|
-
console.log("Listing created:", result.txHash);
|
|
91
|
+
console.log("Listed:", result.txHash);
|
|
99
92
|
```
|
|
100
93
|
|
|
101
94
|
### Make an Offer
|
|
102
95
|
|
|
103
96
|
```typescript
|
|
104
97
|
const result = await client.marketplace.makeOffer(account, {
|
|
105
|
-
nftContract: "
|
|
98
|
+
nftContract: "0x05e73b7...",
|
|
106
99
|
tokenId: 42n,
|
|
107
100
|
currency: "USDC",
|
|
108
101
|
price: "500000", // 0.5 USDC
|
|
109
|
-
endTime: Math.floor(Date.now() / 1000) + 86400 * 7,
|
|
102
|
+
endTime: Math.floor(Date.now() / 1000) + 86400 * 7,
|
|
110
103
|
});
|
|
111
|
-
|
|
112
|
-
console.log("Offer created:", result.txHash);
|
|
113
104
|
```
|
|
114
105
|
|
|
115
106
|
### Fulfill an Order
|
|
@@ -117,227 +108,271 @@ console.log("Offer created:", result.txHash);
|
|
|
117
108
|
```typescript
|
|
118
109
|
const result = await client.marketplace.fulfillOrder(account, {
|
|
119
110
|
orderHash: "0x...",
|
|
120
|
-
fulfiller:
|
|
111
|
+
fulfiller: account.address,
|
|
121
112
|
});
|
|
122
|
-
|
|
123
|
-
console.log("Order fulfilled:", result.txHash);
|
|
124
113
|
```
|
|
125
114
|
|
|
126
|
-
### Checkout Multiple Items
|
|
115
|
+
### Cart Checkout (Multiple Items)
|
|
127
116
|
|
|
128
117
|
```typescript
|
|
129
118
|
const result = await client.marketplace.checkoutCart(account, [
|
|
130
|
-
{
|
|
131
|
-
|
|
132
|
-
fulfiller: "0x...",
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
orderHash: "0x...",
|
|
136
|
-
fulfiller: "0x...",
|
|
137
|
-
},
|
|
119
|
+
{ orderHash: "0x...", fulfiller: account.address },
|
|
120
|
+
{ orderHash: "0x...", fulfiller: account.address },
|
|
138
121
|
]);
|
|
139
|
-
|
|
140
|
-
console.log("Cart checked out:", result.txHash);
|
|
141
122
|
```
|
|
142
123
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
The `MedialaneClient` constructor accepts a `MedialaneConfig` object with the following options:
|
|
146
|
-
|
|
147
|
-
| Option | Type | Default | Description |
|
|
148
|
-
|--------|------|---------|-------------|
|
|
149
|
-
| `network` | `"mainnet" \| "sepolia"` | `"mainnet"` | Starknet network |
|
|
150
|
-
| `rpcUrl` | `string` | BlastAPI endpoint | JSON-RPC URL for the network |
|
|
151
|
-
| `backendUrl` | `string` | *(required for `.api` calls)* | Medialane backend API base URL |
|
|
152
|
-
| `apiKey` | `string` | - | API key for authenticated routes (obtained from Medialane Portal) |
|
|
153
|
-
| `marketplaceContract` | `string` | Network-specific default | Marketplace contract address |
|
|
124
|
+
### Cancel an Order
|
|
154
125
|
|
|
155
|
-
|
|
126
|
+
```typescript
|
|
127
|
+
const result = await client.marketplace.cancelOrder(account, {
|
|
128
|
+
orderHash: "0x...",
|
|
129
|
+
offerer: account.address,
|
|
130
|
+
});
|
|
131
|
+
```
|
|
156
132
|
|
|
157
|
-
|
|
133
|
+
### Mint an IP Asset
|
|
158
134
|
|
|
159
|
-
|
|
135
|
+
```typescript
|
|
136
|
+
const result = await client.marketplace.mint(account, {
|
|
137
|
+
collectionId: "1", // collection ID on the registry
|
|
138
|
+
recipient: account.address,
|
|
139
|
+
tokenUri: "ipfs://...", // IPFS URI of the metadata JSON
|
|
140
|
+
});
|
|
141
|
+
```
|
|
160
142
|
|
|
161
|
-
|
|
143
|
+
### Deploy a Collection
|
|
162
144
|
|
|
163
|
-
|
|
145
|
+
```typescript
|
|
146
|
+
const result = await client.marketplace.createCollection(account, {
|
|
147
|
+
name: "My Creative Works",
|
|
148
|
+
symbol: "MCW",
|
|
149
|
+
baseUri: "",
|
|
150
|
+
});
|
|
151
|
+
```
|
|
164
152
|
|
|
165
|
-
|
|
166
|
-
|--------|-------------|
|
|
167
|
-
| `createListing(account, params)` | List an ERC-721 for sale. Auto-checks approval; includes approve call if needed. |
|
|
168
|
-
| `makeOffer(account, params)` | Bid on an ERC-721 with ERC-20. Includes token approval + order registration. |
|
|
169
|
-
| `fulfillOrder(account, params)` | Purchase a listed NFT. Fetches nonce and signs fulfillment typed data. |
|
|
170
|
-
| `cancelOrder(account, params)` | Cancel an active order. Fetches nonce and signs cancellation typed data. |
|
|
171
|
-
| `checkoutCart(account, items)` | Atomic multicall for multiple purchases. One approve per unique token, sequential nonces. |
|
|
153
|
+
---
|
|
172
154
|
|
|
173
|
-
|
|
155
|
+
## REST API
|
|
174
156
|
|
|
175
|
-
|
|
176
|
-
|--------|-------------|
|
|
177
|
-
| `getOrderDetails(orderHash)` | Fetch order details from the contract. |
|
|
178
|
-
| `getNonce(address)` | Get the current nonce for an address. |
|
|
157
|
+
### Query Orders
|
|
179
158
|
|
|
180
|
-
|
|
159
|
+
```typescript
|
|
160
|
+
const orders = await client.api.getOrders({
|
|
161
|
+
status: "ACTIVE",
|
|
162
|
+
sort: "price_asc",
|
|
163
|
+
currency: "0x033068...", // USDC address
|
|
164
|
+
page: 1,
|
|
165
|
+
limit: 20,
|
|
166
|
+
});
|
|
181
167
|
|
|
182
|
-
|
|
168
|
+
const order = await client.api.getOrder("0x...");
|
|
169
|
+
const tokenOrders = await client.api.getActiveOrdersForToken(contract, tokenId);
|
|
170
|
+
const userOrders = await client.api.getOrdersByUser(address);
|
|
171
|
+
```
|
|
183
172
|
|
|
184
|
-
|
|
173
|
+
### Query Tokens
|
|
185
174
|
|
|
186
175
|
```typescript
|
|
187
|
-
client.api.
|
|
188
|
-
client.api.
|
|
189
|
-
client.api.
|
|
190
|
-
client.api.getOrdersByUser(address, ...) // Get orders by user
|
|
176
|
+
const token = await client.api.getToken(contract, tokenId);
|
|
177
|
+
const tokens = await client.api.getTokensByOwner(address);
|
|
178
|
+
const history = await client.api.getTokenHistory(contract, tokenId);
|
|
191
179
|
```
|
|
192
180
|
|
|
193
|
-
|
|
181
|
+
### Query Collections
|
|
194
182
|
|
|
195
183
|
```typescript
|
|
196
|
-
client.api.
|
|
197
|
-
client.api.
|
|
198
|
-
client.api.
|
|
184
|
+
const collections = await client.api.getCollections();
|
|
185
|
+
const collection = await client.api.getCollection(contract);
|
|
186
|
+
const tokens = await client.api.getCollectionTokens(contract);
|
|
199
187
|
```
|
|
200
188
|
|
|
201
|
-
|
|
189
|
+
### Search
|
|
202
190
|
|
|
203
191
|
```typescript
|
|
204
|
-
client.api.
|
|
205
|
-
|
|
206
|
-
|
|
192
|
+
const results = await client.api.search("landscape painting", 10);
|
|
193
|
+
// results.data.tokens — matching tokens
|
|
194
|
+
// results.data.collections — matching collections
|
|
207
195
|
```
|
|
208
196
|
|
|
209
|
-
|
|
197
|
+
### Activities
|
|
210
198
|
|
|
211
199
|
```typescript
|
|
212
|
-
client.api.getActivities(
|
|
213
|
-
client.api.getActivitiesByAddress(address)
|
|
200
|
+
const feed = await client.api.getActivities({ type: "sale", page: 1 });
|
|
201
|
+
const userFeed = await client.api.getActivitiesByAddress(address);
|
|
214
202
|
```
|
|
215
203
|
|
|
216
|
-
|
|
204
|
+
### Upload Metadata to IPFS
|
|
217
205
|
|
|
218
206
|
```typescript
|
|
219
|
-
|
|
207
|
+
// Upload a file
|
|
208
|
+
const fileResult = await client.api.uploadFile(imageFile);
|
|
209
|
+
// fileResult.data.url → "ipfs://..."
|
|
210
|
+
|
|
211
|
+
// Upload metadata JSON
|
|
212
|
+
const metaResult = await client.api.uploadMetadata({
|
|
213
|
+
name: "My Work",
|
|
214
|
+
description: "...",
|
|
215
|
+
image: "ipfs://...",
|
|
216
|
+
external_url: "https://medialane.io",
|
|
217
|
+
attributes: [
|
|
218
|
+
{ trait_type: "License", value: "CC BY-NC" },
|
|
219
|
+
{ trait_type: "Commercial Use", value: "No" },
|
|
220
|
+
// ...
|
|
221
|
+
],
|
|
222
|
+
});
|
|
223
|
+
// metaResult.data.url → "ipfs://..."
|
|
220
224
|
```
|
|
221
225
|
|
|
222
|
-
|
|
226
|
+
### Intents (Advanced)
|
|
227
|
+
|
|
228
|
+
The intent system handles the SNIP-12 signing flow for marketplace operations:
|
|
223
229
|
|
|
224
230
|
```typescript
|
|
225
|
-
|
|
226
|
-
client.api.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
+
// 1. Create intent (gets typedData to sign)
|
|
232
|
+
const intent = await client.api.createListingIntent({
|
|
233
|
+
offerer: address,
|
|
234
|
+
nftContract: "0x...",
|
|
235
|
+
tokenId: "42",
|
|
236
|
+
currency: "0x033068...",
|
|
237
|
+
price: "1000000",
|
|
238
|
+
endTime: Math.floor(Date.now() / 1000) + 86400 * 30,
|
|
239
|
+
});
|
|
231
240
|
|
|
232
|
-
|
|
241
|
+
// 2. Sign typedData
|
|
242
|
+
const signature = await account.signMessage(intent.data.typedData);
|
|
233
243
|
|
|
234
|
-
|
|
235
|
-
client.api.
|
|
236
|
-
client.api.uploadFile(file) // Upload file to IPFS
|
|
237
|
-
client.api.resolveMetadata(uri) // Resolve ipfs://, data:, https://
|
|
238
|
-
client.api.getMetadataSignedUrl() // Get presigned Pinata URL
|
|
244
|
+
// 3. Submit signature
|
|
245
|
+
await client.api.submitIntentSignature(intent.data.id, toSignatureArray(signature));
|
|
239
246
|
```
|
|
240
247
|
|
|
241
|
-
|
|
248
|
+
Mint and collection intents are pre-signed — no signature step needed:
|
|
242
249
|
|
|
243
250
|
```typescript
|
|
244
|
-
client.api.
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
251
|
+
const mintIntent = await client.api.createMintIntent({
|
|
252
|
+
owner: ownerAddress,
|
|
253
|
+
collectionId: "1",
|
|
254
|
+
recipient: recipientAddress,
|
|
255
|
+
tokenUri: "ipfs://...",
|
|
256
|
+
});
|
|
257
|
+
// mintIntent.data.calls → ready to execute
|
|
249
258
|
```
|
|
250
259
|
|
|
251
|
-
|
|
260
|
+
---
|
|
252
261
|
|
|
253
|
-
|
|
262
|
+
## IP Metadata Types
|
|
254
263
|
|
|
255
264
|
```typescript
|
|
256
|
-
import {
|
|
257
|
-
|
|
258
|
-
//
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
265
|
+
import type { IpAttribute, IpNftMetadata, ApiTokenMetadata } from "@medialane/sdk";
|
|
266
|
+
|
|
267
|
+
// Single OpenSea ERC-721 attribute
|
|
268
|
+
const attr: IpAttribute = { trait_type: "License", value: "CC BY-NC-SA" };
|
|
269
|
+
|
|
270
|
+
// Full IPFS metadata shape for a Medialane IP NFT
|
|
271
|
+
const metadata: IpNftMetadata = {
|
|
272
|
+
name: "My Track",
|
|
273
|
+
description: "Original music",
|
|
274
|
+
image: "ipfs://...",
|
|
275
|
+
external_url: "https://medialane.io",
|
|
276
|
+
attributes: [
|
|
277
|
+
{ trait_type: "IP Type", value: "Music" },
|
|
278
|
+
{ trait_type: "License", value: "CC BY-NC-SA" },
|
|
279
|
+
{ trait_type: "Commercial Use", value: "No" },
|
|
280
|
+
{ trait_type: "Derivatives", value: "Share-Alike" },
|
|
281
|
+
{ trait_type: "Attribution", value: "Required" },
|
|
282
|
+
{ trait_type: "Territory", value: "Worldwide" },
|
|
283
|
+
{ trait_type: "AI Policy", value: "Not Allowed" },
|
|
284
|
+
{ trait_type: "Royalty", value: "10%" },
|
|
285
|
+
{ trait_type: "Standard", value: "Berne Convention" },
|
|
286
|
+
{ trait_type: "Registration", value: "2026-03-06" },
|
|
287
|
+
],
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// Token from the API — includes indexed licensing fields for fast access
|
|
291
|
+
const token = await client.api.getToken(contract, tokenId);
|
|
292
|
+
token.data.metadata.licenseType; // "CC BY-NC-SA"
|
|
293
|
+
token.data.metadata.commercialUse; // "No"
|
|
294
|
+
token.data.metadata.derivatives; // "Share-Alike"
|
|
295
|
+
token.data.metadata.attributes; // IpAttribute[] | null
|
|
275
296
|
```
|
|
276
297
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
The following tokens are supported for on-chain operations:
|
|
298
|
+
---
|
|
280
299
|
|
|
281
|
-
|
|
282
|
-
|--------|---------|----------|
|
|
283
|
-
| USDC | `0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8` | 6 |
|
|
284
|
-
| USDT | `0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8` | 6 |
|
|
285
|
-
| ETH | `0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7` | 18 |
|
|
286
|
-
| STRK | `0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d` | 18 |
|
|
300
|
+
## Supported Tokens
|
|
287
301
|
|
|
288
|
-
|
|
302
|
+
| Symbol | Type | Address | Decimals |
|
|
303
|
+
|---|---|---|---|
|
|
304
|
+
| USDC | Circle-native (canonical) | `0x033068f6539f8e6e6b131e6b2b814e6c34a5224bc66947c47dab9dfee93b35fb` | 6 |
|
|
305
|
+
| USDC.e | Bridged (Starkgate) | `0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8` | 6 |
|
|
306
|
+
| USDT | Tether | `0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8` | 6 |
|
|
307
|
+
| ETH | Ether | `0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7` | 18 |
|
|
308
|
+
| STRK | Starknet native | `0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d` | 18 |
|
|
289
309
|
|
|
290
310
|
```typescript
|
|
291
|
-
import { getTokenBySymbol, getTokenByAddress } from "@medialane/sdk";
|
|
311
|
+
import { getTokenBySymbol, getTokenByAddress, SUPPORTED_TOKENS } from "@medialane/sdk";
|
|
292
312
|
|
|
293
313
|
const usdc = getTokenBySymbol("USDC");
|
|
294
|
-
const token = getTokenByAddress("
|
|
295
|
-
|
|
296
|
-
console.log(usdc.decimals, token.address);
|
|
314
|
+
const token = getTokenByAddress("0x033068...");
|
|
297
315
|
```
|
|
298
316
|
|
|
299
|
-
|
|
317
|
+
---
|
|
300
318
|
|
|
301
|
-
|
|
319
|
+
## Utilities
|
|
302
320
|
|
|
303
321
|
```typescript
|
|
304
322
|
import {
|
|
305
|
-
normalizeAddress,
|
|
306
|
-
shortenAddress,
|
|
307
|
-
parseAmount,
|
|
308
|
-
formatAmount,
|
|
309
|
-
stringifyBigInts,
|
|
323
|
+
normalizeAddress, // Pad to 64-char 0x-prefixed lowercase hex
|
|
324
|
+
shortenAddress, // → "0x1234...5678"
|
|
325
|
+
parseAmount, // Human-readable → smallest unit BigInt ("1.5", 6) → 1500000n
|
|
326
|
+
formatAmount, // Smallest unit → human-readable ("1500000", 6) → "1.5"
|
|
327
|
+
stringifyBigInts, // Recursively convert BigInt → string (for JSON)
|
|
328
|
+
u256ToBigInt, // u256 { low, high } → BigInt
|
|
310
329
|
} from "@medialane/sdk";
|
|
311
|
-
|
|
312
|
-
// Address utilities
|
|
313
|
-
const addr = normalizeAddress("0x123ABC");
|
|
314
|
-
const short = shortenAddress("0x123abc456def789012345678901234567890");
|
|
315
|
-
|
|
316
|
-
// Token amounts
|
|
317
|
-
const amountWei = parseAmount("1.5", 6); // "1500000" (USDC)
|
|
318
|
-
const readable = formatAmount("1500000", 6); // "1.5"
|
|
319
330
|
```
|
|
320
331
|
|
|
321
|
-
|
|
332
|
+
---
|
|
322
333
|
|
|
323
|
-
|
|
334
|
+
## Error Handling
|
|
324
335
|
|
|
325
336
|
```typescript
|
|
326
|
-
import {
|
|
337
|
+
import { MedialaneError, MedialaneApiError } from "@medialane/sdk";
|
|
327
338
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
339
|
+
// On-chain errors (marketplace module)
|
|
340
|
+
try {
|
|
341
|
+
await client.marketplace.createListing(account, params);
|
|
342
|
+
} catch (err) {
|
|
343
|
+
if (err instanceof MedialaneError) {
|
|
344
|
+
console.error("On-chain error:", err.message, err.cause);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
331
347
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
})
|
|
348
|
+
// REST API errors
|
|
349
|
+
try {
|
|
350
|
+
await client.api.getOrders();
|
|
351
|
+
} catch (err) {
|
|
352
|
+
if (err instanceof MedialaneApiError) {
|
|
353
|
+
console.error(`API ${err.status}:`, err.message);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
336
356
|
```
|
|
337
357
|
|
|
338
|
-
|
|
358
|
+
---
|
|
339
359
|
|
|
340
|
-
|
|
360
|
+
## Configuration Reference
|
|
361
|
+
|
|
362
|
+
| Option | Type | Default | Description |
|
|
363
|
+
|---|---|---|---|
|
|
364
|
+
| `network` | `"mainnet" \| "sepolia"` | `"mainnet"` | Starknet network |
|
|
365
|
+
| `rpcUrl` | `string` | BlastAPI public endpoint | JSON-RPC URL |
|
|
366
|
+
| `backendUrl` | `string` | — | Medialane API base URL (required for `.api.*`) |
|
|
367
|
+
| `apiKey` | `string` | — | API key from [Medialane Portal](https://medialane.xyz) |
|
|
368
|
+
| `marketplaceContract` | `string` | Mainnet default | Marketplace contract override |
|
|
369
|
+
| `collectionContract` | `string` | Mainnet default | Collection registry override |
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Advanced: SNIP-12 Typed Data Builders
|
|
374
|
+
|
|
375
|
+
For integrations that handle signing externally (e.g. ChipiPay, Cartridge Controller):
|
|
341
376
|
|
|
342
377
|
```typescript
|
|
343
378
|
import {
|
|
@@ -348,33 +383,49 @@ import {
|
|
|
348
383
|
|
|
349
384
|
const typedData = buildOrderTypedData(orderParams, chainId);
|
|
350
385
|
const signature = await account.signMessage(typedData);
|
|
351
|
-
|
|
352
|
-
// Signature can then be submitted via API intents
|
|
353
|
-
await client.api.submitIntentSignature(intentId, signature);
|
|
386
|
+
await client.api.submitIntentSignature(intentId, signatureArray);
|
|
354
387
|
```
|
|
355
388
|
|
|
356
|
-
|
|
389
|
+
---
|
|
357
390
|
|
|
358
|
-
|
|
391
|
+
## Development
|
|
359
392
|
|
|
360
393
|
```bash
|
|
361
|
-
bun run build # Compile to dist/ (ESM + CJS)
|
|
394
|
+
bun run build # Compile to dist/ (ESM + CJS dual output)
|
|
362
395
|
bun run dev # Watch mode
|
|
363
|
-
bun run typecheck #
|
|
396
|
+
bun run typecheck # tsc --noEmit
|
|
364
397
|
```
|
|
365
398
|
|
|
366
|
-
|
|
367
|
-
- **tsup**
|
|
368
|
-
- **TypeScript**
|
|
369
|
-
- **Zod**
|
|
399
|
+
Built with:
|
|
400
|
+
- **tsup** — dual ESM/CJS bundling
|
|
401
|
+
- **TypeScript** — full type safety
|
|
402
|
+
- **Zod** — runtime config validation
|
|
403
|
+
- Peer dep: `starknet >= 6.0.0`
|
|
370
404
|
|
|
371
|
-
|
|
405
|
+
---
|
|
372
406
|
|
|
373
|
-
|
|
407
|
+
## Changelog
|
|
408
|
+
|
|
409
|
+
### v0.2.0
|
|
410
|
+
- `IpAttribute` and `IpNftMetadata` interfaces for IP metadata
|
|
411
|
+
- `ApiTokenMetadata.attributes` typed as `IpAttribute[] | null` (was `unknown`)
|
|
412
|
+
- `ApiTokenMetadata` extended with `derivatives`, `attribution`, `territory`, `aiPolicy`, `royalty`, `registration`, `standard`
|
|
413
|
+
- Added `USDC.e` (bridged USDC via Starkgate) to `SUPPORTED_TOKENS`
|
|
414
|
+
|
|
415
|
+
### v0.1.0
|
|
416
|
+
- Initial release — orders, tokens, collections, activities, intents, metadata, portal
|
|
374
417
|
|
|
375
|
-
|
|
418
|
+
---
|
|
376
419
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
- **
|
|
380
|
-
- **
|
|
420
|
+
## Links
|
|
421
|
+
|
|
422
|
+
- **Marketplace**: [medialane.io](https://medialane.io)
|
|
423
|
+
- **Developer Portal**: [medialane.xyz](https://medialane.xyz)
|
|
424
|
+
- **npm**: [npmjs.com/package/@medialane/sdk](https://www.npmjs.com/package/@medialane/sdk)
|
|
425
|
+
- **GitHub**: [github.com/medialane-io](https://github.com/medialane-io)
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## License
|
|
430
|
+
|
|
431
|
+
[MIT](LICENSE)
|
package/dist/index.d.cts
CHANGED
|
@@ -302,6 +302,9 @@ interface ApiCollection {
|
|
|
302
302
|
chain: string;
|
|
303
303
|
contractAddress: string;
|
|
304
304
|
name: string | null;
|
|
305
|
+
symbol: string | null;
|
|
306
|
+
description: string | null;
|
|
307
|
+
image: string | null;
|
|
305
308
|
startBlock: string;
|
|
306
309
|
isKnown: boolean;
|
|
307
310
|
floorPrice: string | null;
|
|
@@ -416,7 +419,10 @@ interface CreateCollectionIntentParams {
|
|
|
416
419
|
owner: string;
|
|
417
420
|
name: string;
|
|
418
421
|
symbol: string;
|
|
419
|
-
|
|
422
|
+
/** Optional description stored server-side and surfaced on the collection page. */
|
|
423
|
+
description?: string;
|
|
424
|
+
/** Base URI for token metadata. Defaults to empty string if not provided. */
|
|
425
|
+
baseUri?: string;
|
|
420
426
|
/** Optional: override the default collection contract address */
|
|
421
427
|
collectionContract?: string;
|
|
422
428
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -302,6 +302,9 @@ interface ApiCollection {
|
|
|
302
302
|
chain: string;
|
|
303
303
|
contractAddress: string;
|
|
304
304
|
name: string | null;
|
|
305
|
+
symbol: string | null;
|
|
306
|
+
description: string | null;
|
|
307
|
+
image: string | null;
|
|
305
308
|
startBlock: string;
|
|
306
309
|
isKnown: boolean;
|
|
307
310
|
floorPrice: string | null;
|
|
@@ -416,7 +419,10 @@ interface CreateCollectionIntentParams {
|
|
|
416
419
|
owner: string;
|
|
417
420
|
name: string;
|
|
418
421
|
symbol: string;
|
|
419
|
-
|
|
422
|
+
/** Optional description stored server-side and surfaced on the collection page. */
|
|
423
|
+
description?: string;
|
|
424
|
+
/** Base URI for token metadata. Defaults to empty string if not provided. */
|
|
425
|
+
baseUri?: string;
|
|
420
426
|
/** Optional: override the default collection contract address */
|
|
421
427
|
collectionContract?: string;
|
|
422
428
|
}
|