@campnetwork/origin 1.2.8 → 1.3.0-alpha.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.
- package/README.md +403 -34
- package/dist/core.cjs +519 -89
- package/dist/core.d.ts +549 -15
- package/dist/core.esm.d.ts +549 -15
- package/dist/core.esm.js +513 -99
- package/dist/react/index.esm.d.ts +545 -12
- package/dist/react/index.esm.js +4329 -848
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ The Origin SDK currently exposes the following modules:
|
|
|
18
18
|
- `Auth` - For authenticating users with the Origin SDK (browser and Node.js)
|
|
19
19
|
- Signer adapters and utilities for Node.js support (ethers, viem, custom signers)
|
|
20
20
|
- Camp Network chain configurations (`campMainnet`, `campTestnet`)
|
|
21
|
-
- Origin utilities (`createLicenseTerms`, `LicenseTerms`, `DataStatus`)
|
|
21
|
+
- Origin utilities (`createLicenseTerms`, `LicenseTerms`, `LicenseType`, `DataStatus`, `DisputeStatus`, `Dispute`, `AppInfo`, `TokenInfo`)
|
|
22
22
|
- `"@campnetwork/origin/react"` - Exposes the CampProvider and CampContext, as well as React components and hooks for authentication and fetching user data via Origin
|
|
23
23
|
|
|
24
24
|
## Features
|
|
@@ -29,6 +29,11 @@ The Origin SDK currently exposes the following modules:
|
|
|
29
29
|
- **React Components** - Pre-built UI components and hooks
|
|
30
30
|
- **TypeScript Support** - Full type definitions included
|
|
31
31
|
- **Flexible Storage** - Custom storage adapters for session persistence
|
|
32
|
+
- **Multiple License Types** - Duration-based, single payment, and X402 micropayment licenses
|
|
33
|
+
- **Dispute Resolution** - Raise and resolve IP disputes with CAMP token voting
|
|
34
|
+
- **NFT Fractionalization** - Fractionalize IP NFTs into tradable ERC20 tokens
|
|
35
|
+
- **App Revenue Sharing** - Built-in app fee support via AppRegistry
|
|
36
|
+
- **Bulk Operations** - Purchase multiple IP NFTs in a single transaction
|
|
32
37
|
|
|
33
38
|
# Installation
|
|
34
39
|
|
|
@@ -451,6 +456,9 @@ import {
|
|
|
451
456
|
// Auth class
|
|
452
457
|
Auth,
|
|
453
458
|
|
|
459
|
+
// Origin class
|
|
460
|
+
Origin,
|
|
461
|
+
|
|
454
462
|
// Signer adapters
|
|
455
463
|
ViemSignerAdapter,
|
|
456
464
|
EthersSignerAdapter,
|
|
@@ -467,6 +475,27 @@ import {
|
|
|
467
475
|
// Chain configs
|
|
468
476
|
campMainnet,
|
|
469
477
|
campTestnet,
|
|
478
|
+
|
|
479
|
+
// License utilities
|
|
480
|
+
createLicenseTerms,
|
|
481
|
+
LicenseTerms,
|
|
482
|
+
LicenseType,
|
|
483
|
+
|
|
484
|
+
// Status enums
|
|
485
|
+
DataStatus,
|
|
486
|
+
DisputeStatus,
|
|
487
|
+
|
|
488
|
+
// Types
|
|
489
|
+
Dispute,
|
|
490
|
+
AppInfo,
|
|
491
|
+
TokenInfo,
|
|
492
|
+
BuyParams,
|
|
493
|
+
TolerantResult,
|
|
494
|
+
BulkCostPreview,
|
|
495
|
+
VoteEligibility,
|
|
496
|
+
DisputeProgress,
|
|
497
|
+
FractionOwnership,
|
|
498
|
+
FractionalizeEligibility,
|
|
470
499
|
} from "@campnetwork/origin";
|
|
471
500
|
```
|
|
472
501
|
|
|
@@ -922,6 +951,18 @@ The `Origin` class provides blockchain and API methods for interacting with Orig
|
|
|
922
951
|
|
|
923
952
|
### Types
|
|
924
953
|
|
|
954
|
+
#### `LicenseType`
|
|
955
|
+
|
|
956
|
+
Enum representing the type of license for an IP NFT:
|
|
957
|
+
|
|
958
|
+
```typescript
|
|
959
|
+
enum LicenseType {
|
|
960
|
+
DURATION_BASED = 0, // License expires after a set duration (subscription model)
|
|
961
|
+
SINGLE_PAYMENT = 1, // One-time payment for perpetual access
|
|
962
|
+
X402 = 2, // HTTP 402-based micropayment license
|
|
963
|
+
}
|
|
964
|
+
```
|
|
965
|
+
|
|
925
966
|
#### `LicenseTerms`
|
|
926
967
|
|
|
927
968
|
The license terms object used in minting and updating methods:
|
|
@@ -929,48 +970,136 @@ The license terms object used in minting and updating methods:
|
|
|
929
970
|
```typescript
|
|
930
971
|
type LicenseTerms = {
|
|
931
972
|
price: bigint; // Price in wei
|
|
932
|
-
duration: number; // Duration in seconds
|
|
973
|
+
duration: number; // Duration in seconds (0 for SINGLE_PAYMENT and X402)
|
|
933
974
|
royaltyBps: number; // Royalty in basis points (1-10000)
|
|
934
975
|
paymentToken: Address; // Payment token address (address(0) for native currency)
|
|
976
|
+
licenseType: LicenseType; // Type of license
|
|
935
977
|
};
|
|
936
978
|
```
|
|
937
979
|
|
|
980
|
+
#### `DataStatus`
|
|
981
|
+
|
|
982
|
+
Enum representing the status of data in the system:
|
|
983
|
+
|
|
984
|
+
```typescript
|
|
985
|
+
enum DataStatus {
|
|
986
|
+
ACTIVE = 0, // Data is currently active and available
|
|
987
|
+
DELETED = 1, // Data has been deleted
|
|
988
|
+
DISPUTED = 2, // Data has been disputed and marked as potentially infringing
|
|
989
|
+
}
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
#### `DisputeStatus`
|
|
993
|
+
|
|
994
|
+
Enum representing the status of a dispute:
|
|
995
|
+
|
|
996
|
+
```typescript
|
|
997
|
+
enum DisputeStatus {
|
|
998
|
+
Uninitialized = 0, // Dispute does not exist
|
|
999
|
+
Raised = 1, // Dispute has been raised
|
|
1000
|
+
Asserted = 2, // IP owner has responded
|
|
1001
|
+
Resolved = 3, // Dispute has been resolved
|
|
1002
|
+
Cancelled = 4, // Dispute was cancelled
|
|
1003
|
+
}
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
#### `Dispute`
|
|
1007
|
+
|
|
1008
|
+
Interface representing a dispute against an IP NFT:
|
|
1009
|
+
|
|
1010
|
+
```typescript
|
|
1011
|
+
interface Dispute {
|
|
1012
|
+
initiator: Address;
|
|
1013
|
+
targetId: bigint;
|
|
1014
|
+
disputeTag: Hex;
|
|
1015
|
+
disputeEvidenceHash: Hex;
|
|
1016
|
+
counterEvidenceHash: Hex;
|
|
1017
|
+
disputeTimestamp: bigint;
|
|
1018
|
+
assertionTimestamp: bigint;
|
|
1019
|
+
yesVotes: bigint;
|
|
1020
|
+
noVotes: bigint;
|
|
1021
|
+
status: DisputeStatus;
|
|
1022
|
+
bondAmount: bigint;
|
|
1023
|
+
protocolFeeAmount: bigint;
|
|
1024
|
+
}
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
#### `AppInfo`
|
|
1028
|
+
|
|
1029
|
+
Interface representing app information from the AppRegistry:
|
|
1030
|
+
|
|
1031
|
+
```typescript
|
|
1032
|
+
interface AppInfo {
|
|
1033
|
+
treasury: Address;
|
|
1034
|
+
revenueShareBps: number;
|
|
1035
|
+
isActive: boolean;
|
|
1036
|
+
}
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
#### `TokenInfo`
|
|
1040
|
+
|
|
1041
|
+
Comprehensive token information returned by `getTokenInfoSmart`:
|
|
1042
|
+
|
|
1043
|
+
```typescript
|
|
1044
|
+
interface TokenInfo {
|
|
1045
|
+
tokenId: bigint;
|
|
1046
|
+
owner: Address;
|
|
1047
|
+
uri: string;
|
|
1048
|
+
status: DataStatus;
|
|
1049
|
+
terms: LicenseTerms;
|
|
1050
|
+
hasAccess: boolean;
|
|
1051
|
+
accessExpiry: bigint | null;
|
|
1052
|
+
appId: string;
|
|
1053
|
+
}
|
|
1054
|
+
```
|
|
1055
|
+
|
|
938
1056
|
### Minting Constraints
|
|
939
1057
|
|
|
940
1058
|
When minting or updating an IpNFT, the following constraints apply to the `LicenseTerms`:
|
|
941
1059
|
|
|
942
1060
|
- The price must be at least `1000000000000000` wei (0.001 $CAMP).
|
|
943
1061
|
- The royaltyBps must be between `1` and `10000` (0.01% to 100%).
|
|
944
|
-
-
|
|
1062
|
+
- For `DURATION_BASED` licenses, the duration must be between `86400` seconds and `2628000` seconds (1 day to 30 days).
|
|
1063
|
+
- For `SINGLE_PAYMENT` and `X402` licenses, duration must be `0`.
|
|
945
1064
|
|
|
946
|
-
### `createLicenseTerms(price, duration, royaltyBps, paymentToken)`
|
|
1065
|
+
### `createLicenseTerms(price, duration, royaltyBps, paymentToken, licenseType?)`
|
|
947
1066
|
|
|
948
1067
|
A utility function to create properly validated license terms for minting and updating IpNFTs.
|
|
949
1068
|
|
|
950
1069
|
- `price`: Price in wei (bigint)
|
|
951
|
-
- `duration`: Duration in seconds (number)
|
|
1070
|
+
- `duration`: Duration in seconds (number) - use 0 for SINGLE_PAYMENT and X402
|
|
952
1071
|
- `royaltyBps`: Royalty in basis points (number)
|
|
953
1072
|
- `paymentToken`: Payment token address (Address) - use `zeroAddress` from viem for native currency
|
|
1073
|
+
- `licenseType`: Type of license (LicenseType) - defaults to `DURATION_BASED`
|
|
954
1074
|
- **Returns:** A validated `LicenseTerms` object
|
|
955
1075
|
- **Throws:** Error if any parameter violates the constraints
|
|
956
1076
|
|
|
957
1077
|
**Example:**
|
|
958
1078
|
|
|
959
1079
|
```typescript
|
|
960
|
-
import { createLicenseTerms } from "@campnetwork/origin";
|
|
1080
|
+
import { createLicenseTerms, LicenseType } from "@campnetwork/origin";
|
|
961
1081
|
import { zeroAddress } from "viem";
|
|
962
1082
|
|
|
963
|
-
// Create license
|
|
964
|
-
const
|
|
1083
|
+
// Create duration-based license (subscription)
|
|
1084
|
+
const subscriptionLicense = createLicenseTerms(
|
|
965
1085
|
BigInt("1000000000000000"), // 0.001 CAMP in wei
|
|
966
1086
|
86400, // 1 day in seconds
|
|
967
1087
|
1000, // 10% royalty (1000 basis points)
|
|
968
1088
|
zeroAddress // Native currency (CAMP)
|
|
969
1089
|
);
|
|
970
1090
|
|
|
1091
|
+
// Create single payment license (perpetual access)
|
|
1092
|
+
const perpetualLicense = createLicenseTerms(
|
|
1093
|
+
BigInt("10000000000000000"), // 0.01 CAMP
|
|
1094
|
+
0, // Duration must be 0 for single payment
|
|
1095
|
+
500, // 5% royalty
|
|
1096
|
+
zeroAddress,
|
|
1097
|
+
LicenseType.SINGLE_PAYMENT
|
|
1098
|
+
);
|
|
1099
|
+
|
|
971
1100
|
// Use with minting functions
|
|
972
|
-
await auth.origin.mintFile(file, metadata,
|
|
973
|
-
await auth.origin.mintSocial("twitter", metadata,
|
|
1101
|
+
await auth.origin.mintFile(file, metadata, subscriptionLicense);
|
|
1102
|
+
await auth.origin.mintSocial("twitter", metadata, perpetualLicense);
|
|
974
1103
|
```
|
|
975
1104
|
|
|
976
1105
|
### File Upload & Minting
|
|
@@ -1007,37 +1136,277 @@ Most methods mirror smart contract functions and require appropriate permissions
|
|
|
1007
1136
|
|
|
1008
1137
|
#### Core IpNFT Methods
|
|
1009
1138
|
|
|
1010
|
-
- `mintWithSignature(
|
|
1011
|
-
- `registerIpNFT(source, deadline, license, metadata, fileKey?, parents?)`
|
|
1012
|
-
- `updateTerms(tokenId, license)`
|
|
1013
|
-
- `finalizeDelete(tokenId)`
|
|
1014
|
-
- `getOrCreateRoyaltyVault(tokenId)`
|
|
1015
|
-
- `getTerms(tokenId)`
|
|
1016
|
-
- `ownerOf(tokenId)`
|
|
1017
|
-
- `balanceOf(owner)`
|
|
1018
|
-
- `tokenURI(tokenId)`
|
|
1019
|
-
- `dataStatus(tokenId)`
|
|
1020
|
-
- `isApprovedForAll(owner, operator)`
|
|
1021
|
-
- `transferFrom(from, to, tokenId)`
|
|
1022
|
-
- `safeTransferFrom(from, to, tokenId)`
|
|
1023
|
-
- `approve(to, tokenId)`
|
|
1024
|
-
- `setApprovalForAll(operator, approved)`
|
|
1139
|
+
- `mintWithSignature(to, tokenId, parents, isIp, hash, uri, license, deadline, signature, appId?)` — Mint with a backend signature. `appId` defaults to SDK's clientId.
|
|
1140
|
+
- `registerIpNFT(source, deadline, license, metadata, fileKey?, parents?)` — Register IP with backend
|
|
1141
|
+
- `updateTerms(tokenId, license)` — Update license terms
|
|
1142
|
+
- `finalizeDelete(tokenId)` — Finalize deletion of an IP NFT
|
|
1143
|
+
- `getOrCreateRoyaltyVault(tokenId)` — Get or create Token Bound Account for royalties
|
|
1144
|
+
- `getTerms(tokenId)` — Get license terms for a token
|
|
1145
|
+
- `ownerOf(tokenId)` — Get owner address
|
|
1146
|
+
- `balanceOf(owner)` — Get token count for an owner
|
|
1147
|
+
- `tokenURI(tokenId)` — Get metadata URI
|
|
1148
|
+
- `dataStatus(tokenId)` — Get data status (ACTIVE, DELETED, or DISPUTED)
|
|
1149
|
+
- `isApprovedForAll(owner, operator)` — Check operator approval
|
|
1150
|
+
- `transferFrom(from, to, tokenId)` — Transfer token
|
|
1151
|
+
- `safeTransferFrom(from, to, tokenId)` — Safe transfer token
|
|
1152
|
+
- `approve(to, tokenId)` — Approve address for token
|
|
1153
|
+
- `setApprovalForAll(operator, approved)` — Set operator approval
|
|
1025
1154
|
|
|
1026
1155
|
#### Marketplace Methods
|
|
1027
1156
|
|
|
1028
|
-
- `buyAccess(buyer, tokenId, expectedPrice, expectedDuration, expectedPaymentToken, value?)`
|
|
1029
|
-
- `hasAccess(
|
|
1030
|
-
- `subscriptionExpiry(tokenId,
|
|
1157
|
+
- `buyAccess(buyer, tokenId, expectedPrice, expectedDuration, expectedPaymentToken, expectedProtocolFeeBps?, expectedAppFeeBps?, value?)` — Purchase access to an IP NFT
|
|
1158
|
+
- `hasAccess(address, tokenId)` — Check if address has access
|
|
1159
|
+
- `subscriptionExpiry(tokenId, address)` — Get subscription expiry timestamp
|
|
1160
|
+
|
|
1161
|
+
#### Smart Helper Methods (Recommended)
|
|
1031
1162
|
|
|
1032
|
-
|
|
1163
|
+
These methods handle complexity automatically and are recommended for most use cases:
|
|
1164
|
+
|
|
1165
|
+
- `getTokenInfoSmart(tokenId, owner?)` — Get comprehensive token info in a single call (owner, terms, status, access info, etc.)
|
|
1166
|
+
- `buyAccessSmart(tokenId)` — Buys access with automatic fee fetching. Returns `null` if user already has access.
|
|
1167
|
+
- `settlePaymentIntent(x402Response, signer?)` — Settle an X402 payment intent response
|
|
1168
|
+
|
|
1169
|
+
**Example:**
|
|
1170
|
+
|
|
1171
|
+
```typescript
|
|
1172
|
+
// Get all token info at once
|
|
1173
|
+
const info = await auth.origin.getTokenInfoSmart(1n);
|
|
1174
|
+
console.log(`Owner: ${info.owner}`);
|
|
1175
|
+
console.log(`Price: ${info.terms.price}`);
|
|
1176
|
+
console.log(`Has access: ${info.hasAccess}`);
|
|
1177
|
+
console.log(`License type: ${info.terms.licenseType}`);
|
|
1178
|
+
|
|
1179
|
+
// Smart purchase - checks access first, fetches fees automatically
|
|
1180
|
+
const result = await auth.origin.buyAccessSmart(1n);
|
|
1181
|
+
if (result === null) {
|
|
1182
|
+
console.log("Already have access!");
|
|
1183
|
+
} else {
|
|
1184
|
+
console.log("Purchased:", result.txHash);
|
|
1185
|
+
}
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
#### Bulk Purchase Methods
|
|
1189
|
+
|
|
1190
|
+
For purchasing multiple IP NFTs in a single transaction:
|
|
1191
|
+
|
|
1192
|
+
- `bulkBuyAccess(buyer, purchases, value?)` — Atomic bulk purchase (all succeed or all fail)
|
|
1193
|
+
- `bulkBuyAccessTolerant(buyer, purchases, value?)` — Tolerant bulk purchase (partial success allowed)
|
|
1194
|
+
- `bulkBuyAccessSmart(tokenIds, options?)` — Smart bulk purchase with automatic parameter building
|
|
1195
|
+
- `previewBulkCost(tokenIds)` — Preview total cost for multiple tokens
|
|
1196
|
+
- `buildPurchaseParams(tokenIds)` — Build purchase parameters from token IDs
|
|
1197
|
+
- `checkActiveStatus(tokenIds)` — Check active status of multiple tokens
|
|
1198
|
+
|
|
1199
|
+
**Example:**
|
|
1200
|
+
|
|
1201
|
+
```typescript
|
|
1202
|
+
// Smart bulk purchase - handles everything automatically
|
|
1203
|
+
const result = await auth.origin.bulkBuyAccessSmart([1n, 2n, 3n], {
|
|
1204
|
+
tolerant: true, // Continue even if some fail
|
|
1205
|
+
});
|
|
1206
|
+
|
|
1207
|
+
// Preview costs before purchasing
|
|
1208
|
+
const preview = await auth.origin.previewBulkCost([1n, 2n, 3n]);
|
|
1209
|
+
console.log(`Total cost: ${preview.totalNativeCost} wei`);
|
|
1210
|
+
```
|
|
1033
1211
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1212
|
+
#### Dispute Module Methods
|
|
1213
|
+
|
|
1214
|
+
Methods for the IP dispute resolution system:
|
|
1215
|
+
|
|
1216
|
+
- `raiseDispute(targetIpId, evidenceHash, disputeTag)` — Raise a dispute against an IP NFT
|
|
1217
|
+
- `disputeAssertion(disputeId, counterEvidenceHash)` — IP owner responds to dispute
|
|
1218
|
+
- `voteOnDispute(disputeId, support)` — CAMP stakers vote on dispute
|
|
1219
|
+
- `resolveDispute(disputeId)` — Finalize dispute after voting period
|
|
1220
|
+
- `cancelDispute(disputeId)` — Cancel a dispute (initiator only)
|
|
1221
|
+
- `tagChildIp(childIpId, infringerDisputeId)` — Tag derivative IPs of disputed content
|
|
1222
|
+
- `getDispute(disputeId)` — Get dispute details
|
|
1223
|
+
- `canVoteOnDispute(disputeId, voter?)` — Check if user can vote and why (recommended before voting)
|
|
1224
|
+
- `getDisputeProgress(disputeId)` — Get voting stats, quorum progress, timeline, and projected outcome
|
|
1225
|
+
|
|
1226
|
+
**VoteEligibility Interface:**
|
|
1227
|
+
|
|
1228
|
+
```typescript
|
|
1229
|
+
interface VoteEligibility {
|
|
1230
|
+
canVote: boolean; // Whether the user can vote
|
|
1231
|
+
reason?: string; // Why they can't vote (if canVote is false)
|
|
1232
|
+
votingWeight: bigint; // User's staked CAMP balance
|
|
1233
|
+
stakingThreshold: bigint; // Minimum required stake
|
|
1234
|
+
hasAlreadyVoted: boolean; // Whether user already voted
|
|
1235
|
+
userStakeTimestamp: bigint; // When user staked (0 if never)
|
|
1236
|
+
disputeTimestamp: bigint; // When dispute was raised
|
|
1237
|
+
disputeStatus: DisputeStatus; // Current status
|
|
1238
|
+
isVotingPeriodActive: boolean; // Whether voting is open
|
|
1239
|
+
}
|
|
1240
|
+
```
|
|
1241
|
+
|
|
1242
|
+
**DisputeProgress Interface:**
|
|
1243
|
+
|
|
1244
|
+
```typescript
|
|
1245
|
+
interface DisputeProgress {
|
|
1246
|
+
disputeId: bigint;
|
|
1247
|
+
status: DisputeStatus;
|
|
1248
|
+
yesVotes: bigint; // Total YES votes (weighted)
|
|
1249
|
+
noVotes: bigint; // Total NO votes (weighted)
|
|
1250
|
+
totalVotes: bigint;
|
|
1251
|
+
yesPercentage: number; // 0-100
|
|
1252
|
+
noPercentage: number; // 0-100
|
|
1253
|
+
quorum: bigint; // Required for valid resolution
|
|
1254
|
+
quorumPercentage: number; // Progress toward quorum
|
|
1255
|
+
quorumMet: boolean;
|
|
1256
|
+
projectedOutcome: "dispute_succeeds" | "dispute_fails" | "no_quorum";
|
|
1257
|
+
timeline: {
|
|
1258
|
+
raisedAt: Date;
|
|
1259
|
+
cooldownEndsAt: Date; // Owner can assert until this time
|
|
1260
|
+
votingEndsAt: Date;
|
|
1261
|
+
canResolveNow: boolean;
|
|
1262
|
+
timeUntilResolution: number; // Seconds remaining
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
```
|
|
1266
|
+
|
|
1267
|
+
**Example:**
|
|
1268
|
+
|
|
1269
|
+
```typescript
|
|
1270
|
+
import { keccak256, toBytes } from "viem";
|
|
1271
|
+
|
|
1272
|
+
// Raise a dispute
|
|
1273
|
+
const evidenceHash = keccak256(toBytes("ipfs://QmEvidence..."));
|
|
1274
|
+
const disputeTag = keccak256(toBytes("copyright_infringement"));
|
|
1275
|
+
|
|
1276
|
+
const result = await auth.origin.raiseDispute(
|
|
1277
|
+
1n, // Token ID to dispute
|
|
1278
|
+
evidenceHash,
|
|
1279
|
+
disputeTag
|
|
1280
|
+
);
|
|
1281
|
+
|
|
1282
|
+
// Check if you can vote before voting
|
|
1283
|
+
const eligibility = await auth.origin.canVoteOnDispute(disputeId);
|
|
1284
|
+
|
|
1285
|
+
if (eligibility.canVote) {
|
|
1286
|
+
console.log(`Voting with weight: ${eligibility.votingWeight}`);
|
|
1287
|
+
await auth.origin.voteOnDispute(disputeId, true); // Vote YES
|
|
1288
|
+
} else {
|
|
1289
|
+
console.log(`Cannot vote: ${eligibility.reason}`);
|
|
1290
|
+
// Possible reasons:
|
|
1291
|
+
// - "Dispute is not in a voteable status"
|
|
1292
|
+
// - "Voting period has ended"
|
|
1293
|
+
// - "You have already voted on this dispute"
|
|
1294
|
+
// - "You have never staked CAMP tokens"
|
|
1295
|
+
// - "You staked after this dispute was raised"
|
|
1296
|
+
// - "Insufficient stake: you have X but need at least Y"
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// Get detailed dispute progress
|
|
1300
|
+
const progress = await auth.origin.getDisputeProgress(disputeId);
|
|
1301
|
+
console.log(`Yes: ${progress.yesPercentage}% | No: ${progress.noPercentage}%`);
|
|
1302
|
+
console.log(`Quorum: ${progress.quorumPercentage}% (${progress.quorumMet ? "met" : "not met"})`);
|
|
1303
|
+
console.log(`Projected outcome: ${progress.projectedOutcome}`);
|
|
1304
|
+
|
|
1305
|
+
if (progress.timeline.canResolveNow) {
|
|
1306
|
+
await auth.origin.resolveDispute(disputeId);
|
|
1307
|
+
} else {
|
|
1308
|
+
console.log(`Can resolve in ${progress.timeline.timeUntilResolution} seconds`);
|
|
1309
|
+
}
|
|
1310
|
+
```
|
|
1311
|
+
|
|
1312
|
+
#### Fractionalizer Module Methods
|
|
1313
|
+
|
|
1314
|
+
Methods for fractionalizing IP NFTs into ERC20 tokens:
|
|
1315
|
+
|
|
1316
|
+
- `fractionalize(tokenId)` — Fractionalize an NFT into ERC20 tokens
|
|
1317
|
+
- `fractionalizeWithApproval(tokenId)` — Fractionalize with automatic approval (recommended)
|
|
1318
|
+
- `redeem(tokenId)` — Redeem fractional tokens for the underlying NFT
|
|
1319
|
+
- `redeemIfComplete(tokenId)` — Redeem only if holding 100% of tokens (recommended)
|
|
1320
|
+
- `getTokenForNFT(tokenId)` — Get the ERC20 token address for a fractionalized NFT
|
|
1321
|
+
- `getFractionOwnership(tokenId, owner?)` — Get user's ownership percentage of fractional tokens
|
|
1322
|
+
- `canFractionalize(tokenId, owner?)` — Check if user can fractionalize an NFT
|
|
1323
|
+
|
|
1324
|
+
**FractionOwnership Interface:**
|
|
1325
|
+
|
|
1326
|
+
```typescript
|
|
1327
|
+
interface FractionOwnership {
|
|
1328
|
+
tokenId: bigint;
|
|
1329
|
+
erc20Address: Address; // Zero if not fractionalized
|
|
1330
|
+
isFractionalized: boolean;
|
|
1331
|
+
balance: bigint; // User's fractional token balance
|
|
1332
|
+
totalSupply: bigint; // Total supply of fractional tokens
|
|
1333
|
+
ownershipPercentage: number; // 0-100
|
|
1334
|
+
canRedeem: boolean; // True if owns 100%
|
|
1335
|
+
decimals: number;
|
|
1336
|
+
}
|
|
1337
|
+
```
|
|
1338
|
+
|
|
1339
|
+
**FractionalizeEligibility Interface:**
|
|
1340
|
+
|
|
1341
|
+
```typescript
|
|
1342
|
+
interface FractionalizeEligibility {
|
|
1343
|
+
canFractionalize: boolean;
|
|
1344
|
+
reason?: string; // Why not (if false)
|
|
1345
|
+
isOwner: boolean;
|
|
1346
|
+
currentOwner: Address;
|
|
1347
|
+
isAlreadyFractionalized: boolean;
|
|
1348
|
+
existingErc20Address?: Address;
|
|
1349
|
+
dataStatus: DataStatus;
|
|
1350
|
+
isApproved: boolean; // Fractionalizer approved to transfer
|
|
1351
|
+
needsApproval: boolean;
|
|
1352
|
+
}
|
|
1353
|
+
```
|
|
1354
|
+
|
|
1355
|
+
**Example:**
|
|
1356
|
+
|
|
1357
|
+
```typescript
|
|
1358
|
+
// Check if you can fractionalize
|
|
1359
|
+
const eligibility = await auth.origin.canFractionalize(1n);
|
|
1360
|
+
|
|
1361
|
+
if (eligibility.canFractionalize) {
|
|
1362
|
+
// Fractionalize with automatic approval
|
|
1363
|
+
await auth.origin.fractionalizeWithApproval(1n);
|
|
1364
|
+
} else {
|
|
1365
|
+
console.log(`Cannot fractionalize: ${eligibility.reason}`);
|
|
1366
|
+
// Possible reasons:
|
|
1367
|
+
// - "You don't own this NFT"
|
|
1368
|
+
// - "This NFT is already fractionalized"
|
|
1369
|
+
// - "This NFT has been deleted"
|
|
1370
|
+
// - "This NFT is disputed"
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
// Check your ownership of fractional tokens
|
|
1374
|
+
const ownership = await auth.origin.getFractionOwnership(1n);
|
|
1375
|
+
|
|
1376
|
+
if (!ownership.isFractionalized) {
|
|
1377
|
+
console.log("This NFT has not been fractionalized");
|
|
1378
|
+
} else {
|
|
1379
|
+
console.log(`You own ${ownership.ownershipPercentage}% of this NFT`);
|
|
1380
|
+
console.log(`Balance: ${ownership.balance} / ${ownership.totalSupply}`);
|
|
1381
|
+
|
|
1382
|
+
if (ownership.canRedeem) {
|
|
1383
|
+
console.log("You can redeem the original NFT!");
|
|
1384
|
+
await auth.origin.redeemIfComplete(1n);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
```
|
|
1388
|
+
|
|
1389
|
+
#### AppRegistry Module Methods
|
|
1390
|
+
|
|
1391
|
+
Methods for querying app information:
|
|
1392
|
+
|
|
1393
|
+
- `getAppInfo(appId)` — Get app information from the registry
|
|
1394
|
+
|
|
1395
|
+
**Example:**
|
|
1396
|
+
|
|
1397
|
+
```typescript
|
|
1398
|
+
const appInfo = await auth.origin.getAppInfo("my-app-id");
|
|
1399
|
+
console.log(`Treasury: ${appInfo.treasury}`);
|
|
1400
|
+
console.log(`Revenue Share: ${appInfo.revenueShareBps / 100}%`);
|
|
1401
|
+
console.log(`Active: ${appInfo.isActive}`);
|
|
1402
|
+
```
|
|
1036
1403
|
|
|
1037
|
-
####
|
|
1404
|
+
#### Royalty & Data Methods
|
|
1038
1405
|
|
|
1039
|
-
- `
|
|
1040
|
-
- `
|
|
1406
|
+
- `getTokenBoundAccount(tokenId)` — Get the Token Bound Account address for a token
|
|
1407
|
+
- `getRoyalties(tokenId, token?)` — Get royalty balance for a token
|
|
1408
|
+
- `claimRoyalties(tokenId, recipient?, token?)` — Claim royalties from a token's TBA
|
|
1409
|
+
- `getData(tokenId)` — Fetch the underlying IP data (requires access)
|
|
1041
1410
|
|
|
1042
1411
|
### Utility Methods
|
|
1043
1412
|
|