@campnetwork/origin 1.3.0-alpha.6 → 1.3.0-alpha.7

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.
@@ -320,9 +320,13 @@ interface RaiseDisputeSmartResult {
320
320
  }
321
321
  /**
322
322
  * Raises a dispute with automatic evidence upload to IPFS.
323
- * Uploads evidence JSON to IPFS, hashes the CID to bytes32 for on-chain storage,
323
+ * Uploads evidence JSON to IPFS, encodes the CID to bytes32 for on-chain storage,
324
324
  * and calls raiseDispute.
325
325
  *
326
+ * The CID is encoded by stripping the 0x1220 multihash prefix from CIDv0,
327
+ * leaving only the 32-byte SHA-256 digest. This encoding is reversible,
328
+ * allowing the original CID to be reconstructed from the on-chain data.
329
+ *
326
330
  * @param targetIpId The token ID of the IP NFT to dispute.
327
331
  * @param evidence The evidence JSON object to upload to IPFS.
328
332
  * @param disputeTag A tag identifying the type of dispute.
@@ -336,13 +340,11 @@ interface RaiseDisputeSmartResult {
336
340
  * "0x696e6672696e67656d656e74..." // dispute tag
337
341
  * );
338
342
  *
339
- * // Store the CID for evidence retrieval
343
+ * // The CID can be recovered from evidenceHash using decodeCidFromBytes32
340
344
  * console.log("Evidence CID:", result.evidenceCid);
341
345
  *
342
- * // Fetch evidence later via IPFS gateway
346
+ * // Fetch evidence via IPFS gateway
343
347
  * // https://ipfs.io/ipfs/{result.evidenceCid}
344
- *
345
- * // Verify evidence hash matches on-chain: keccak256(toHex(evidenceCid)) === evidenceHash
346
348
  * ```
347
349
  */
348
350
  declare function raiseDisputeSmart(this: Origin, targetIpId: bigint, evidence: Record<string, any>, disputeTag: Hex): Promise<RaiseDisputeSmartResult>;
@@ -362,6 +364,42 @@ declare function raiseDisputeSmart(this: Origin, targetIpId: bigint, evidence: R
362
364
  */
363
365
  declare function disputeAssertion(this: Origin, disputeId: bigint, counterEvidenceHash: Hex): Promise<any>;
364
366
 
367
+ interface DisputeAssertionSmartResult {
368
+ transactionResult: any;
369
+ counterEvidenceCid: string;
370
+ counterEvidenceHash: Hex;
371
+ }
372
+ /**
373
+ * Asserts a dispute with automatic counter-evidence upload to IPFS.
374
+ * Uploads counter-evidence JSON to IPFS, encodes the CID to bytes32 for on-chain storage,
375
+ * and calls disputeAssertion.
376
+ *
377
+ * The CID is encoded by stripping the 0x1220 multihash prefix from CIDv0,
378
+ * leaving only the 32-byte SHA-256 digest. This encoding is reversible,
379
+ * allowing the original CID to be reconstructed from the on-chain data.
380
+ *
381
+ * Must be called by the owner of the disputed IP within the cooldown period.
382
+ *
383
+ * @param disputeId The ID of the dispute to assert.
384
+ * @param counterEvidence The counter-evidence JSON object to upload to IPFS.
385
+ * @returns A promise that resolves with the transaction result, IPFS CID, and counter-evidence hash.
386
+ *
387
+ * @example
388
+ * ```typescript
389
+ * const result = await origin.disputeAssertionSmart(
390
+ * 1n,
391
+ * { description: "This is my original work", proofUrl: "https://..." }
392
+ * );
393
+ *
394
+ * // The CID can be recovered from counterEvidenceHash using decodeCidFromBytes32
395
+ * console.log("Counter-evidence CID:", result.counterEvidenceCid);
396
+ *
397
+ * // Fetch counter-evidence via IPFS gateway
398
+ * // https://ipfs.io/ipfs/{result.counterEvidenceCid}
399
+ * ```
400
+ */
401
+ declare function disputeAssertionSmart(this: Origin, disputeId: bigint, counterEvidence: Record<string, any>): Promise<DisputeAssertionSmartResult>;
402
+
365
403
  /**
366
404
  * Votes on a dispute as a CAMP token staker.
367
405
  * Only users who staked before the dispute was raised can vote.
@@ -927,6 +965,7 @@ declare class Origin {
927
965
  raiseDispute: typeof raiseDispute;
928
966
  raiseDisputeSmart: typeof raiseDisputeSmart;
929
967
  disputeAssertion: typeof disputeAssertion;
968
+ disputeAssertionSmart: typeof disputeAssertionSmart;
930
969
  voteOnDispute: typeof voteOnDispute;
931
970
  resolveDispute: typeof resolveDispute;
932
971
  cancelDispute: typeof cancelDispute;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import React, { createContext, useState, useContext, useEffect, useLayoutEffect, useRef, useSyncExternalStore } from 'react';
3
- import { custom, createWalletClient, createPublicClient, http, encodeFunctionData, checksumAddress, zeroAddress, keccak256, toBytes, toHex, erc20Abi, getAbiItem, formatEther, formatUnits, parseEther } from 'viem';
3
+ import { custom, createWalletClient, createPublicClient, http, encodeFunctionData, checksumAddress, zeroAddress, keccak256, toBytes, erc20Abi, getAbiItem, formatEther, formatUnits, parseEther } from 'viem';
4
4
  import { toAccount } from 'viem/accounts';
5
5
  import { createSiweMessage } from 'viem/siwe';
6
6
  import axios from 'axios';
@@ -6845,11 +6845,155 @@ function raiseDispute(targetIpId, evidenceHash, disputeTag) {
6845
6845
  });
6846
6846
  }
6847
6847
 
6848
+ // base-x encoding / decoding
6849
+ // Copyright (c) 2018 base-x contributors
6850
+ // Copyright (c) 2014-2018 The Bitcoin Core developers (base58.cpp)
6851
+ // Distributed under the MIT software license, see the accompanying
6852
+ // file LICENSE or http://www.opensource.org/licenses/mit-license.php.
6853
+ function base (ALPHABET) {
6854
+ if (ALPHABET.length >= 255) { throw new TypeError('Alphabet too long') }
6855
+ const BASE_MAP = new Uint8Array(256);
6856
+ for (let j = 0; j < BASE_MAP.length; j++) {
6857
+ BASE_MAP[j] = 255;
6858
+ }
6859
+ for (let i = 0; i < ALPHABET.length; i++) {
6860
+ const x = ALPHABET.charAt(i);
6861
+ const xc = x.charCodeAt(0);
6862
+ if (BASE_MAP[xc] !== 255) { throw new TypeError(x + ' is ambiguous') }
6863
+ BASE_MAP[xc] = i;
6864
+ }
6865
+ const BASE = ALPHABET.length;
6866
+ const LEADER = ALPHABET.charAt(0);
6867
+ const FACTOR = Math.log(BASE) / Math.log(256); // log(BASE) / log(256), rounded up
6868
+ const iFACTOR = Math.log(256) / Math.log(BASE); // log(256) / log(BASE), rounded up
6869
+ function encode (source) {
6870
+ // eslint-disable-next-line no-empty
6871
+ if (source instanceof Uint8Array) ; else if (ArrayBuffer.isView(source)) {
6872
+ source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
6873
+ } else if (Array.isArray(source)) {
6874
+ source = Uint8Array.from(source);
6875
+ }
6876
+ if (!(source instanceof Uint8Array)) { throw new TypeError('Expected Uint8Array') }
6877
+ if (source.length === 0) { return '' }
6878
+ // Skip & count leading zeroes.
6879
+ let zeroes = 0;
6880
+ let length = 0;
6881
+ let pbegin = 0;
6882
+ const pend = source.length;
6883
+ while (pbegin !== pend && source[pbegin] === 0) {
6884
+ pbegin++;
6885
+ zeroes++;
6886
+ }
6887
+ // Allocate enough space in big-endian base58 representation.
6888
+ const size = ((pend - pbegin) * iFACTOR + 1) >>> 0;
6889
+ const b58 = new Uint8Array(size);
6890
+ // Process the bytes.
6891
+ while (pbegin !== pend) {
6892
+ let carry = source[pbegin];
6893
+ // Apply "b58 = b58 * 256 + ch".
6894
+ let i = 0;
6895
+ for (let it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) {
6896
+ carry += (256 * b58[it1]) >>> 0;
6897
+ b58[it1] = (carry % BASE) >>> 0;
6898
+ carry = (carry / BASE) >>> 0;
6899
+ }
6900
+ if (carry !== 0) { throw new Error('Non-zero carry') }
6901
+ length = i;
6902
+ pbegin++;
6903
+ }
6904
+ // Skip leading zeroes in base58 result.
6905
+ let it2 = size - length;
6906
+ while (it2 !== size && b58[it2] === 0) {
6907
+ it2++;
6908
+ }
6909
+ // Translate the result into a string.
6910
+ let str = LEADER.repeat(zeroes);
6911
+ for (; it2 < size; ++it2) { str += ALPHABET.charAt(b58[it2]); }
6912
+ return str
6913
+ }
6914
+ function decodeUnsafe (source) {
6915
+ if (typeof source !== 'string') { throw new TypeError('Expected String') }
6916
+ if (source.length === 0) { return new Uint8Array() }
6917
+ let psz = 0;
6918
+ // Skip and count leading '1's.
6919
+ let zeroes = 0;
6920
+ let length = 0;
6921
+ while (source[psz] === LEADER) {
6922
+ zeroes++;
6923
+ psz++;
6924
+ }
6925
+ // Allocate enough space in big-endian base256 representation.
6926
+ const size = (((source.length - psz) * FACTOR) + 1) >>> 0; // log(58) / log(256), rounded up.
6927
+ const b256 = new Uint8Array(size);
6928
+ // Process the characters.
6929
+ while (psz < source.length) {
6930
+ // Find code of next character
6931
+ const charCode = source.charCodeAt(psz);
6932
+ // Base map can not be indexed using char code
6933
+ if (charCode > 255) { return }
6934
+ // Decode character
6935
+ let carry = BASE_MAP[charCode];
6936
+ // Invalid character
6937
+ if (carry === 255) { return }
6938
+ let i = 0;
6939
+ for (let it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) {
6940
+ carry += (BASE * b256[it3]) >>> 0;
6941
+ b256[it3] = (carry % 256) >>> 0;
6942
+ carry = (carry / 256) >>> 0;
6943
+ }
6944
+ if (carry !== 0) { throw new Error('Non-zero carry') }
6945
+ length = i;
6946
+ psz++;
6947
+ }
6948
+ // Skip leading zeroes in b256.
6949
+ let it4 = size - length;
6950
+ while (it4 !== size && b256[it4] === 0) {
6951
+ it4++;
6952
+ }
6953
+ const vch = new Uint8Array(zeroes + (size - it4));
6954
+ let j = zeroes;
6955
+ while (it4 !== size) {
6956
+ vch[j++] = b256[it4++];
6957
+ }
6958
+ return vch
6959
+ }
6960
+ function decode (string) {
6961
+ const buffer = decodeUnsafe(string);
6962
+ if (buffer) { return buffer }
6963
+ throw new Error('Non-base' + BASE + ' character')
6964
+ }
6965
+ return {
6966
+ encode,
6967
+ decodeUnsafe,
6968
+ decode
6969
+ }
6970
+ }
6971
+
6972
+ var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
6973
+ var bs58 = base(ALPHABET);
6974
+
6975
+ /**
6976
+ * Encode CIDv0 to bytes32 by stripping the 0x1220 multihash prefix.
6977
+ * Only works with CIDv0 (SHA-256 hash, starts with "Qm").
6978
+ */
6979
+ function encodeCidToBytes32(cid) {
6980
+ const decoded = bs58.decode(cid);
6981
+ if (decoded[0] !== 0x12 || decoded[1] !== 0x20 || decoded.length !== 34) {
6982
+ throw new Error("Only CIDv0 with SHA-256 is supported");
6983
+ }
6984
+ // Return only the 32-byte digest (skip 0x1220 prefix)
6985
+ return `0x${Buffer.from(decoded.slice(2)).toString("hex")}`;
6986
+ }
6987
+
6848
6988
  /**
6849
6989
  * Raises a dispute with automatic evidence upload to IPFS.
6850
- * Uploads evidence JSON to IPFS, hashes the CID to bytes32 for on-chain storage,
6990
+ * Uploads evidence JSON to IPFS, encodes the CID to bytes32 for on-chain storage,
6851
6991
  * and calls raiseDispute.
6852
6992
  *
6993
+ * The CID is encoded by stripping the 0x1220 multihash prefix from CIDv0,
6994
+ * leaving only the 32-byte SHA-256 digest. This encoding is reversible,
6995
+ * allowing the original CID to be reconstructed from the on-chain data.
6996
+ *
6853
6997
  * @param targetIpId The token ID of the IP NFT to dispute.
6854
6998
  * @param evidence The evidence JSON object to upload to IPFS.
6855
6999
  * @param disputeTag A tag identifying the type of dispute.
@@ -6863,19 +7007,17 @@ function raiseDispute(targetIpId, evidenceHash, disputeTag) {
6863
7007
  * "0x696e6672696e67656d656e74..." // dispute tag
6864
7008
  * );
6865
7009
  *
6866
- * // Store the CID for evidence retrieval
7010
+ * // The CID can be recovered from evidenceHash using decodeCidFromBytes32
6867
7011
  * console.log("Evidence CID:", result.evidenceCid);
6868
7012
  *
6869
- * // Fetch evidence later via IPFS gateway
7013
+ * // Fetch evidence via IPFS gateway
6870
7014
  * // https://ipfs.io/ipfs/{result.evidenceCid}
6871
- *
6872
- * // Verify evidence hash matches on-chain: keccak256(toHex(evidenceCid)) === evidenceHash
6873
7015
  * ```
6874
7016
  */
6875
7017
  function raiseDisputeSmart(targetIpId, evidence, disputeTag) {
6876
7018
  return __awaiter(this, void 0, void 0, function* () {
6877
7019
  const cid = yield this.uploadJSONToIPFS(evidence);
6878
- const evidenceHash = keccak256(toHex(cid));
7020
+ const evidenceHash = encodeCidToBytes32(cid);
6879
7021
  const transactionResult = yield this.raiseDispute(targetIpId, evidenceHash, disputeTag);
6880
7022
  return {
6881
7023
  transactionResult,
@@ -6904,6 +7046,48 @@ function disputeAssertion(disputeId, counterEvidenceHash) {
6904
7046
  });
6905
7047
  }
6906
7048
 
7049
+ /**
7050
+ * Asserts a dispute with automatic counter-evidence upload to IPFS.
7051
+ * Uploads counter-evidence JSON to IPFS, encodes the CID to bytes32 for on-chain storage,
7052
+ * and calls disputeAssertion.
7053
+ *
7054
+ * The CID is encoded by stripping the 0x1220 multihash prefix from CIDv0,
7055
+ * leaving only the 32-byte SHA-256 digest. This encoding is reversible,
7056
+ * allowing the original CID to be reconstructed from the on-chain data.
7057
+ *
7058
+ * Must be called by the owner of the disputed IP within the cooldown period.
7059
+ *
7060
+ * @param disputeId The ID of the dispute to assert.
7061
+ * @param counterEvidence The counter-evidence JSON object to upload to IPFS.
7062
+ * @returns A promise that resolves with the transaction result, IPFS CID, and counter-evidence hash.
7063
+ *
7064
+ * @example
7065
+ * ```typescript
7066
+ * const result = await origin.disputeAssertionSmart(
7067
+ * 1n,
7068
+ * { description: "This is my original work", proofUrl: "https://..." }
7069
+ * );
7070
+ *
7071
+ * // The CID can be recovered from counterEvidenceHash using decodeCidFromBytes32
7072
+ * console.log("Counter-evidence CID:", result.counterEvidenceCid);
7073
+ *
7074
+ * // Fetch counter-evidence via IPFS gateway
7075
+ * // https://ipfs.io/ipfs/{result.counterEvidenceCid}
7076
+ * ```
7077
+ */
7078
+ function disputeAssertionSmart(disputeId, counterEvidence) {
7079
+ return __awaiter(this, void 0, void 0, function* () {
7080
+ const cid = yield this.uploadJSONToIPFS(counterEvidence);
7081
+ const counterEvidenceHash = encodeCidToBytes32(cid);
7082
+ const transactionResult = yield this.disputeAssertion(disputeId, counterEvidenceHash);
7083
+ return {
7084
+ transactionResult,
7085
+ counterEvidenceCid: cid,
7086
+ counterEvidenceHash,
7087
+ };
7088
+ });
7089
+ }
7090
+
6907
7091
  /**
6908
7092
  * Votes on a dispute as a CAMP token staker.
6909
7093
  * Only users who staked before the dispute was raised can vote.
@@ -8001,6 +8185,7 @@ class Origin {
8001
8185
  this.raiseDispute = raiseDispute.bind(this);
8002
8186
  this.raiseDisputeSmart = raiseDisputeSmart.bind(this);
8003
8187
  this.disputeAssertion = disputeAssertion.bind(this);
8188
+ this.disputeAssertionSmart = disputeAssertionSmart.bind(this);
8004
8189
  this.voteOnDispute = voteOnDispute.bind(this);
8005
8190
  this.resolveDispute = resolveDispute.bind(this);
8006
8191
  this.cancelDispute = cancelDispute.bind(this);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@campnetwork/origin",
3
- "version": "1.3.0-alpha.6",
3
+ "version": "1.3.0-alpha.7",
4
4
  "main": "dist/core.cjs",
5
5
  "exports": {
6
6
  ".": {
@@ -41,6 +41,7 @@
41
41
  "@tanstack/react-query": "^5",
42
42
  "@walletconnect/ethereum-provider": "^2.17.2",
43
43
  "axios": "^1.7.7",
44
+ "bs58": "^6.0.0",
44
45
  "viem": "^2.21.37",
45
46
  "wagmi": "^2.12.33"
46
47
  },