@nexus-cross/pop 1.4.0-beta.6 → 2.4.0-beta.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/AGENTS.md +8 -1
- package/README.md +9 -1
- package/dist/{createSafeDrop-DtWLupoE.d.ts → SafeDropApiPort-BLewfSaK.d.ts} +1 -310
- package/dist/adapters/index.d.ts +6 -303
- package/dist/adapters/index.js +1 -1
- package/dist/api/index.d.ts +3 -0
- package/dist/api/index.js +1 -0
- package/dist/chunk-5DT3H2VX.js +1 -0
- package/dist/chunk-GS7GCYQD.js +1 -0
- package/dist/chunk-I7UGWJHZ.js +1 -0
- package/dist/createSafeDrop-DfiY8vHq.d.ts +312 -0
- package/dist/index-2sfHzZeD.d.ts +305 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/react/index.d.ts +2 -1
- package/package.json +5 -1
- package/dist/chunk-SX7PPVTJ.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as i}from"./chunk-5DT3H2VX.js";function g(a){return a.trim().replace(/^@/,"").toLowerCase()}function S(a){let e=a.baseUrl.replace(/\/$/,""),r=e.includes("?")?"&":"?",n=a.claimAddress?`&claim=${encodeURIComponent(a.claimAddress)}`:"",s=`${e}${r}sender=${encodeURIComponent(a.sender)}${n}`;return a.secret?`${s}#${encodeURIComponent(a.secret)}`:s}function E(a){let e=a.indexOf("#"),r=e===-1?a:a.slice(0,e),n=e===-1?"":a.slice(e+1),s=r.indexOf("?"),d=s===-1?"":r.slice(s+1);return{sender:A(d,"sender"),secret:n?decodeURIComponent(n):null}}function B(a){return`\u{1F381} You've received a one-pop drop! Claim your tokens here: ${a}`}function M(a,e){let r=[`text=${encodeURIComponent(a)}`];return e&&r.push(`recipient_id=${encodeURIComponent(e)}`),`https://x.com/messages/compose?${r.join("&")}`}function A(a,e){if(!a)return null;for(let r of a.split("&")){if(!r)continue;let n=r.indexOf("=");if(decodeURIComponent(n===-1?r:r.slice(0,n))===e)return decodeURIComponent(n===-1?"":r.slice(n+1))}return null}var y=class{constructor(e,r,n,s){this.chain=e;this.api=r;this.crypto=n;this.claimBaseUrl=s}async execute(e){if(!e.sender)throw new i("MISSING_SENDER","sender address is required");if(!e.recipient?.handle)throw new i("MISSING_RECIPIENT","recipient social handle is required");if(!e.token)throw new i("INVALID_TOKEN","token address is required (ERC20 only)");if(e.amount<=0n)throw new i("INVALID_AMOUNT","amount must be a positive BigInt");if(e.message&&[...e.message].length>140)throw new i("INVALID_PARAM","message must be <= 140 runes");let r=g(e.recipient.handle);if(!r)throw new i("MISSING_RECIPIENT","recipient handle normalizes to empty");let n=await this.api.createClaimWallet({sender:e.sender,recipient:{...e.recipient,handle:r}}),s=n.id,d=async m=>{if(this.api.recordDropMetadata)try{await this.api.recordDropMetadata({txHash:m,message:e.message,envelopeId:e.envelopeId})}catch(c){if(c instanceof i&&c.details?.codeName==="ENVELOPE_NOT_FOUND"&&e.envelopeId)try{await this.api.recordDropMetadata({txHash:m,message:e.message})}catch{}}};if(n.isMapped){let{txHash:m,dropKey:c}=await this.chain.depositMapped({token:e.token,amount:e.amount,id:s,onSubmitted:d});return{isMapped:!0,dropKey:c,depositTxHash:m}}let o=e.secret??this.crypto.randomSecret();if(!o)throw new i("MISSING_SECRET","secret is empty");let t=this.crypto.keccak256(o),l={claimAddress:n.claimAddress,token:e.token,amount:e.amount,id:s,secretHash:t,onSubmitted:d},{txHash:h,dropKey:u}=await this.chain.depositWithPermit(l);return{isMapped:!1,dropKey:u,claimAddress:n.claimAddress,secretHash:t,withdrawLink:S({baseUrl:this.claimBaseUrl,sender:e.sender,claimAddress:n.claimAddress,secret:o}),depositTxHash:h}}};var b=BigInt(1800),N=30,f=class{constructor(e,r,n,s=()=>Date.now()){this.chain=e;this.api=r;this.crypto=n;this.now=s}async execute(e){let r=g(e.id);if(!r)throw new i("MISSING_RECIPIENT","batchClaim requires an id");if(!e.claimAddress)throw new i("MISSING_CLAIM_ADDRESS","claim address is required");if(!e.sponsor)throw new i("MISSING_SENDER","sponsor address is required");if(!e.claimKey)throw new i("MISSING_CLAIM_KEY","claim key is required");if(!e.secret)throw new i("MISSING_SECRET","secret is required");if(!this.api.requestBatchClaimSignature)throw new i("API_ERROR","requestBatchClaimSignature is not implemented");if(!this.chain.getValidatorNonce||!this.chain.getValidatorClaimDigest||!this.chain.getValidator)throw new i("CHAIN_ERROR","validator reads are not implemented");let n=await this.chain.getDropKeyByClaimAddress(e.claimAddress,e.sponsor);if(!n)throw new i("DROP_NOT_FOUND","anchor drop not found");let s=await this.chain.getDropByKey(n);if(!s||s.id!==r)throw new i("DROP_NOT_FOUND","anchor drop id does not match");let d=await this.chain.getPendingDropsById({id:r});if(!d.length)throw new i("DROP_NOT_FOUND",`No pending drops for ${r}`);let o=e.maxCount??N;if(!Number.isSafeInteger(o)||o<=0)throw new i("INVALID_PARAM","maxCount must be a positive safe integer");let t=e.deadline??BigInt(Math.floor(this.now()/1e3))+(e.deadlineTtlSeconds??b),l=[],h="",u=BigInt(0);for(;d.length;){let m=await this.chain.getValidatorNonce({id:r}),c=await this.api.requestBatchClaimSignature({id:r,oauth:e.oauth,nonce:m,deadline:t});if(e.recipient&&e.recipient.toLowerCase()!==c.recipient.toLowerCase())throw new i("SIGN_FAILED","validator signature is bound to a different recipient");if(h&&h.toLowerCase()!==c.recipient.toLowerCase())throw new i("SIGN_FAILED","validator recipient changed between batches");h=c.recipient,l.length||(u=c.nonce);let R=await this.chain.getValidatorClaimDigest({recipient:h,id:r,nonce:c.nonce,deadline:c.deadline});await this.assertSignedByValidator(R,c.signature);let I=d.length,D=await this.chain.withdrawUnmappedBatchByKeys({claimKey:e.claimKey,recipient:h,id:r,anchorDropKey:n,secret:e.secret,nonce:c.nonce,deadline:c.deadline,dropKeys:d.slice(0,o).map(C=>C.dropKey).filter(C=>C.toLowerCase()!==n.toLowerCase()),validatorSignature:c.signature});if(l.push(D),d=await this.chain.getPendingDropsById({id:r}),d.length>=I)throw new i("CHAIN_ERROR","batch claim made no progress",{id:r,txHash:D})}return{txHashes:l,recipient:h,id:r,nonce:u,deadline:t}}async assertSignedByValidator(e,r){if(!this.crypto.recoverAddress||!this.chain.getValidator)return;let[n,s]=await Promise.all([this.crypto.recoverAddress({digest:e,signature:r}),this.chain.getValidator()]);if(n.toLowerCase()!==s.toLowerCase())throw new i("SIGN_FAILED","batch-claim signature does not recover to validator")}};var P=class{constructor(e,r){this.chain=e;this.signer=r}async execute(e){if(!e.recipient)throw new i("MISSING_RECIPIENT","recipient address is required");if(!e.claimAddress)throw new i("MISSING_CLAIM_ADDRESS","claim address is required");if(!e.secret)throw new i("MISSING_SECRET","secret is required");if(!e.claimKey)throw new i("MISSING_CLAIM_KEY","claim key is required");if(!e.sponsor)throw new i("MISSING_SENDER","sponsor address is required");let r=await this.chain.getDropKeyByClaimAddress(e.claimAddress,e.sponsor);if(!r)throw new i("DROP_NOT_FOUND",`No drop for claim address ${e.claimAddress}`);let n=await this.chain.getDropByKey(r);if(!n)throw new i("DROP_NOT_FOUND",`No drop for key ${r}`);let s=await this.chain.getClaimDigest({recipient:e.recipient,id:n.id,dropKey:r}),d=await this.signer.signDigest({claimKey:e.claimKey,digest:s});return{txHash:await this.chain.withdrawUnmapped({claimKey:e.claimKey,recipient:e.recipient,id:n.id,dropKey:r,signature:d,secret:e.secret})}}};var w=class{constructor(e){this.chain=e}async execute(e){if(!e.claimAddress)throw new i("MISSING_CLAIM_ADDRESS","claim address is required");if(!e.sponsor)throw new i("MISSING_SENDER","sponsor address is required");let r=await this.chain.getDropKeyByClaimAddress(e.claimAddress,e.sponsor);if(!r)throw new i("DROP_NOT_FOUND",`No drop for claim address ${e.claimAddress}`);return{txHash:await this.chain.refundByKey({dropKey:r})}}};function p(a,e){if(!a)throw new i("API_ERROR",`SafeDropApiPort.${e} is not implemented by the injected api adapter`);return a}function Y(a,e){let r=new y(e.chain,e.api,e.crypto,a.claimBaseUrl),n=new P(e.chain,e.signer),s=new w(e.chain),d=new f(e.chain,e.api,e.crypto),{api:o}=e;return{config:a,deposit:t=>r.execute(t),retrieveClaimKey:t=>o.retrieveClaimKey(t),withdraw:t=>n.execute(t),refund:t=>s.execute(t),getDrop:(t,l)=>e.chain.getDrop(t,l),getDropByKey:t=>e.chain.getDropByKey(t),getDropKeyByClaimAddress:(t,l)=>e.chain.getDropKeyByClaimAddress(t,l),getClaimedRecipient:t=>e.chain.getClaimedRecipient({id:t}),getPendingDropsById:t=>e.chain.getPendingDropsById({id:t}),getPendingDropsByRecipient:t=>e.chain.getPendingDropsByRecipient({recipient:t}),getPendingDropsBySponsor:t=>e.chain.getPendingDropsBySponsor({sponsor:t}),withdrawUnmapped:t=>e.chain.withdrawUnmapped(t),withdrawMapped:t=>e.chain.withdrawMapped(t),batchWithdrawMapped:t=>e.chain.batchWithdrawMapped({count:t}),batchWithdrawMappedByKeys:t=>e.chain.batchWithdrawMappedByKeys({dropKeys:t}),refundByKey:t=>e.chain.refundByKey({dropKey:t}),getChangeNonce:t=>e.chain.getChangeNonce({id:t}),getPendingRecipientChange:t=>e.chain.getPendingRecipientChange({id:t}),requestRecipientChange:(t,l)=>e.chain.requestRecipientChange({id:t,newRecipient:l}),completeRecipientChange:t=>e.chain.completeRecipientChange(t),cancelRecipientChange:t=>e.chain.cancelRecipientChange({id:t}),resetRecipient:t=>e.chain.resetRecipient(t),listDrops:t=>p(o.listDrops,"listDrops").call(o,t),rejectDrops:t=>p(o.rejectDrops,"rejectDrops").call(o,{dropIds:t}),listEnvelopes:t=>p(o.listEnvelopes,"listEnvelopes").call(o,t),getLeaderboard:t=>p(o.getLeaderboard,"getLeaderboard").call(o,t),getMyLeaderboardEntry:t=>p(o.getMyLeaderboardEntry,"getMyLeaderboardEntry").call(o,t),listHistories:t=>p(o.listHistories,"listHistories").call(o,t),getXConnection:()=>p(o.getXConnection,"getXConnection").call(o),connectX:t=>p(o.connectX,"connectX").call(o,t),disconnectX:()=>p(o.disconnectX,"disconnectX").call(o),submitFeedback:t=>p(o.submitFeedback,"submitFeedback").call(o,t),setRevealYou:t=>p(o.setRevealYou,"setRevealYou").call(o,{revealYou:t}),requestRecipientChangeSignature:t=>p(o.requestRecipientChangeSignature,"requestRecipientChangeSignature").call(o,t),requestRecipientResetSignature:t=>p(o.requestRecipientResetSignature,"requestRecipientResetSignature").call(o,t),batchClaim:t=>d.execute(t),requestBatchClaimSignature:t=>p(o.requestBatchClaimSignature,"requestBatchClaimSignature").call(o,t)}}export{g as a,S as b,E as c,B as d,M as e,y as f,f as g,P as h,w as i,Y as j};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as o}from"./chunk-5DT3H2VX.js";var Z=BigInt(500),Q=BigInt(1e4),y={dev:{apiBaseUrl:"https://dev-one-pop-api.onechain.nexus/api",contracts:{onePop:"0xfBadB337e634757ca8F8EEB7682acF06bA297d85",permitErc20:"0xFaDAB54449262178aE0562F5D8416bBeF4659714",nft:"0x11ce973082c7B90aB2Fc789949CC04e1F85397ff",nftMinter:"0xfBadB337e634757ca8F8EEB7682acF06bA297d85",validator:"0xF30d8e0544f0b92A6987522f4F696D3915B579b4",feeRecipient:"0xF30d8e0544f0b92A6987522f4F696D3915B579b4"}},stage:{apiBaseUrl:"https://stg-one-pop-api.onechain.nexus/api",contracts:{onePop:"0x4c4599fFa1D83bB9689d9a0C557fF2EB35443949",permitErc20:"0xFaDAB54449262178aE0562F5D8416bBeF4659714",nft:"0x0535fce7113cf48f21C32472bBA929F8F31ab05c",nftMinter:"0x4c4599fFa1D83bB9689d9a0C557fF2EB35443949",validator:"0xa953af3742345dFC2BdcA30cBa79D8313b0a3B61",feeRecipient:"0xa953af3742345dFC2BdcA30cBa79D8313b0a3B61"}},production:{apiBaseUrl:"https://one-pop-api.onechain.nexus/api"}},E={createWallet:"/wallets",dropMetadata:"/drops/metadata",retrievePrivateKey:"/wallets/private-key",drops:"/drops",rejectDrops:"/drops/reject",envelopes:"/envelopes",leaderboards:"/leaderboards",leaderboardMe:"/leaderboards/me",histories:"/histories",xConnections:"/x-connections",batchClaimSignature:"/batch-claim-signature",feedbacks:"/feedbacks",revealYou:"/reveal-you",recipientChangeSignature:"/recipient-change-signature",recipientResetSignature:"/recipient-reset-signature",eventsSubscribe:"/events/subscribe"},F="https://dev-cross-auth.crosstoken.io";function h(r){try{return import.meta.env?.[r]}catch{return}}function u(r){if(!(typeof process>"u"||!process.env))switch(r){case"NEXT_PUBLIC_ONE_POP_ENVIRONMENT":return process.env.NEXT_PUBLIC_ONE_POP_ENVIRONMENT;case"ONE_POP_ENVIRONMENT":return process.env.ONE_POP_ENVIRONMENT;case"NEXT_PUBLIC_ONE_POP_API_BASE_URL":return process.env.NEXT_PUBLIC_ONE_POP_API_BASE_URL;case"NEXT_PUBLIC_CROSS_AUTH_URL":return process.env.NEXT_PUBLIC_CROSS_AUTH_URL;default:return}}function b(){let r=h("VITE_ONE_POP_ENVIRONMENT")??u("NEXT_PUBLIC_ONE_POP_ENVIRONMENT")??u("ONE_POP_ENVIRONMENT");return H(r)}function H(r){switch(r?.toLowerCase()){case"dev":case"development":return"dev";case"stg":case"stage":case"staging":return"stage";case void 0:case"production":case"prod":return"production";default:throw new Error(`[pop] Invalid environment: ${r}`)}}function X(){return y[b()]}function ee(){return $(b())}function $(r){let e=y[r].contracts;if(!e)throw new Error(`[pop] Contract addresses are not configured for ${r}`);return e}function R(){let e=h("VITE_ONE_POP_API_BASE_URL")??u("NEXT_PUBLIC_ONE_POP_API_BASE_URL")??X().apiBaseUrl;return w(e),e}function A(){let e=(h("VITE_CROSS_AUTH_URL")??u("NEXT_PUBLIC_CROSS_AUTH_URL")??F).replace(/\/+$/,"");return w(e),e}function w(r){let e;try{e=new URL(r)}catch{throw new Error(`[pop] Invalid base URL: ${r}`)}if(e.protocol==="https:")return;let t=e.hostname==="localhost"||e.hostname==="127.0.0.1"||e.hostname.endsWith(".local");if(!(e.protocol==="http:"&&t))throw new Error(`[pop] base URL must be https (or http://localhost for dev). Got: ${r}`)}var q={INVALID_PARAM:"INVALID_PARAM",RATE_LIMITED:"RATE_LIMITED",INVALID_OAUTH_TOKEN:"INVALID_OAUTH_TOKEN",UNAUTHORIZED:"UNAUTHORIZED",WALLET_NOT_FOUND:"WALLET_NOT_FOUND",SEND_BLOCKED:"SEND_BLOCKED",ENVELOPE_NOT_FOUND:"ENVELOPE_NOT_FOUND",PENDING_LIMIT_EXCEEDED:"PENDING_LIMIT_EXCEEDED",DROP_NOT_FOUND:"DROP_NOT_FOUND",IDENTIFIER_NOT_MAPPED:"IDENTIFIER_NOT_MAPPED",X_CONNECTION_NOT_FOUND:"X_CONNECTION_NOT_FOUND",X_ALREADY_CONNECTED:"X_ALREADY_CONNECTED"},l=140,I=class{constructor(e={}){this.baseUrl=(e.baseUrl??R()).replace(/\/+$/,"");let t=e.fetchImpl??globalThis.fetch;if(!t)throw new Error("fetch is unavailable; provide options.fetchImpl");this.fetchImpl=t,this.getJwt=e.getJwt,this.paths={...E,...e.paths}}async createClaimWallet(e){let t=await this.request(this.paths.createWallet,{method:"POST",auth:!0,payload:{identifier:e.recipient.handle,oauth_type:e.recipient.provider,sender_address:e.sender}});if(!t?.address)throw new o("API_ERROR","createClaimWallet: missing address in response",{body:t});if(!t.identifier)throw new o("API_ERROR","createClaimWallet: missing identifier in response",{body:t});return{claimAddress:t.address,id:t.identifier,isMapped:t.is_mapped===!0}}async recordDropMetadata(e){if(e.message&&[...e.message].length>l)throw new o("INVALID_PARAM",`message must be <= ${l} runes`);await this.request(this.paths.dropMetadata,{method:"POST",auth:!0,query:{tx_hash:e.txHash},payload:{...e.message?{message:e.message}:{},...e.envelopeId?{envelope_id:e.envelopeId}:{}}})}async retrieveClaimKey(e){let t=await this.request(this.paths.retrievePrivateKey,{method:"POST",payload:{oauth_token:e.oauth.accessToken,oauth_type:e.oauth.provider,sender_address:e.senderAddress,address:e.claimAddress}});if(t?.private_key&&t.address){if(t.address.toLowerCase()!==e.claimAddress.toLowerCase())throw new o("API_ERROR","retrieveClaimKey: returned a different address");return{isMapped:!1,claimKey:t.private_key,claimAddress:t.address}}if(t?.is_mapped===!0)return{isMapped:!0};throw new o("API_ERROR","retrieveClaimKey: missing key/address in response",{body:t})}async listDrops(e){if(!e?.token)throw new o("INVALID_PARAM","listDrops requires a token address");let t=await this.request(this.paths.drops,{method:"GET",auth:!0,query:{token:e.token,drop_key:e.dropKey}});return{items:(t?.items??[]).map(j),count:t?.count??0,totalAmount:d(t?.total_amount,"drops.total_amount"),hasClaimedBefore:t?.has_claimed_before===!0,mappedRecipient:c(t?.mapped_recipient),pendingChangeTo:c(t?.pending_change_to)}}async rejectDrops(e){if(!Array.isArray(e.dropIds)||e.dropIds.length===0||e.dropIds.length>100||e.dropIds.some(n=>!Number.isSafeInteger(n)||n<=0))throw new o("INVALID_PARAM","dropIds must contain 1-100 positive integers");return(await this.request(this.paths.rejectDrops,{method:"POST",auth:!0,payload:{drop_ids:e.dropIds}}))?.count??0}async listEnvelopes(e={}){return((await this.request(this.paths.envelopes,{method:"GET",query:{locale:e.locale}}))?.items??[]).map(n=>({id:s(n.id),name:s(n.name),imageUrl:s(n.image_url),badge:s(n.badge),sortOrder:Number(n.sort_order??0)}))}async getLeaderboard(e){if(!e.token)throw new o("INVALID_PARAM","getLeaderboard requires a token address");let t=await this.request(this.paths.leaderboards,{method:"GET",query:{token:e.token,page:e.page,page_size:e.pageSize,identifier:e.identifier}});return{items:(t?.items??[]).map(S),page:t?.page??1,pageSize:t?.page_size??0,total:t?.total??0}}async getMyLeaderboardEntry(e){let t=await this.request(this.paths.leaderboardMe,{method:"GET",auth:!0,query:{token:e.token}});return{...S(t??{}),rank:N(t?.rank)}}async listHistories(e){if(!e?.type)throw new o("INVALID_PARAM","listHistories requires type");let t=await this.request(this.paths.histories,{method:"GET",auth:!0,query:{type:e.type,token:e.token,status:e.status,rejected:e.rejected===void 0?void 0:String(e.rejected),page:e.page,page_size:e.pageSize}});return{items:(t?.items??[]).map(n=>({id:Number(n.id??0),type:s(n.type),status:s(n.status),token:s(n.token),amount:d(n.amount,"history.amount"),claimAddress:s(n.claim_address),depositTxHash:s(n.deposit_tx_hash),depositedAt:s(n.deposited_at),resolvedTxHash:c(n.resolved_tx_hash),resolvedAt:c(n.resolved_at),message:s(n.message),feedback:c(n.feedback),envelopeId:s(n.envelope_id),rejected:n.rejected===!0,sender:k(n.sender),receiver:z(n.receiver)})),page:t?.page??1,pageSize:t?.page_size??0,total:t?.total??0}}async getXConnection(){let e=await this.request(this.paths.xConnections,{method:"GET",auth:!0,notFoundAsNull:!0});return e?O(e):null}async connectX(e){let t=await this.request(this.paths.xConnections,{method:"POST",auth:!0,payload:{oauth_token:e.oauth.accessToken}});return O(t??{})}async disconnectX(){await this.request(this.paths.xConnections,{method:"DELETE",auth:!0,notFoundAsNull:!0})}async submitFeedback(e){if(!Number.isSafeInteger(e.dropId)||e.dropId<=0)throw new o("INVALID_PARAM","dropId must be a positive integer");if(!e.message.trim()||[...e.message.trim()].length>l)throw new o("INVALID_PARAM",`message must be 1-${l} runes`);let t=await this.request(this.paths.feedbacks,{method:"PUT",auth:!0,query:{drop_id:e.dropId},payload:{message:e.message}});return s(t?.message)}async setRevealYou(e){return(await this.request(this.paths.revealYou,{method:"PUT",auth:!0,payload:{reveal_you:e.revealYou}}))?.reveal_you===!0}async requestRecipientChangeSignature(e){let t=await this.request(this.paths.recipientChangeSignature,{method:"POST",auth:!0,payload:T(e)});return{...v(t,e),newRecipient:s(t?.new_recipient)}}async requestRecipientResetSignature(e){let t=await this.request(this.paths.recipientResetSignature,{method:"POST",payload:T(e)});return v(t,e)}async requestBatchClaimSignature(e){let t=await this.request(this.paths.batchClaimSignature,{method:"POST",auth:!0,payload:{id:e.id,oauth_token:e.oauth.accessToken,nonce:e.nonce.toString(),deadline:e.deadline.toString()}}),n=s(t?.signature);if(!n)throw new o("API_ERROR","requestBatchClaimSignature: missing signature",{body:t});return{id:s(t?.id)||e.id,recipient:s(t?.recipient),nonce:g(t?.nonce)?d(t?.nonce,"batchClaim.nonce"):e.nonce,deadline:g(t?.deadline)?d(t?.deadline,"batchClaim.deadline"):e.deadline,signature:n}}async request(e,t){let n={};if(t.payload&&(n["Content-Type"]="application/json"),t.auth){let a=await this.getJwt?.();if(!a)throw new o("UNAUTHORIZED",`${e} requires a SIWE JWT (options.getJwt)`);n.Authorization=`Bearer ${a}`}let i;try{i=await this.fetchImpl(`${this.baseUrl}${e}${V(t.query)}`,{method:t.method,headers:n,body:t.payload?JSON.stringify(t.payload):void 0})}catch(a){throw new o("API_ERROR",`Network error calling ${e}`,{cause:a instanceof Error?a.message:String(a)})}if(i.status===404&&t.notFoundAsNull)return null;if(!i.ok){let a=await i.json().catch(()=>{}),p=a?.code_name;throw new o((p?q[p]:void 0)??"API_ERROR",a?.message?`${e}: ${a.message}`:`${e} responded ${i.status}`,{status:i.status,code:a?.code,codeName:p})}return i.status===204?null:await i.json().catch(()=>null)}};function V(r){if(!r)return"";let e=new URLSearchParams;for(let[n,i]of Object.entries(r))i!==void 0&&i!==""&&e.set(n,String(i));let t=e.toString();return t?`?${t}`:""}function g(r){return r!=null&&r!==""}function s(r){return typeof r=="string"?r:""}function c(r){return typeof r=="string"&&r?r:null}function d(r,e){if(typeof r=="bigint")return r;if(typeof r=="number"){if(!Number.isSafeInteger(r))throw new o("API_ERROR",`${e} exceeds safe-integer precision as a JSON number`,{value:r});return BigInt(r)}let t=typeof r=="string"?r.trim():"";if(!t)return BigInt(0);try{return BigInt(t)}catch{throw new o("API_ERROR",`${e} is not a valid decimal string`,{value:r})}}function j(r){let e=r??{},t=e.sender??{};return{id:Number(e.id??0),dropKey:s(e.drop_key),claimAddress:s(e.claim_address),token:s(e.token),amount:d(e.amount,"drop.amount"),message:s(e.message),envelopeId:s(e.envelope_id),depositedAt:s(e.deposited_at),rejected:e.rejected===!0,sender:{address:s(t.address),handle:s(t.handle),displayName:s(t.display_name),profileImageUrl:s(t.profile_image_url)}}}function O(r){return{xUserId:s(r.x_user_id),handle:s(r.handle),displayName:s(r.display_name),profileImageUrl:s(r.profile_image_url),walletAddress:s(r.wallet_address),revealYou:r.reveal_you===!0,onchainMapped:r.onchain_mapped===!0,mappedRecipient:c(r.mapped_recipient)}}function S(r){return{identifier:s(r.identifier),balance:d(r.balance,"leaderboard.balance"),lastDepositAmount:d(r.last_deposit_amount,"leaderboard.last_deposit_amount"),rank:Number(r.rank??0),previousRank:N(r.previous_rank),profileImageUrl:s(r.profile_image_url)}}function N(r){return typeof r=="number"?r:null}function k(r){let e=r??{};return{address:s(e.address),handle:s(e.handle),displayName:s(e.display_name),profileImageUrl:s(e.profile_image_url)}}function z(r){return{...k(r),address:c(r?.address)}}function T(r){return{id:r.id,oauth_token:r.oauth.accessToken,nonce:r.nonce.toString(),deadline:r.deadline.toString()}}function v(r,e){let t=s(r?.signature);if(!t)throw new o("API_ERROR","signature response is missing signature");return{id:s(r?.id)||e.id,nonce:g(r?.nonce)?d(r?.nonce,"signature.nonce"):e.nonce,deadline:g(r?.deadline)?d(r?.deadline,"signature.deadline"):e.deadline,signature:t}}var U=class{constructor(e={}){this.baseUrl=(e.baseUrl??A()).replace(/\/+$/,""),this.domain=e.domain??globalThis.location?.origin??"";let t=e.fetchImpl??globalThis.fetch;if(!t)throw new Error("fetch is unavailable; provide options.fetchImpl");this.fetchImpl=t}unsignedHash(e,t){return this.post("/login/unsigned-hash",{chain_id:e,address:t,domain:this.domain})}siweToken(e,t){return this.post("/login/token",{address:e,signature:t,domain:this.domain})}async post(e,t){let n;try{n=await this.fetchImpl(`${this.baseUrl}/cross-auth${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}catch(a){throw new o("API_ERROR",`cross-auth network error calling ${e}`,{cause:a instanceof Error?a.message:String(a)})}let i=await n.json().catch(()=>({}));if(!n.ok||i.data==null)throw new o("API_ERROR",`cross-auth ${e} failed`,{code:i.code,message:i.message});return i.data}};async function C(){let r=f(x(32)),e=await K().digest("SHA-256",W(r)),t=f(new Uint8Array(e));return{verifier:r,challenge:t,method:"S256"}}function D(){return f(x(16))}function x(r){let e=globalThis.crypto;if(!e?.getRandomValues)throw new Error("crypto.getRandomValues unavailable");let t=new Uint8Array(r);return e.getRandomValues(t),t}function K(){let r=globalThis.crypto?.subtle;if(!r)throw new Error("crypto.subtle unavailable (needs https/secure context)");return r}function W(r){return new TextEncoder().encode(r)}function f(r){let e="";for(let n of r)e+=String.fromCharCode(n);let t=globalThis.btoa?.(e);if(t===void 0)throw new Error("btoa unavailable");return t.replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}var L=class{constructor(e={}){this.baseUrl=(e.baseUrl??"").replace(/\/+$/,""),this.tokenPath=e.tokenPath??"/api/x/token",this.mePath=e.mePath??"/api/x/me";let t=e.fetchImpl??globalThis.fetch;if(!t)throw new Error("fetch is unavailable; provide options.fetchImpl");this.fetchImpl=t}async exchangeCode(e){let n=await(await this.call(this.tokenPath,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clientId:e.clientId,redirectUri:e.redirectUri,code:e.code,verifier:e.codeVerifier})})).json().catch(()=>({}));if(!n.access_token)throw new o("API_ERROR","X token exchange: missing access_token",{body:n});return{accessToken:n.access_token,scope:n.scope,expiresIn:n.expires_in,refreshToken:n.refresh_token}}async getHandle(e){let n=await(await this.call(this.mePath,{method:"GET",headers:{Authorization:`Bearer ${e}`}})).json().catch(()=>({})),i=n.data?.username??n.username;if(!i)throw new o("API_ERROR","X /me: missing username",{body:n});return{handle:i}}async call(e,t){let n;try{n=await this.fetchImpl(`${this.baseUrl}${e}`,t)}catch(i){throw new o("API_ERROR",`Network error calling ${e}`,{cause:i instanceof Error?i.message:String(i)})}if(!n.ok)throw new o("API_ERROR",`${e} responded ${n.status}`,{status:n.status});return n}};var m="pop.xauth.verifier",_="pop.xauth.state",G="https://x.com/i/oauth2/authorize",J="tweet.read users.read offline.access",B=class{constructor(e){this.opts={clientId:e.clientId,redirectUri:e.redirectUri,scope:e.scope??J,authorizeUrl:e.authorizeUrl??G,port:e.port,storage:e.storage??Y()}}async start(){let e=await C(),t=D();this.opts.storage.set(m,e.verifier),this.opts.storage.set(_,t);let n=new URLSearchParams({response_type:"code",client_id:this.opts.clientId,redirect_uri:this.opts.redirectUri,scope:this.opts.scope,state:t,code_challenge:e.challenge,code_challenge_method:"S256"});return{authorizeUrl:`${this.opts.authorizeUrl}?${n.toString()}`,state:t}}async complete(e){let t=new URL(e),n=t.searchParams.get("code"),i=t.searchParams.get("state");if(!n)throw new o("API_ERROR","X callback: missing authorization code",{error:t.searchParams.get("error")});let a=this.opts.storage.get(_);if(!i||!a||i!==a)throw new o("API_ERROR","X callback: state mismatch (possible CSRF)");let p=this.opts.storage.get(m);if(!p)throw new o("API_ERROR","X callback: missing PKCE verifier (expired session?)");let P=await this.opts.port.exchangeCode({clientId:this.opts.clientId,redirectUri:this.opts.redirectUri,code:n,codeVerifier:p}),{handle:M}=await this.opts.port.getHandle(P.accessToken);return this.opts.storage.remove(m),this.opts.storage.remove(_),{oauth:{provider:"x",accessToken:P.accessToken},handle:M}}};function Y(){let r=globalThis.sessionStorage;if(!r)throw new Error("sessionStorage unavailable; provide options.storage");return{get:e=>r.getItem(e),set:(e,t)=>r.setItem(e,t),remove:e=>r.removeItem(e)}}export{Z as a,Q as b,y as c,E as d,b as e,H as f,X as g,ee as h,R as i,A as j,I as k,U as l,C as m,D as n,L as o,B as p};
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { S as Secret, a as SecretHash, H as Hex, A as Address, I as Id, D as DepositParams, b as DepositResult, O as OAuthProof, W as WithdrawParams, c as WithdrawResult, R as RefundParams, d as RefundResult, e as DropInbox, E as Envelope, L as LeaderboardPage, M as MyLeaderboardEntry, f as HistoryType, g as HistoryStatus, h as HistoryPage, X as XConnection, i as RecipientChangeSignature, j as RecipientSignature, B as BatchClaimParams, k as BatchClaimResult, l as BatchClaimSignature, m as SafeDropApiPort } from './SafeDropApiPort-BLewfSaK.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 순수 계산이 아니라 외부 구현(해시 라이브러리/CSPRNG)이 필요한 암호 연산.
|
|
5
|
+
* core는 keccak/난수 구현을 갖지 않으므로 Port로 분리한다.
|
|
6
|
+
* 어댑터가 viem `keccak256`/`crypto.getRandomValues` 등으로 구현.
|
|
7
|
+
*/
|
|
8
|
+
interface CryptoPort {
|
|
9
|
+
/** utf8(secret) → keccak256 → 0x-prefixed hex. 컨트랙트 secretHash와 일치해야 함. */
|
|
10
|
+
keccak256(input: Secret): SecretHash;
|
|
11
|
+
/** CSPRNG 기반 고엔트로피 secret 문구 생성. */
|
|
12
|
+
randomSecret(): Secret;
|
|
13
|
+
/**
|
|
14
|
+
* digest + 서명 → 서명자 주소. 백엔드 validator 서명을 **가스 쓰기 전에** 검증하는
|
|
15
|
+
* 용도(최종 관문은 여전히 컨트랙트다). optional — 미구현 어댑터에서는 사전 검증만
|
|
16
|
+
* 생략되고 플로우는 그대로 동작한다.
|
|
17
|
+
*/
|
|
18
|
+
recoverAddress?(params: {
|
|
19
|
+
digest: Hex;
|
|
20
|
+
signature: Hex;
|
|
21
|
+
}): Promise<Address>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Current ONEpop drop record, keyed by bytes32 rather than claim wallet. */
|
|
25
|
+
interface OnePopDrop {
|
|
26
|
+
dropKey: Hex;
|
|
27
|
+
sponsor: Address;
|
|
28
|
+
amount: bigint;
|
|
29
|
+
claimAddress: Address;
|
|
30
|
+
recipient: Address;
|
|
31
|
+
secretHash: SecretHash;
|
|
32
|
+
id: Id;
|
|
33
|
+
}
|
|
34
|
+
interface DropState extends OnePopDrop {
|
|
35
|
+
/** ONEpop escrow is single-token; token() is contract-wide. */
|
|
36
|
+
token: Address;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* SafeDrop 컨트랙트 상호작용. 어댑터는 자신의 컨트랙트 주소를 알고 있으므로
|
|
40
|
+
* approve의 spender 등은 받지 않는다. 쓰기는 receipt 확인 후 tx hash 반환.
|
|
41
|
+
* withdraw는 임시 지갑이 직접 전송(가스 대납) — claimKey 필요.
|
|
42
|
+
* ABI: src/infrastructure/safedrop_abi.json.
|
|
43
|
+
*/
|
|
44
|
+
interface SafeDropChainPort {
|
|
45
|
+
getDropByKey(dropKey: Hex): Promise<OnePopDrop | null>;
|
|
46
|
+
getDropKeyByClaimAddress(claimAddress: Address, sponsor: Address): Promise<Hex | null>;
|
|
47
|
+
getClaimedRecipient(params: {
|
|
48
|
+
id: Id;
|
|
49
|
+
}): Promise<Address>;
|
|
50
|
+
getPendingDropsById(params: {
|
|
51
|
+
id: Id;
|
|
52
|
+
}): Promise<readonly OnePopDrop[]>;
|
|
53
|
+
getPendingDropsByRecipient(params: {
|
|
54
|
+
recipient: Address;
|
|
55
|
+
}): Promise<readonly OnePopDrop[]>;
|
|
56
|
+
getPendingDropsBySponsor(params: {
|
|
57
|
+
sponsor: Address;
|
|
58
|
+
}): Promise<readonly OnePopDrop[]>;
|
|
59
|
+
/** activeDropOf(claimAddr) → drops(dropKey). 없으면 null. */
|
|
60
|
+
getDrop(claimAddress: Address, sponsor: Address): Promise<DropState | null>;
|
|
61
|
+
/** claimDigest(recipient, id, dropKey) — 서명 대상 bytes32. */
|
|
62
|
+
getClaimDigest(params: {
|
|
63
|
+
recipient: Address;
|
|
64
|
+
id: Id;
|
|
65
|
+
dropKey: Hex;
|
|
66
|
+
}): Promise<Hex>;
|
|
67
|
+
/**
|
|
68
|
+
* EIP-2612 permit 예치 — 현재 ONEpop deposit의 유일한 형태다.
|
|
69
|
+
* 서명(typed data)·deadline·v/r/s는 전부 어댑터 내부 관심사다.
|
|
70
|
+
*/
|
|
71
|
+
depositWithPermit(params: {
|
|
72
|
+
claimAddress: Address;
|
|
73
|
+
token: Address;
|
|
74
|
+
amount: bigint;
|
|
75
|
+
id: Id;
|
|
76
|
+
secretHash: SecretHash;
|
|
77
|
+
onSubmitted?: (txHash: Hex) => void | Promise<void>;
|
|
78
|
+
}): Promise<{
|
|
79
|
+
txHash: Hex;
|
|
80
|
+
dropKey: Hex;
|
|
81
|
+
}>;
|
|
82
|
+
depositMapped(params: {
|
|
83
|
+
token: Address;
|
|
84
|
+
amount: bigint;
|
|
85
|
+
id: Id;
|
|
86
|
+
onSubmitted?: (txHash: Hex) => void | Promise<void>;
|
|
87
|
+
}): Promise<{
|
|
88
|
+
txHash: Hex;
|
|
89
|
+
dropKey: Hex;
|
|
90
|
+
}>;
|
|
91
|
+
withdrawUnmapped(params: {
|
|
92
|
+
claimKey: Hex;
|
|
93
|
+
recipient: Address;
|
|
94
|
+
id: Id;
|
|
95
|
+
dropKey: Hex;
|
|
96
|
+
secret: Secret;
|
|
97
|
+
signature?: Hex;
|
|
98
|
+
onSubmitted?: (txHash: Hex) => void | Promise<void>;
|
|
99
|
+
}): Promise<Hex>;
|
|
100
|
+
withdrawMapped(params: {
|
|
101
|
+
dropKey: Hex;
|
|
102
|
+
onSubmitted?: (txHash: Hex) => void | Promise<void>;
|
|
103
|
+
}): Promise<Hex>;
|
|
104
|
+
batchWithdrawMapped(params: {
|
|
105
|
+
count: number;
|
|
106
|
+
}): Promise<Hex>;
|
|
107
|
+
batchWithdrawMappedByKeys(params: {
|
|
108
|
+
dropKeys: readonly Hex[];
|
|
109
|
+
}): Promise<Hex>;
|
|
110
|
+
withdrawUnmappedBatchByKeys(params: {
|
|
111
|
+
claimKey: Hex;
|
|
112
|
+
recipient: Address;
|
|
113
|
+
id: Id;
|
|
114
|
+
anchorDropKey: Hex;
|
|
115
|
+
secret: Secret;
|
|
116
|
+
nonce: bigint;
|
|
117
|
+
deadline: bigint;
|
|
118
|
+
dropKeys: readonly Hex[];
|
|
119
|
+
validatorSignature: Hex;
|
|
120
|
+
}): Promise<Hex>;
|
|
121
|
+
refundByKey(params: {
|
|
122
|
+
dropKey: Hex;
|
|
123
|
+
}): Promise<Hex>;
|
|
124
|
+
getChangeNonce(params: {
|
|
125
|
+
id: Id;
|
|
126
|
+
}): Promise<bigint>;
|
|
127
|
+
getPendingRecipientChange(params: {
|
|
128
|
+
id: Id;
|
|
129
|
+
}): Promise<Address>;
|
|
130
|
+
requestRecipientChange(params: {
|
|
131
|
+
id: Id;
|
|
132
|
+
newRecipient: Address;
|
|
133
|
+
}): Promise<Hex>;
|
|
134
|
+
completeRecipientChange(params: {
|
|
135
|
+
id: Id;
|
|
136
|
+
nonce: bigint;
|
|
137
|
+
deadline: bigint;
|
|
138
|
+
signature: Hex;
|
|
139
|
+
}): Promise<Hex>;
|
|
140
|
+
cancelRecipientChange(params: {
|
|
141
|
+
id: Id;
|
|
142
|
+
}): Promise<Hex>;
|
|
143
|
+
resetRecipient(params: {
|
|
144
|
+
id: Id;
|
|
145
|
+
nonce: bigint;
|
|
146
|
+
deadline: bigint;
|
|
147
|
+
signature: Hex;
|
|
148
|
+
}): Promise<Hex>;
|
|
149
|
+
/** validatorNonceById(keccak256(utf8(id))). id 해싱은 어댑터 책임. */
|
|
150
|
+
getValidatorNonce?(params: {
|
|
151
|
+
id: Id;
|
|
152
|
+
}): Promise<bigint>;
|
|
153
|
+
/**
|
|
154
|
+
* validatorClaimDigest(recipient, id, nonce, deadline) — 온체인 EIP-712 다이제스트.
|
|
155
|
+
* 로컬 재조립 대신 이 값을 읽어 백엔드 서명을 검증한다.
|
|
156
|
+
*/
|
|
157
|
+
getValidatorClaimDigest?(params: {
|
|
158
|
+
recipient: Address;
|
|
159
|
+
id: Id;
|
|
160
|
+
nonce: bigint;
|
|
161
|
+
deadline: bigint;
|
|
162
|
+
}): Promise<Hex>;
|
|
163
|
+
/** validator() — 서명자여야 하는 주소. 백엔드 서명 검증의 기준값. */
|
|
164
|
+
getValidator?(): Promise<Address>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 임시 claim 키로 claimDigest(온체인에서 읽은 bytes32)에 raw ECDSA 서명을 만든다.
|
|
169
|
+
* 컨트랙트가 claimDigest를 계산해주므로 로컬 EIP-712 typed data 구성은 불필요 —
|
|
170
|
+
* digest를 그대로 서명한다. 서명은 브라우저 로컬, 백엔드 미관여.
|
|
171
|
+
*/
|
|
172
|
+
interface ClaimSignerPort {
|
|
173
|
+
signDigest(params: {
|
|
174
|
+
claimKey: Hex;
|
|
175
|
+
digest: Hex;
|
|
176
|
+
}): Promise<Hex>;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 프레임워크 무관 진입점. 포트 구현(어댑터)을 주입하면 usecase를 조립해 반환한다.
|
|
181
|
+
*
|
|
182
|
+
* const safeDrop = createSafeDrop(
|
|
183
|
+
* { claimBaseUrl },
|
|
184
|
+
* { api, chain, signer, crypto },
|
|
185
|
+
* );
|
|
186
|
+
* const result = await safeDrop.deposit({ ... });
|
|
187
|
+
* if (!result.isMapped) sendLink(result.withdrawLink);
|
|
188
|
+
*
|
|
189
|
+
* viem/HTTP 어댑터를 자동 조립하려면 `@nexus-cross/pop/adapters`의
|
|
190
|
+
* createSafeDropClient를 사용한다. (도메인/컨트랙트 주소는 chain 어댑터가 안다.)
|
|
191
|
+
*/
|
|
192
|
+
|
|
193
|
+
interface SafeDropConfig {
|
|
194
|
+
/** 수령 링크 base URL. 예: https://one-pop.example/claim */
|
|
195
|
+
claimBaseUrl: string;
|
|
196
|
+
}
|
|
197
|
+
interface SafeDropDeps {
|
|
198
|
+
api: SafeDropApiPort;
|
|
199
|
+
chain: SafeDropChainPort;
|
|
200
|
+
signer: ClaimSignerPort;
|
|
201
|
+
crypto: CryptoPort;
|
|
202
|
+
}
|
|
203
|
+
interface SafeDrop {
|
|
204
|
+
readonly config: SafeDropConfig;
|
|
205
|
+
deposit(params: DepositParams): Promise<DepositResult>;
|
|
206
|
+
/** X OAuth 검증 후 (sender_address + 토큰 소유자)로 임시 claim 키/주소를 받는다 (point of return). */
|
|
207
|
+
retrieveClaimKey(params: {
|
|
208
|
+
claimAddress: Address;
|
|
209
|
+
senderAddress: Address;
|
|
210
|
+
oauth: OAuthProof;
|
|
211
|
+
}): Promise<{
|
|
212
|
+
isMapped: true;
|
|
213
|
+
} | {
|
|
214
|
+
isMapped: false;
|
|
215
|
+
claimKey: Hex;
|
|
216
|
+
claimAddress: Address;
|
|
217
|
+
}>;
|
|
218
|
+
withdraw(params: WithdrawParams): Promise<WithdrawResult>;
|
|
219
|
+
refund(params: RefundParams): Promise<RefundResult>;
|
|
220
|
+
/** activeDropOf(claimAddr)로 조회한 현재 온체인 드롭. */
|
|
221
|
+
getDrop(claimAddress: Address, sponsor: Address): Promise<DropState | null>;
|
|
222
|
+
getDropByKey(dropKey: Hex): Promise<OnePopDrop | null>;
|
|
223
|
+
getDropKeyByClaimAddress(claimAddress: Address, sponsor: Address): Promise<Hex | null>;
|
|
224
|
+
getClaimedRecipient(id: Id): Promise<Address>;
|
|
225
|
+
getPendingDropsById(id: Id): Promise<readonly OnePopDrop[]>;
|
|
226
|
+
getPendingDropsByRecipient(recipient: Address): Promise<readonly OnePopDrop[]>;
|
|
227
|
+
getPendingDropsBySponsor(sponsor: Address): Promise<readonly OnePopDrop[]>;
|
|
228
|
+
withdrawUnmapped(params: Parameters<SafeDropChainPort['withdrawUnmapped']>[0]): Promise<Hex>;
|
|
229
|
+
withdrawMapped(params: Parameters<SafeDropChainPort['withdrawMapped']>[0]): Promise<Hex>;
|
|
230
|
+
batchWithdrawMapped(count: number): Promise<Hex>;
|
|
231
|
+
batchWithdrawMappedByKeys(dropKeys: readonly Hex[]): Promise<Hex>;
|
|
232
|
+
refundByKey(dropKey: Hex): Promise<Hex>;
|
|
233
|
+
getChangeNonce(id: Id): Promise<bigint>;
|
|
234
|
+
getPendingRecipientChange(id: Id): Promise<Address>;
|
|
235
|
+
requestRecipientChange(id: Id, newRecipient: Address): Promise<Hex>;
|
|
236
|
+
completeRecipientChange(params: Parameters<SafeDropChainPort['completeRecipientChange']>[0]): Promise<Hex>;
|
|
237
|
+
cancelRecipientChange(id: Id): Promise<Hex>;
|
|
238
|
+
resetRecipient(params: Parameters<SafeDropChainPort['resetRecipient']>[0]): Promise<Hex>;
|
|
239
|
+
/** 내게 온 수령 대기 목록. Bearer JWT + 활성 X 연결 필요. */
|
|
240
|
+
listDrops(params: {
|
|
241
|
+
token: Address;
|
|
242
|
+
dropKey?: Hex;
|
|
243
|
+
}): Promise<DropInbox>;
|
|
244
|
+
/** 선택한 pending 드롭을 인박스에서 숨긴다. */
|
|
245
|
+
rejectDrops(dropIds: readonly number[]): Promise<number>;
|
|
246
|
+
/** 카드 디자인 목록 (공개). deposit의 `envelopeId`에 쓴다. */
|
|
247
|
+
listEnvelopes(params?: {
|
|
248
|
+
locale?: string;
|
|
249
|
+
}): Promise<readonly Envelope[]>;
|
|
250
|
+
/** 토큰별 pending 잔액 상위 (공개). */
|
|
251
|
+
getLeaderboard(params: {
|
|
252
|
+
token: Address;
|
|
253
|
+
page?: number;
|
|
254
|
+
pageSize?: number;
|
|
255
|
+
identifier?: string;
|
|
256
|
+
}): Promise<LeaderboardPage>;
|
|
257
|
+
getMyLeaderboardEntry(params: {
|
|
258
|
+
token: Address;
|
|
259
|
+
}): Promise<MyLeaderboardEntry>;
|
|
260
|
+
/** sent/received 드롭 히스토리. Bearer JWT 필요. */
|
|
261
|
+
listHistories(params: {
|
|
262
|
+
type: HistoryType;
|
|
263
|
+
token?: Address;
|
|
264
|
+
status?: HistoryStatus;
|
|
265
|
+
rejected?: boolean;
|
|
266
|
+
page?: number;
|
|
267
|
+
pageSize?: number;
|
|
268
|
+
}): Promise<HistoryPage>;
|
|
269
|
+
/** 활성 X 연결. 없으면 null. */
|
|
270
|
+
getXConnection(): Promise<XConnection | null>;
|
|
271
|
+
/** X 계정을 SIWE 지갑에 연결. `listDrops`의 선행 조건. */
|
|
272
|
+
connectX(params: {
|
|
273
|
+
oauth: OAuthProof;
|
|
274
|
+
}): Promise<XConnection>;
|
|
275
|
+
/** X 연결 해제 (idempotent). */
|
|
276
|
+
disconnectX(): Promise<void>;
|
|
277
|
+
submitFeedback(params: {
|
|
278
|
+
dropId: number;
|
|
279
|
+
message: string;
|
|
280
|
+
}): Promise<string>;
|
|
281
|
+
setRevealYou(revealYou: boolean): Promise<boolean>;
|
|
282
|
+
requestRecipientChangeSignature(params: {
|
|
283
|
+
id: Id;
|
|
284
|
+
oauth: OAuthProof;
|
|
285
|
+
nonce: bigint;
|
|
286
|
+
deadline: bigint;
|
|
287
|
+
}): Promise<RecipientChangeSignature>;
|
|
288
|
+
requestRecipientResetSignature(params: {
|
|
289
|
+
id: Id;
|
|
290
|
+
oauth: OAuthProof;
|
|
291
|
+
nonce: bigint;
|
|
292
|
+
deadline: bigint;
|
|
293
|
+
}): Promise<RecipientSignature>;
|
|
294
|
+
/**
|
|
295
|
+
* anchor drop의 secret/claim key와 validator 서명을 함께 사용해 현재 pending key를
|
|
296
|
+
* 한 번에 수령한다.
|
|
297
|
+
*/
|
|
298
|
+
batchClaim(params: BatchClaimParams): Promise<BatchClaimResult>;
|
|
299
|
+
/**
|
|
300
|
+
* 서명만 따로 받는 저수준 경로(직접 컨트랙트를 호출할 때). 대부분은 `batchClaim`을 쓴다.
|
|
301
|
+
* nonce는 `validatorNonceById(keccak256(utf8(id)))`에서 읽은 값이어야 한다.
|
|
302
|
+
*/
|
|
303
|
+
requestBatchClaimSignature(params: {
|
|
304
|
+
id: Id;
|
|
305
|
+
oauth: OAuthProof;
|
|
306
|
+
nonce: bigint;
|
|
307
|
+
deadline: bigint;
|
|
308
|
+
}): Promise<BatchClaimSignature>;
|
|
309
|
+
}
|
|
310
|
+
declare function createSafeDrop(config: SafeDropConfig, deps: SafeDropDeps): SafeDrop;
|
|
311
|
+
|
|
312
|
+
export { type CryptoPort as C, type DropState as D, type OnePopDrop as O, type SafeDrop as S, type SafeDropChainPort as a, type ClaimSignerPort as b, type SafeDropConfig as c, type SafeDropDeps as d, createSafeDrop as e };
|