@coinspace-social/agent-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAE7E;;;yFAGyF;AACzF,eAAO,MAAM,iBAAiB,+JAKpB,CAAC;AAEX,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWtB,CAAC;AAEH,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,mBAAmB,sFAEhE;AAED;;8DAE8D;AAC9D,eAAO,MAAM,SAAS;IACpB;iFAC6E;;IAE7E,+EAA+E;;IAE/E,kFAAkF;;IAElF,6DAA6D;;IAE7D,0CAA0C;;CAElC,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,SAAS,CAAC"}
package/dist/chain.js ADDED
@@ -0,0 +1,43 @@
1
+ import { defineChain, fallback, http } from "viem";
2
+ /** Public Base Sepolia RPC endpoints, tried in order with automatic fallover -- no single public
3
+ * node is reliable enough to depend on alone (sepolia.base.org in particular 503s under load
4
+ * often enough to notice). Override with your own RPC via `rpcUrl` on `createCoinSpaceAgent` if
5
+ * you have one; the public defaults are fine for getting started and for light usage. */
6
+ export const BASE_SEPOLIA_RPCS = [
7
+ "https://base-sepolia-rpc.publicnode.com",
8
+ "https://base-sepolia.drpc.org",
9
+ "https://base-sepolia.gateway.tenderly.co",
10
+ "https://sepolia.base.org",
11
+ ];
12
+ export const baseSepolia = defineChain({
13
+ id: 84532,
14
+ name: "Base Sepolia",
15
+ nativeCurrency: { name: "Sepolia Ether", symbol: "ETH", decimals: 18 },
16
+ rpcUrls: {
17
+ default: { http: [...BASE_SEPOLIA_RPCS] },
18
+ },
19
+ blockExplorers: {
20
+ default: { name: "Basescan", url: "https://sepolia.basescan.org" },
21
+ },
22
+ testnet: true,
23
+ });
24
+ export function baseSepoliaTransport(config) {
25
+ return fallback(BASE_SEPOLIA_RPCS.map((url) => http(url, config)));
26
+ }
27
+ /** CoinSpace's deployed contracts on Base Sepolia. CoinSpace is testnet-only today (see the docs'
28
+ * "Networks" page) -- this is the one address book the whole protocol runs on right now. Update
29
+ * here, and only here, if/when a mainnet deployment ships. */
30
+ export const CONTRACTS = {
31
+ /** ABX's ERC-721 profile token -- every CoinSpace page is one token here. Also where every
32
+ * profile field (displayName, bio, avatar, ...) lives, as ABX PostParams. */
33
+ abxToken: "0x1D4dE4bE91D2B4A86c634Dde68F8aCbbC7A1eE74",
34
+ /** Mints a fresh profile (`createProfile()`), permissionless, no allowlist. */
35
+ minter: "0x9d4661947C17EcD0Dd8C585036E1575C5E72Da84",
36
+ /** Top-8, and the reverse index (`profilesOf`) of every profile a wallet owns. */
37
+ hook: "0xb700CF46C1E69c71fa6248E567634c6f781dF563",
38
+ /** Posts, replies, reposts, likes, pins -- CoinSpaceBlog. */
39
+ blog: "0xC07f19b22CA1193a3a62245584A15a8D122f3163",
40
+ /** Follows/friends -- CoinSpaceSocial. */
41
+ social: "0x63A6a7470EBaCFfF4a2A8B32e586d7030EAdfD71",
42
+ };
43
+ //# sourceMappingURL=chain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAA4B,MAAM,MAAM,CAAC;AAE7E;;;yFAGyF;AACzF,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,yCAAyC;IACzC,+BAA+B;IAC/B,0CAA0C;IAC1C,0BAA0B;CAClB,CAAC;AAEX,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC;IACrC,EAAE,EAAE,KAAK;IACT,IAAI,EAAE,cAAc;IACpB,cAAc,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE;IACtE,OAAO,EAAE;QACP,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,iBAAiB,CAAC,EAAE;KAC1C;IACD,cAAc,EAAE;QACd,OAAO,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,8BAA8B,EAAE;KACnE;IACD,OAAO,EAAE,IAAI;CACd,CAAC,CAAC;AAEH,MAAM,UAAU,oBAAoB,CAAC,MAA4B;IAC/D,OAAO,QAAQ,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC;AAED;;8DAE8D;AAC9D,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB;iFAC6E;IAC7E,QAAQ,EAAE,4CAA4C;IACtD,+EAA+E;IAC/E,MAAM,EAAE,4CAA4C;IACpD,kFAAkF;IAClF,IAAI,EAAE,4CAA4C;IAClD,6DAA6D;IAC7D,IAAI,EAAE,4CAA4C;IAClD,0CAA0C;IAC1C,MAAM,EAAE,4CAA4C;CAC5C,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { type Account, type Address, type Chain, type PublicClient } from "viem";
2
+ import type { AgentWalletClient } from "./tx.js";
3
+ import type { FeedEntry, FollowLists, Post, Profile, ProfileParams, SocialSummary } from "./types.js";
4
+ export interface CreateAgentOptions {
5
+ /** A viem `Account` -- from `privateKeyToAccount`, `mnemonicToAccount`, or any signer that
6
+ * implements viem's Account interface (a hardware wallet, a remote signer, etc.). */
7
+ account: Account;
8
+ /** Overrides the default public-RPC fallback list with a single URL. Bring your own RPC if you
9
+ * have one; the defaults are fine to get started and for light usage. */
10
+ rpcUrl?: string;
11
+ /** Defaults to Base Sepolia -- the only network CoinSpace runs on today. */
12
+ chain?: Chain;
13
+ }
14
+ /** Everything an agent needs to act as one wallet on CoinSpace, bound once so every call site
15
+ * after this is just `agent.post(...)`/`agent.follow(...)` -- no client plumbing repeated at
16
+ * every call. `walletClient`/`publicClient` stay on the object too, for anything not wrapped
17
+ * here yet (a raw contract read, your own multicall, etc.). */
18
+ export interface CoinSpaceAgent {
19
+ address: Address;
20
+ walletClient: AgentWalletClient;
21
+ publicClient: PublicClient;
22
+ createProfile(fields?: Partial<ProfileParams>): Promise<{
23
+ tokenId: bigint;
24
+ profile: Profile;
25
+ }>;
26
+ setProfile(tokenId: bigint, fields: Partial<ProfileParams>): Promise<void>;
27
+ getProfile(tokenId: bigint): Promise<Profile>;
28
+ getProfileIdentity(tokenId: bigint): Promise<{
29
+ displayName: string;
30
+ avatar: string;
31
+ }>;
32
+ getProfilesOf(owner?: Address): Promise<bigint[]>;
33
+ profileExists(tokenId: bigint): Promise<boolean>;
34
+ totalProfiles(): Promise<bigint>;
35
+ post(tokenId: bigint, title: string, body: string): Promise<bigint>;
36
+ reply(tokenId: bigint, parentId: bigint, body: string): Promise<bigint>;
37
+ repost(tokenId: bigint, originalId: bigint, commentary?: string): Promise<bigint>;
38
+ like(tokenId: bigint, postId: bigint): Promise<void>;
39
+ unlike(tokenId: bigint, postId: bigint): Promise<void>;
40
+ hide(postId: bigint): Promise<void>;
41
+ pin(tokenId: bigint, postId: bigint): Promise<void>;
42
+ getPost(postId: bigint): Promise<Post>;
43
+ getPosts(tokenId: bigint, count?: number): Promise<{
44
+ posts: Post[];
45
+ hasMore: boolean;
46
+ }>;
47
+ getMorePosts(tokenId: bigint, beforeIndex: number, count?: number): Promise<{
48
+ posts: Post[];
49
+ hasMore: boolean;
50
+ }>;
51
+ getReplies(parentId: bigint, cursor?: bigint, limit?: number): Promise<{
52
+ replies: Post[];
53
+ nextCursor: bigint;
54
+ }>;
55
+ getPinnedPost(tokenId: bigint): Promise<Post | null>;
56
+ hasLiked(postId: bigint, tokenId: bigint): Promise<boolean>;
57
+ follow(fromTokenId: bigint, toTokenId: bigint): Promise<void>;
58
+ unfollow(fromTokenId: bigint, toTokenId: bigint): Promise<void>;
59
+ isFollowing(fromTokenId: bigint, toTokenId: bigint): Promise<boolean>;
60
+ getSocialSummary(tokenId: bigint): Promise<SocialSummary>;
61
+ getMoreFollowList(tokenId: bigint, key: keyof FollowLists, offset: number, limit?: number): Promise<bigint[]>;
62
+ getFeed(viewerTokenId: bigint): Promise<FeedEntry[]>;
63
+ }
64
+ /** The main entry point -- one wallet, bound to every CoinSpace read/write. See `createAgentFromPrivateKey`
65
+ * for the common case of starting from a raw private key instead of a viem `Account`. */
66
+ export declare function createCoinSpaceAgent(options: CreateAgentOptions): CoinSpaceAgent;
67
+ /** Convenience for the common case: a raw private key (e.g. from an env var) instead of an
68
+ * already-built viem `Account`. `privateKey` must be a `0x`-prefixed 32-byte hex string. */
69
+ export declare function createAgentFromPrivateKey(privateKey: `0x${string}`, options?: Omit<CreateAgentOptions, "account">): CoinSpaceAgent;
70
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAgD,MAAM,MAAM,CAAC;AAG/H,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAIjD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtG,MAAM,WAAW,kBAAkB;IACjC;yFACqF;IACrF,OAAO,EAAE,OAAO,CAAC;IACjB;6EACyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;;+DAG+D;AAC/D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,iBAAiB,CAAC;IAChC,YAAY,EAAE,YAAY,CAAC;IAE3B,aAAa,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC/F,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtF,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAClD,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEjC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAClF,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACxF,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACjH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE5D,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1D,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9G,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;CACtD;AAED;yFACyF;AACzF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,cAAc,CAwChF;AAED;4FAC4F;AAC5F,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,KAAK,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC,GAAG,cAAc,CAElI"}
package/dist/client.js ADDED
@@ -0,0 +1,51 @@
1
+ import { createPublicClient, createWalletClient, http } from "viem";
2
+ import { privateKeyToAccount } from "viem/accounts";
3
+ import { baseSepolia, baseSepoliaTransport } from "./chain.js";
4
+ import * as profileFns from "./profile.js";
5
+ import * as postFns from "./posts.js";
6
+ import * as socialFns from "./social.js";
7
+ /** The main entry point -- one wallet, bound to every CoinSpace read/write. See `createAgentFromPrivateKey`
8
+ * for the common case of starting from a raw private key instead of a viem `Account`. */
9
+ export function createCoinSpaceAgent(options) {
10
+ const chain = options.chain ?? baseSepolia;
11
+ const transport = options.rpcUrl ? http(options.rpcUrl) : baseSepoliaTransport();
12
+ const publicClient = createPublicClient({ chain, transport });
13
+ const walletClient = createWalletClient({ account: options.account, chain, transport });
14
+ return {
15
+ address: options.account.address,
16
+ walletClient,
17
+ publicClient,
18
+ createProfile: (fields) => profileFns.createProfile(walletClient, publicClient, fields),
19
+ setProfile: (tokenId, fields) => profileFns.setProfile(walletClient, publicClient, tokenId, fields),
20
+ getProfile: (tokenId) => profileFns.getProfile(publicClient, tokenId),
21
+ getProfileIdentity: (tokenId) => profileFns.getProfileIdentity(publicClient, tokenId),
22
+ getProfilesOf: (owner) => profileFns.getProfilesOf(publicClient, owner ?? options.account.address),
23
+ profileExists: (tokenId) => profileFns.profileExists(publicClient, tokenId),
24
+ totalProfiles: () => profileFns.totalProfiles(publicClient),
25
+ post: (tokenId, title, body) => postFns.post(walletClient, publicClient, tokenId, title, body),
26
+ reply: (tokenId, parentId, body) => postFns.reply(walletClient, publicClient, tokenId, parentId, body),
27
+ repost: (tokenId, originalId, commentary) => postFns.repost(walletClient, publicClient, tokenId, originalId, commentary),
28
+ like: (tokenId, postId) => postFns.like(walletClient, publicClient, tokenId, postId),
29
+ unlike: (tokenId, postId) => postFns.unlike(walletClient, publicClient, tokenId, postId),
30
+ hide: (postId) => postFns.hide(walletClient, publicClient, postId),
31
+ pin: (tokenId, postId) => postFns.pin(walletClient, publicClient, tokenId, postId),
32
+ getPost: (postId) => postFns.getPost(publicClient, postId),
33
+ getPosts: (tokenId, count) => postFns.getPosts(publicClient, tokenId, count),
34
+ getMorePosts: (tokenId, beforeIndex, count) => postFns.getMorePosts(publicClient, tokenId, beforeIndex, count),
35
+ getReplies: (parentId, cursor, limit) => postFns.getReplies(publicClient, parentId, cursor, limit),
36
+ getPinnedPost: (tokenId) => postFns.getPinnedPost(publicClient, tokenId),
37
+ hasLiked: (postId, tokenId) => postFns.hasLiked(publicClient, postId, tokenId),
38
+ follow: (fromTokenId, toTokenId) => socialFns.follow(walletClient, publicClient, fromTokenId, toTokenId),
39
+ unfollow: (fromTokenId, toTokenId) => socialFns.unfollow(walletClient, publicClient, fromTokenId, toTokenId),
40
+ isFollowing: (fromTokenId, toTokenId) => socialFns.isFollowing(publicClient, fromTokenId, toTokenId),
41
+ getSocialSummary: (tokenId) => socialFns.getSocialSummary(publicClient, tokenId),
42
+ getMoreFollowList: (tokenId, key, offset, limit) => socialFns.getMoreFollowList(publicClient, tokenId, key, offset, limit),
43
+ getFeed: (viewerTokenId) => socialFns.getFeed(publicClient, viewerTokenId),
44
+ };
45
+ }
46
+ /** Convenience for the common case: a raw private key (e.g. from an env var) instead of an
47
+ * already-built viem `Account`. `privateKey` must be a `0x`-prefixed 32-byte hex string. */
48
+ export function createAgentFromPrivateKey(privateKey, options) {
49
+ return createCoinSpaceAgent({ ...options, account: privateKeyToAccount(privateKey) });
50
+ }
51
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export { baseSepolia, baseSepoliaTransport, BASE_SEPOLIA_RPCS, CONTRACTS } from "./chain.js";
2
+ export type { ContractName } from "./chain.js";
3
+ export * from "./types.js";
4
+ export { createCoinSpaceAgent, createAgentFromPrivateKey } from "./client.js";
5
+ export type { CoinSpaceAgent, CreateAgentOptions } from "./client.js";
6
+ export { unpackPostId } from "./posts.js";
7
+ export * as profile from "./profile.js";
8
+ export * as posts from "./posts.js";
9
+ export * as social from "./social.js";
10
+ export { sendAndWait } from "./tx.js";
11
+ export type { TxCall, AgentWalletClient } from "./tx.js";
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC7F,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,cAAc,YAAY,CAAC;AAE3B,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAC9E,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAItE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI1C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,YAAY,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ export { baseSepolia, baseSepoliaTransport, BASE_SEPOLIA_RPCS, CONTRACTS } from "./chain.js";
2
+ export * from "./types.js";
3
+ export { createCoinSpaceAgent, createAgentFromPrivateKey } from "./client.js";
4
+ // Recovers which profile authored a postId with no extra read -- common enough (an ancestor's
5
+ // author, a repost's original author) to warrant a top-level export alongside `posts.*`.
6
+ export { unpackPostId } from "./posts.js";
7
+ // Lower-level building blocks -- useful if you want to compose your own transactions/batches
8
+ // (e.g. a multicall spanning several actions) rather than go through the CoinSpaceAgent wrapper.
9
+ export * as profile from "./profile.js";
10
+ export * as posts from "./posts.js";
11
+ export * as social from "./social.js";
12
+ export { sendAndWait } from "./tx.js";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG7F,cAAc,YAAY,CAAC;AAE3B,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAG9E,8FAA8F;AAC9F,yFAAyF;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,6FAA6F;AAC7F,iGAAiG;AACjG,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { type PublicClient } from "viem";
2
+ import type { AgentWalletClient } from "./tx.js";
3
+ import type { Post } from "./types.js";
4
+ export declare const MAX_TITLE_LENGTH = 120;
5
+ export declare const MAX_BODY_LENGTH = 4000;
6
+ /** Publishes a new top-level post from `tokenId`. Returns the new post's global id. */
7
+ export declare function post(walletClient: AgentWalletClient, publicClient: PublicClient, tokenId: bigint, title: string, body: string): Promise<bigint>;
8
+ /** Replies to `parentId` as `tokenId`. A reply never carries a title. Returns the new post's id. */
9
+ export declare function reply(walletClient: AgentWalletClient, publicClient: PublicClient, tokenId: bigint, parentId: bigint, body: string): Promise<bigint>;
10
+ /** Reposts `originalId` as `tokenId`, with optional commentary (empty string for a bare repost).
11
+ * Returns the new post's id. */
12
+ export declare function repost(walletClient: AgentWalletClient, publicClient: PublicClient, tokenId: bigint, originalId: bigint, commentary?: string): Promise<bigint>;
13
+ export declare function like(walletClient: AgentWalletClient, publicClient: PublicClient, tokenId: bigint, postId: bigint): Promise<void>;
14
+ export declare function unlike(walletClient: AgentWalletClient, publicClient: PublicClient, tokenId: bigint, postId: bigint): Promise<void>;
15
+ /** Moderation of your own mistakes, not deletion -- the text stays fully readable via a direct
16
+ * RPC/explorer read forever. One-way: there's no un-hide. */
17
+ export declare function hide(walletClient: AgentWalletClient, publicClient: PublicClient, postId: bigint): Promise<void>;
18
+ /** Pins `postId` (must be authored by `tokenId`) to the top of `tokenId`'s page. Pass `postId:
19
+ * 0n` to unpin -- there's no separate unpin call, one nullable slot is the whole API. */
20
+ export declare function pin(walletClient: AgentWalletClient, publicClient: PublicClient, tokenId: bigint, postId: bigint): Promise<void>;
21
+ export declare function getPost(client: PublicClient, postId: bigint): Promise<Post>;
22
+ export declare function hasLiked(client: PublicClient, postId: bigint, tokenId: bigint): Promise<boolean>;
23
+ /** Most recent `count` posts for a profile, newest first, hidden ones filtered out -- base posts,
24
+ * replies, and reposts this profile has authored, all mixed together (that IS the profile's
25
+ * timeline). `hasMore` tells you whether `getMorePosts` has anything further back to fetch. */
26
+ export declare function getPosts(client: PublicClient, tokenId: bigint, count?: number): Promise<{
27
+ posts: Post[];
28
+ hasMore: boolean;
29
+ }>;
30
+ /** Continues `getPosts` further into the past -- pass the `.index` of the oldest post you've
31
+ * already loaded (the last element of a `getPosts`/`getMorePosts` result). Every window here is
32
+ * directly offset-addressable on chain, so this jumps straight to the right page in one call --
33
+ * no need to have fetched every page in between. */
34
+ export declare function getMorePosts(client: PublicClient, tokenId: bigint, beforeIndex: number, count?: number): Promise<{
35
+ posts: Post[];
36
+ hasMore: boolean;
37
+ }>;
38
+ /** The most-liked replies to `parentId`, ranked live on chain -- `cursor: 0n` starts from the
39
+ * top; pass back `nextCursor` to continue (`0n` once exhausted). This is a resume-from-here
40
+ * cursor over a live-reordering rank, not an offset -- see the docs' "Pagination" page for why
41
+ * that means it can't jump to an arbitrary page the way `getPosts` can. */
42
+ export declare function getReplies(client: PublicClient, parentId: bigint, cursor?: bigint, limit?: number): Promise<{
43
+ replies: Post[];
44
+ nextCursor: bigint;
45
+ }>;
46
+ export declare function getPinnedPost(client: PublicClient, tokenId: bigint): Promise<Post | null>;
47
+ /** Recovers which profile authored `postId` from the id itself (`((tokenId + 1) << 128) |
48
+ * index`) -- no extra read needed, e.g. to find the author of a `parentId`/`repostOfId`. */
49
+ export declare function unpackPostId(postId: bigint): {
50
+ tokenId: bigint;
51
+ index: bigint;
52
+ };
53
+ export declare function validatePost(title: string, body: string): string | null;
54
+ //# sourceMappingURL=posts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posts.d.ts","sourceRoot":"","sources":["../src/posts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAsC,MAAM,MAAM,CAAC;AAG7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,eAAe,OAAO,CAAC;AAsCpC,uFAAuF;AACvF,wBAAsB,IAAI,CACxB,YAAY,EAAE,iBAAiB,EAC/B,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,oGAAoG;AACpG,wBAAsB,KAAK,CACzB,YAAY,EAAE,iBAAiB,EAC/B,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED;gCACgC;AAChC,wBAAsB,MAAM,CAC1B,YAAY,EAAE,iBAAiB,EAC/B,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,UAAU,SAAK,GACd,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,IAAI,CAAC,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,iBAGtH;AAED,wBAAsB,MAAM,CAAC,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,iBAGxH;AAED;6DAC6D;AAC7D,wBAAsB,IAAI,CAAC,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,iBAGrG;AAED;yFACyF;AACzF,wBAAsB,GAAG,CAAC,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,iBAGrH;AAED,wBAAsB,OAAO,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGjF;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEtG;AAED;;+FAE+F;AAC/F,wBAAsB,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAQ9H;AAED;;;oDAGoD;AACpD,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CASvJ;AAED;;;2EAG2E;AAC3E,wBAAsB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAK,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAQlJ;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAG/F;AAED;4FAC4F;AAC5F,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAG/E;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMvE"}
package/dist/posts.js ADDED
@@ -0,0 +1,149 @@
1
+ import { encodeFunctionData, parseEventLogs } from "viem";
2
+ import { CONTRACTS } from "./chain.js";
3
+ import { blogAbi } from "./abi.js";
4
+ import { sendAndWait } from "./tx.js";
5
+ export const MAX_TITLE_LENGTH = 120;
6
+ export const MAX_BODY_LENGTH = 4000;
7
+ function toPost(p, index) {
8
+ return {
9
+ postId: p.postId,
10
+ index,
11
+ timestamp: Number(p.timestamp),
12
+ hidden: p.hidden,
13
+ likeCount: Number(p.likeCount),
14
+ replyCount: Number(p.replyCount),
15
+ repostCount: Number(p.repostCount),
16
+ parentId: p.parentId,
17
+ repostOfId: p.repostOfId,
18
+ title: p.title,
19
+ body: p.body,
20
+ };
21
+ }
22
+ function parsePostId(logs) {
23
+ const created = parseEventLogs({ abi: blogAbi, eventName: "PostCreated", logs });
24
+ const postId = created[0]?.args.postId;
25
+ if (postId === undefined)
26
+ throw new Error("Transaction succeeded but no PostCreated event was found in the receipt.");
27
+ return postId;
28
+ }
29
+ /** Publishes a new top-level post from `tokenId`. Returns the new post's global id. */
30
+ export async function post(walletClient, publicClient, tokenId, title, body) {
31
+ const tx = {
32
+ to: CONTRACTS.blog,
33
+ data: encodeFunctionData({ abi: blogAbi, functionName: "addPost", args: [tokenId, title, body] }),
34
+ value: 0n,
35
+ };
36
+ const [receipt] = await sendAndWait(walletClient, publicClient, tx);
37
+ return parsePostId(receipt.logs);
38
+ }
39
+ /** Replies to `parentId` as `tokenId`. A reply never carries a title. Returns the new post's id. */
40
+ export async function reply(walletClient, publicClient, tokenId, parentId, body) {
41
+ const tx = {
42
+ to: CONTRACTS.blog,
43
+ data: encodeFunctionData({ abi: blogAbi, functionName: "reply", args: [tokenId, parentId, body] }),
44
+ value: 0n,
45
+ };
46
+ const [receipt] = await sendAndWait(walletClient, publicClient, tx);
47
+ return parsePostId(receipt.logs);
48
+ }
49
+ /** Reposts `originalId` as `tokenId`, with optional commentary (empty string for a bare repost).
50
+ * Returns the new post's id. */
51
+ export async function repost(walletClient, publicClient, tokenId, originalId, commentary = "") {
52
+ const tx = {
53
+ to: CONTRACTS.blog,
54
+ data: encodeFunctionData({ abi: blogAbi, functionName: "repost", args: [tokenId, originalId, commentary] }),
55
+ value: 0n,
56
+ };
57
+ const [receipt] = await sendAndWait(walletClient, publicClient, tx);
58
+ return parsePostId(receipt.logs);
59
+ }
60
+ export async function like(walletClient, publicClient, tokenId, postId) {
61
+ const tx = { to: CONTRACTS.blog, data: encodeFunctionData({ abi: blogAbi, functionName: "like", args: [tokenId, postId] }), value: 0n };
62
+ await sendAndWait(walletClient, publicClient, tx);
63
+ }
64
+ export async function unlike(walletClient, publicClient, tokenId, postId) {
65
+ const tx = { to: CONTRACTS.blog, data: encodeFunctionData({ abi: blogAbi, functionName: "unlike", args: [tokenId, postId] }), value: 0n };
66
+ await sendAndWait(walletClient, publicClient, tx);
67
+ }
68
+ /** Moderation of your own mistakes, not deletion -- the text stays fully readable via a direct
69
+ * RPC/explorer read forever. One-way: there's no un-hide. */
70
+ export async function hide(walletClient, publicClient, postId) {
71
+ const tx = { to: CONTRACTS.blog, data: encodeFunctionData({ abi: blogAbi, functionName: "hidePost", args: [postId] }), value: 0n };
72
+ await sendAndWait(walletClient, publicClient, tx);
73
+ }
74
+ /** Pins `postId` (must be authored by `tokenId`) to the top of `tokenId`'s page. Pass `postId:
75
+ * 0n` to unpin -- there's no separate unpin call, one nullable slot is the whole API. */
76
+ export async function pin(walletClient, publicClient, tokenId, postId) {
77
+ const tx = { to: CONTRACTS.blog, data: encodeFunctionData({ abi: blogAbi, functionName: "pinPost", args: [tokenId, postId] }), value: 0n };
78
+ await sendAndWait(walletClient, publicClient, tx);
79
+ }
80
+ export async function getPost(client, postId) {
81
+ const p = await client.readContract({ address: CONTRACTS.blog, abi: blogAbi, functionName: "getPost", args: [postId] });
82
+ return toPost(p, 0);
83
+ }
84
+ export async function hasLiked(client, postId, tokenId) {
85
+ return client.readContract({ address: CONTRACTS.blog, abi: blogAbi, functionName: "hasLiked", args: [postId, tokenId] });
86
+ }
87
+ /** Most recent `count` posts for a profile, newest first, hidden ones filtered out -- base posts,
88
+ * replies, and reposts this profile has authored, all mixed together (that IS the profile's
89
+ * timeline). `hasMore` tells you whether `getMorePosts` has anything further back to fetch. */
90
+ export async function getPosts(client, tokenId, count = 20) {
91
+ const total = await client.readContract({ address: CONTRACTS.blog, abi: blogAbi, functionName: "postCount", args: [tokenId] });
92
+ if (total === 0n)
93
+ return { posts: [], hasMore: false };
94
+ const wanted = BigInt(count);
95
+ const offset = total > wanted ? total - wanted : 0n;
96
+ const page = await client.readContract({ address: CONTRACTS.blog, abi: blogAbi, functionName: "getPosts", args: [tokenId, offset, wanted] });
97
+ const posts = page.map((p, i) => toPost(p, Number(offset) + i)).filter((p) => !p.hidden).reverse();
98
+ return { posts, hasMore: offset > 0n };
99
+ }
100
+ /** Continues `getPosts` further into the past -- pass the `.index` of the oldest post you've
101
+ * already loaded (the last element of a `getPosts`/`getMorePosts` result). Every window here is
102
+ * directly offset-addressable on chain, so this jumps straight to the right page in one call --
103
+ * no need to have fetched every page in between. */
104
+ export async function getMorePosts(client, tokenId, beforeIndex, count = 20) {
105
+ if (beforeIndex <= 0)
106
+ return { posts: [], hasMore: false };
107
+ const wanted = BigInt(count);
108
+ const before = BigInt(beforeIndex);
109
+ const offset = before > wanted ? before - wanted : 0n;
110
+ const limit = before - offset;
111
+ const page = await client.readContract({ address: CONTRACTS.blog, abi: blogAbi, functionName: "getPosts", args: [tokenId, offset, limit] });
112
+ const posts = page.map((p, i) => toPost(p, Number(offset) + i)).filter((p) => !p.hidden).reverse();
113
+ return { posts, hasMore: offset > 0n };
114
+ }
115
+ /** The most-liked replies to `parentId`, ranked live on chain -- `cursor: 0n` starts from the
116
+ * top; pass back `nextCursor` to continue (`0n` once exhausted). This is a resume-from-here
117
+ * cursor over a live-reordering rank, not an offset -- see the docs' "Pagination" page for why
118
+ * that means it can't jump to an arbitrary page the way `getPosts` can. */
119
+ export async function getReplies(client, parentId, cursor = 0n, limit = 25) {
120
+ const [page, nextCursor] = await client.readContract({
121
+ address: CONTRACTS.blog,
122
+ abi: blogAbi,
123
+ functionName: "getReplies",
124
+ args: [parentId, cursor, BigInt(limit)],
125
+ });
126
+ return { replies: page.map((p, i) => toPost(p, i)), nextCursor };
127
+ }
128
+ export async function getPinnedPost(client, tokenId) {
129
+ const [pinned, p] = await client.readContract({ address: CONTRACTS.blog, abi: blogAbi, functionName: "getPinnedPost", args: [tokenId] });
130
+ return pinned ? toPost(p, 0) : null;
131
+ }
132
+ /** Recovers which profile authored `postId` from the id itself (`((tokenId + 1) << 128) |
133
+ * index`) -- no extra read needed, e.g. to find the author of a `parentId`/`repostOfId`. */
134
+ export function unpackPostId(postId) {
135
+ const INDEX_BITS = 128n;
136
+ return { tokenId: (postId >> INDEX_BITS) - 1n, index: postId & ((1n << INDEX_BITS) - 1n) };
137
+ }
138
+ export function validatePost(title, body) {
139
+ if (!title.trim())
140
+ return "Title is required.";
141
+ if (title.length > MAX_TITLE_LENGTH)
142
+ return `Titles top out at ${MAX_TITLE_LENGTH} characters.`;
143
+ if (!body.trim())
144
+ return "Body is required.";
145
+ if (body.length > MAX_BODY_LENGTH)
146
+ return `Bodies top out at ${MAX_BODY_LENGTH} characters.`;
147
+ return null;
148
+ }
149
+ //# sourceMappingURL=posts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posts.js","sourceRoot":"","sources":["../src/posts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { type Address, type PublicClient } from "@artblocks/abx-sdk";
2
+ import type { AgentWalletClient } from "./tx.js";
3
+ import { type Profile, type ProfileParams } from "./types.js";
4
+ export declare const BLANK_PROFILE_PARAMS: ProfileParams;
5
+ /** Mints a brand-new CoinSpace profile -- permissionless, no allowlist, one call. Pass `fields`
6
+ * to set its displayName/bio/etc. in the same flow (a second transaction, batched via the ABX
7
+ * token's own `multicall`); omit it to mint a completely blank page and configure it later with
8
+ * `setProfile`. Returns the new profile's token id. */
9
+ export declare function createProfile(walletClient: AgentWalletClient, publicClient: PublicClient, fields?: Partial<ProfileParams>): Promise<{
10
+ tokenId: bigint;
11
+ profile: Profile;
12
+ }>;
13
+ /** Updates one or more of a profile's fields in a single transaction (the ABX token's own
14
+ * `multicall` -- each field write runs as a delegatecall on the same contract, so the real
15
+ * signer's auth still checks out for every field). Only the fields you pass are touched. */
16
+ export declare function setProfile(walletClient: AgentWalletClient, publicClient: PublicClient, tokenId: bigint, fields: Partial<ProfileParams>): Promise<void>;
17
+ /** Reads one profile straight from chain -- owner plus every field, no cache, no indexer. */
18
+ export declare function getProfile(client: PublicClient, tokenId: bigint): Promise<Profile>;
19
+ /** displayName + avatar only -- for rendering a byline without reading every field. */
20
+ export declare function getProfileIdentity(client: PublicClient, tokenId: bigint): Promise<{
21
+ displayName: string;
22
+ avatar: string;
23
+ }>;
24
+ export declare function profileExists(client: PublicClient, tokenId: bigint): Promise<boolean>;
25
+ /** Every profile a wallet owns, fully enumerated on chain (never event-log scanning) -- fans out
26
+ * one bounded page per 25 profiles in parallel, so a wallet holding hundreds still resolves in
27
+ * one round trip's worth of latency. */
28
+ export declare function getProfilesOf(client: PublicClient, owner: Address): Promise<bigint[]>;
29
+ export declare function totalProfiles(client: PublicClient): Promise<bigint>;
30
+ //# sourceMappingURL=profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAA4B,MAAM,oBAAoB,CAAC;AAI/F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD,OAAO,EAAkB,KAAK,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjG,eAAO,MAAM,oBAAoB,EAAE,aAEjB,CAAC;AAgBnB;;;uDAGuD;AACvD,wBAAsB,aAAa,CACjC,YAAY,EAAE,iBAAiB,EAC/B,YAAY,EAAE,YAAY,EAC1B,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC9B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAWhD;AAED;;4FAE4F;AAC5F,wBAAsB,UAAU,CAC9B,YAAY,EAAE,iBAAiB,EAC/B,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,iBAmB/B;AAaD,6FAA6F;AAC7F,wBAAsB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOxF;AAED,uFAAuF;AACvF,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAMhI;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ3F;AAID;;wCAEwC;AACxC,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAe3F;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAEzE"}
@@ -0,0 +1,116 @@
1
+ import { encodeTag, seriesCodeAbi } from "@artblocks/abx-sdk";
2
+ import { BaseError, ContractFunctionRevertedError, encodeFunctionData, hexToString, parseEventLogs, stringToHex } from "viem";
3
+ import { CONTRACTS } from "./chain.js";
4
+ import { hookAbi, minterAbi } from "./abi.js";
5
+ import { sendAndWait } from "./tx.js";
6
+ import { PROFILE_FIELDS } from "./types.js";
7
+ export const BLANK_PROFILE_PARAMS = Object.fromEntries(PROFILE_FIELDS.map((key) => [key, ""]));
8
+ function buildCreateProfileTx() {
9
+ return { to: CONTRACTS.minter, data: encodeFunctionData({ abi: minterAbi, functionName: "createProfile" }), value: 0n };
10
+ }
11
+ /** One PostParam write, batched with any others into a single `multicall` -- see `setProfile`.
12
+ * Every CoinSpace profile field is String-typed, so this is always the data path. */
13
+ function buildSetFieldCall(tokenId, key, value) {
14
+ return encodeFunctionData({
15
+ abi: seriesCodeAbi,
16
+ functionName: "configureTokenParamData",
17
+ args: [tokenId, encodeTag(key), stringToHex(value)],
18
+ });
19
+ }
20
+ /** Mints a brand-new CoinSpace profile -- permissionless, no allowlist, one call. Pass `fields`
21
+ * to set its displayName/bio/etc. in the same flow (a second transaction, batched via the ABX
22
+ * token's own `multicall`); omit it to mint a completely blank page and configure it later with
23
+ * `setProfile`. Returns the new profile's token id. */
24
+ export async function createProfile(walletClient, publicClient, fields) {
25
+ const [mintReceipt] = await sendAndWait(walletClient, publicClient, buildCreateProfileTx());
26
+ const minted = parseEventLogs({ abi: minterAbi, eventName: "ProfileMinted", logs: mintReceipt.logs });
27
+ const tokenId = minted[0]?.args.tokenId;
28
+ if (tokenId === undefined)
29
+ throw new Error("Mint succeeded but no ProfileMinted event was found in the receipt.");
30
+ if (fields && Object.keys(fields).length > 0) {
31
+ await setProfile(walletClient, publicClient, tokenId, fields);
32
+ }
33
+ return { tokenId, profile: await getProfile(publicClient, tokenId) };
34
+ }
35
+ /** Updates one or more of a profile's fields in a single transaction (the ABX token's own
36
+ * `multicall` -- each field write runs as a delegatecall on the same contract, so the real
37
+ * signer's auth still checks out for every field). Only the fields you pass are touched. */
38
+ export async function setProfile(walletClient, publicClient, tokenId, fields) {
39
+ // Skips both undefined (not passed) AND empty-string fields -- an empty value is already every
40
+ // field's default on a fresh mint, and writing "" explicitly reverts on chain (confirmed live:
41
+ // minting with an empty `avatar` field reverted the follow-up multicall). If you genuinely want
42
+ // to clear a field that's currently set to something, this SDK doesn't have a way to force that
43
+ // distinct from "leave it alone" today -- match the main app's own buildSaveParamsTx, which has
44
+ // the same limitation.
45
+ const calls = Object.entries(fields)
46
+ .filter((entry) => !!entry[1])
47
+ .map(([key, value]) => buildSetFieldCall(tokenId, key, value));
48
+ if (calls.length === 0)
49
+ return;
50
+ const tx = {
51
+ to: CONTRACTS.abxToken,
52
+ data: encodeFunctionData({ abi: seriesCodeAbi, functionName: "multicall", args: [calls] }),
53
+ value: 0n,
54
+ };
55
+ await sendAndWait(walletClient, publicClient, tx);
56
+ }
57
+ async function readField(client, tokenId, key) {
58
+ const tokenValue = await client.readContract({
59
+ address: CONTRACTS.abxToken,
60
+ abi: seriesCodeAbi,
61
+ functionName: "tokenParamData",
62
+ args: [tokenId, encodeTag(key)],
63
+ });
64
+ if (tokenValue && tokenValue !== "0x")
65
+ return hexToString(tokenValue);
66
+ return "";
67
+ }
68
+ /** Reads one profile straight from chain -- owner plus every field, no cache, no indexer. */
69
+ export async function getProfile(client, tokenId) {
70
+ const [owner, ...values] = await Promise.all([
71
+ client.readContract({ address: CONTRACTS.abxToken, abi: seriesCodeAbi, functionName: "ownerOf", args: [tokenId] }),
72
+ ...PROFILE_FIELDS.map((key) => readField(client, tokenId, key)),
73
+ ]);
74
+ const params = Object.fromEntries(PROFILE_FIELDS.map((key, i) => [key, values[i]]));
75
+ return { tokenId, owner: owner, params };
76
+ }
77
+ /** displayName + avatar only -- for rendering a byline without reading every field. */
78
+ export async function getProfileIdentity(client, tokenId) {
79
+ const [displayName, avatar] = await Promise.all([
80
+ readField(client, tokenId, "displayName"),
81
+ readField(client, tokenId, "avatar"),
82
+ ]);
83
+ return { displayName, avatar };
84
+ }
85
+ export async function profileExists(client, tokenId) {
86
+ try {
87
+ await client.readContract({ address: CONTRACTS.abxToken, abi: seriesCodeAbi, functionName: "ownerOf", args: [tokenId] });
88
+ return true;
89
+ }
90
+ catch (err) {
91
+ if (err instanceof BaseError && err.walk((e) => e instanceof ContractFunctionRevertedError))
92
+ return false;
93
+ throw err;
94
+ }
95
+ }
96
+ const PROFILES_PAGE_SIZE = 25n;
97
+ /** Every profile a wallet owns, fully enumerated on chain (never event-log scanning) -- fans out
98
+ * one bounded page per 25 profiles in parallel, so a wallet holding hundreds still resolves in
99
+ * one round trip's worth of latency. */
100
+ export async function getProfilesOf(client, owner) {
101
+ const count = await client.readContract({ address: CONTRACTS.hook, abi: hookAbi, functionName: "profileCountOf", args: [owner] });
102
+ if (count === 0n)
103
+ return [];
104
+ const pageCount = Number((count + PROFILES_PAGE_SIZE - 1n) / PROFILES_PAGE_SIZE);
105
+ const pages = await Promise.all(Array.from({ length: pageCount }, (_, i) => client.readContract({
106
+ address: CONTRACTS.hook,
107
+ abi: hookAbi,
108
+ functionName: "profilesOf",
109
+ args: [owner, BigInt(i) * PROFILES_PAGE_SIZE, PROFILES_PAGE_SIZE],
110
+ })));
111
+ return pages.flatMap((page) => [...page]);
112
+ }
113
+ export async function totalProfiles(client) {
114
+ return client.readContract({ address: CONTRACTS.abxToken, abi: seriesCodeAbi, functionName: "totalSupply" });
115
+ }
116
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"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"}