@privy-io/cross-app-connect
Version:
Privy cross app wallet connectors for wagmi and RainbowKit
2 lines • 11.2 kB
JavaScript
import{ProviderRpcError as e,createPublicClient as t,http as n}from"viem";import{trigger as r}from"@privy-io/popup";import{secp256k1 as i}from"@noble/curves/secp256k1";import{base64 as a}from"@scure/base";import{Buffer as o}from"buffer";import{unzlibSync as s,zlibSync as c}from"fflate";import{encoding as l}from"@privy-io/encoding";async function u({providerAppId:e,apiUrl:t}){let{custom_connect_url:n,custom_transact_url:r,custom_api_url:i,icon_url:a,name:o}=await(await fetch(`${t}/api/v1/apps/${e}/cross-app/details`,{method:`GET`,headers:{"Content-Type":`application/json`}})).json();return{url:i,customConnectUrl:n,customTransactUrl:r,name:o,iconUrl:a}}const d=120*1e3;function f(){let e=i.utils.randomPrivateKey(),t=i.getPublicKey(e);return{privateKey:a.encode(e),publicKey:a.encode(t)}}function p({privateKey:e,publicKey:t}){let n=i.getSharedSecret(a.decode(e),a.decode(t)).slice(1);return a.encode(n)}async function m(e,t){let n=JSON.stringify(e),r=c(l.utf8.toBytes(n)),i=l.base64.toBytes(t),a=await crypto.subtle.importKey(`raw`,i,{name:`AES-GCM`},!0,[`encrypt`]),o=crypto.getRandomValues(new Uint8Array(12)),s=await crypto.subtle.encrypt({name:`AES-GCM`,iv:o},a,new Uint8Array(r));return{iv:l.base64.fromBytes(o),encryptedRequest:l.base64.fromBytes(new Uint8Array(s))}}async function h({encryptedResult:e,iv:t,sharedSecret:n}){let r=l.base64.toBytes(n),i=l.base64.toBytes(t),a=await crypto.subtle.importKey(`raw`,r,{name:`AES-GCM`},!0,[`decrypt`]),c=l.base64.toBytes(e),u=await crypto.subtle.decrypt({name:`AES-GCM`,iv:i},a,c),d=s(o.from(u));return l.utf8.fromBytes(d)}async function g({request:e,apiUrl:t,publicKey:n,sharedSecret:i,providerAppId:a,timeout:o=d}){let s=r();if(!s)throw Error(`Failed to initialize request`);let c=new URL(t),{encryptedRequest:l,iv:u}=await m(e,i);return c.searchParams.set(`requester_public_key`,n),c.searchParams.set(`encrypted_request`,l),c.searchParams.set(`requester_origin`,window.location.origin),c.searchParams.set(`iv`,u),c.searchParams.set(`provider_app_id`,a),c.searchParams.set(`signout_enabled`,`true`),c.searchParams.set(`v`,`1`),s.location=c.href,new Promise((e,t)=>{let n=setTimeout(()=>{c(),t(new _(`Request timeout`))},o),r=setInterval(()=>{s.closed&&(c(),t(new _(`User rejected request`)))},300),a=async n=>{n.data&&(n.data.type===`PRIVY_CROSS_APP_ACTION_RESPONSE`&&n.data.encryptedResult&&(c(),e(await h({encryptedResult:n.data.encryptedResult,iv:n.data.iv,sharedSecret:i}))),n.data.type===`PRIVY_CROSS_APP_ACTION_ERROR`&&n.data.error&&(c(),t(new _(n.data.error,{mwp:n.data.mwp,code:n.data?.errorCode}))))};window.addEventListener(`message`,a);let c=()=>{s.close(),clearInterval(r),clearTimeout(n),window.removeEventListener(`message`,a)}})}var _=class extends Error{action;code;constructor(e,t){super(e),t?.mwp?.action&&(this.action=t.mwp.action),t?.code&&(this.code=t.code)}};async function v({url:e,timeout:t=d}){let n=r({location:e.href});if(!n)throw Error(``);return new Promise((e,r)=>{let i=setTimeout(()=>{r(Error(`Authorization request timed out after ${t} ms.`)),a()},t);function a(){n?.close(),window.removeEventListener(`message`,c)}let o,s=setInterval(()=>{n?.closed&&!o&&(a(),clearInterval(s),clearTimeout(i),r(Error(`User rejected request`)))},300);function c(t){t.data&&(t.data.type===`PRIVY_CROSS_APP_CONNECT_RESPONSE`&&(e(t.data),n?.close()),t.data.type===`PRIVY_CROSS_APP_ACTION_ERROR`&&(clearTimeout(i),r(Error(t.data.error)),a()),t.data.type===`PRIVY_OAUTH_USE_BROADCAST_CHANNEL`&&(o=new BroadcastChannel(`popup-privy-oauth`),o.onmessage=c))}window.addEventListener(`message`,c)})}async function y({providerAppId:e,providerUrl:t,connectionOpts:n,defaultPopupTimeout:r}){let i=new URL(t),{privateKey:a,publicKey:o}=f();i.searchParams.set(`requester_public_key`,o),i.searchParams.set(`connect`,`true`),i.searchParams.set(`provider_app_id`,e),i.searchParams.set(`requester_origin`,window.location.origin),i.searchParams.set(`smart_wallet_mode`,n?.smartWalletMode?`true`:`false`);let{address:s,providerPublicKey:c,exp:l}=await v({url:i,timeout:r});return{address:s,sharedSecret:p({privateKey:a,publicKey:c}),publicKey:o,exp:l}}var b=class{_cache={};get(e){return this._cache[e]}put(e,t){t===void 0?this.del(e):this._cache[e]=t}del(e){delete this._cache[e]}getKeys(){return Object.keys(this._cache)}},x=class{get(e){let t=localStorage.getItem(e);return t===null?void 0:JSON.parse(t)}put(e,t){t===void 0?this.del(e):localStorage.setItem(e,JSON.stringify(t))}del(e){localStorage.removeItem(e)}getKeys(){return Object.entries(localStorage).map(([e])=>e)}};function S(){return typeof window<`u`&&window.localStorage?new x:new b}var C=S();const w=({providerAppId:e,chains:t,chainId:n,apiUrl:r,connectionOpts:i,defaultPopupTimeout:a,overrideConnectUrl:o,overrideTransactUrl:s})=>new T(e,t,n,r,i,a,o,s);var T=class{providerAppId;_apiUrl;chainId;_providerDetailsLoaded=!1;_providerConnectUrl;_providerTransactUrl;_connectionOpts;chains;_sharedSecret;_publicKey;_address;_defaultPopupTimeout;_overrideConnectUrl;_overrideTransactUrl;constructor(e,t,n,r,i,a,o,s){this.providerAppId=e,this.chains=t,this._apiUrl=r??`https://auth.privy.io`,this._connectionOpts=i,this._defaultPopupTimeout=a,this._overrideConnectUrl=o,this._overrideTransactUrl=s;let c=C.get(this.STORAGE_CONNECTION_KEY),l=c&&c.exp>new Date().getTime(),u=C.get(this.STORAGE_CHAIN_ID_KEY);this.chainId=n??u??t[0].id,l?(this._sharedSecret=c.sharedSecret,this._publicKey=c.publicKey,this._address=c.address):this.clearConnection(),typeof window<`u`&&this.loadProviderDetails()}get STORAGE_CONNECTION_KEY(){let{smartWalletMode:e}=this._connectionOpts??{};return`privy-caw:${this.providerAppId}:connection${e?`:smart-wallet`:``}`}get STORAGE_CHAIN_ID_KEY(){let{smartWalletMode:e}=this._connectionOpts??{};return`privy-caw:${this.providerAppId}:connection_chain_id${e?`:smart-wallet`:``}`}async loadProviderDetails(){if(!this._providerDetailsLoaded){let{url:e,customConnectUrl:t,customTransactUrl:n}=await u({providerAppId:this.providerAppId,apiUrl:this._apiUrl});this._providerConnectUrl=this._overrideConnectUrl||t||`${e}/cross-app/connect`,this._providerTransactUrl=this._overrideTransactUrl||n||`${e}/cross-app/transact`,this._providerDetailsLoaded=!0}}async getProviderConnectUrl(){return await this.loadProviderDetails(),this._providerConnectUrl}async getProviderTransactUrl(){return await this.loadProviderDetails(),this._providerTransactUrl}clearConnection(){this._sharedSecret=void 0,this._publicKey=void 0,this._address=void 0,C.del(this.STORAGE_CONNECTION_KEY),C.del(this.STORAGE_CHAIN_ID_KEY)}get chain(){return this.chains.find(({id:e})=>e===this.chainId)}get address(){return this._address}async requestConnection(){let{address:e,sharedSecret:t,publicKey:n,exp:r}=await y({providerAppId:this.providerAppId,providerUrl:await this.getProviderConnectUrl(),connectionOpts:this._connectionOpts,defaultPopupTimeout:this._defaultPopupTimeout});C.put(this.STORAGE_CONNECTION_KEY,{address:e,sharedSecret:t,publicKey:n,exp:r}),this._address=e,this._sharedSecret=t,this._publicKey=n}switchChain({id:e}){this.chainId=e,C.put(this.STORAGE_CHAIN_ID_KEY,this.chainId)}async sendRequest(e,t){if(!this._sharedSecret||!this._publicKey)throw Error(`Must call 'eth_requestAccounts' before ${e}`);try{return await g({request:{method:e,params:t,chainId:this.chainId},apiUrl:await this.getProviderTransactUrl(),publicKey:this._publicKey,providerAppId:this.providerAppId,sharedSecret:this._sharedSecret,timeout:this._defaultPopupTimeout})}catch(e){throw e instanceof _&&e.action===`clear`&&this.clearConnection(),e}}};const E=r=>{let i=w({providerAppId:r.providerAppId,chains:r.chains,chainId:r.chainId,apiUrl:r.apiUrl,connectionOpts:{smartWalletMode:r.smartWalletMode},defaultPopupTimeout:r.defaultPopupTimeout,overrideConnectUrl:r.overrideConnectUrl,overrideTransactUrl:r.overrideTransactUrl}),a=t({chain:i.chain,transport:r.transports?.[i.chain.id]??n()}),o={accountsChanged:[],connect:[],chainChanged:[],disconnect:[],message:[]},s=()=>{i.clearConnection(),o.accountsChanged?.forEach(e=>e([]))};return{on:(e,t)=>{o[e].push(t)},removeListener:(e,t)=>{let n=o[e].indexOf(t);n>-1&&o[e].splice(n)},request:(async c=>{r.smartWalletMode&&(c.method===`eth_sendTransaction`&&(c.method=`privy_sendSmartWalletTx`),c.method===`eth_signTransaction`&&(c.method=`privy_signSmartWalletTx`),c.method===`personal_sign`&&(c.method=`privy_signSmartWalletMessage`),c.method===`eth_signTypedData_v4`&&(c.method=`privy_signSmartWalletTypedData`));let{method:l,params:u}=c;if(console.debug(`PrivyWalletProvider.request`,{method:l,params:u}),l===`wallet_requestPermissions`||l===`eth_requestAccounts`&&!i.address){await i.requestConnection(),o.accountsChanged?.forEach(e=>e([i.address])),o.connect?.forEach(e=>e({chainId:D(i.chain.id)}));return}if(l===`eth_chainId`)return i.chain.id;if(k(l))return a.request({method:l,params:u});switch(l){case`eth_requestAccounts`:case`eth_accounts`:return i.address?[i.address]:[];case`wallet_switchEthereumChain`:return i.switchChain({id:Number(u[0].chainId)}),a=t({chain:i.chain,transport:r.transports?.[i.chain.id]??n()}),o.chainChanged.forEach(e=>e(D(i.chain.id))),null;case`wallet_revokePermissions`:s();return;case`eth_sendTransaction`:case`eth_signTransaction`:case`eth_signTypedData_v4`:case`eth_sign`:case`privy_signSmartWalletMessage`:case`privy_signSmartWalletTypedData`:case`privy_signSmartWalletTx`:case`privy_sendSmartWalletTx`:case`personal_sign`:[`eth_sendTransaction`,`eth_signTransaction`,`privy_sendSmartWalletTx`,`privy_signSmartWalletTx`].includes(l)&&(u[0].chainId??=i.chain.id);try{return await i.sendRequest(l,u)}catch(t){throw t instanceof _&&(t.action===`clear`&&s(),t.code===void 0&&t.message===`User rejected request`)?new e(Error(`User rejected request`),{code:4001,shortMessage:`User rejected request`}):new e(t,{code:t.code??-1,shortMessage:t.message})}default:throw new e(Error(`Unsupported method`),{code:4200,shortMessage:`Unsupported method: ${l}`})}})}},D=e=>`0x${e.toString(16)}`,O={web3_clientVersion:!0,web3_sha3:!0,net_listening:!0,net_peerCount:!0,net_version:!0,eth_blobBaseFee:!0,eth_blockNumber:!0,eth_call:!0,eth_chainId:!0,eth_coinbase:!0,eth_estimateGas:!0,eth_feeHistory:!0,eth_fillTransaction:!0,eth_gasPrice:!0,eth_getBalance:!0,eth_getBlockByHash:!0,eth_getBlockByNumber:!0,eth_getBlockReceipts:!0,eth_getBlockTransactionCountByHash:!0,eth_getBlockTransactionCountByNumber:!0,eth_getCode:!0,eth_getFilterChanges:!0,eth_getFilterLogs:!0,eth_getLogs:!0,eth_getProof:!0,eth_getRawTransactionByHash:!0,eth_getStorageAt:!0,eth_getTransactionByBlockHashAndIndex:!0,eth_getTransactionByBlockNumberAndIndex:!0,eth_getTransactionByHash:!0,eth_getTransactionBySenderAndNonce:!0,eth_getTransactionCount:!0,eth_getTransactionReceipt:!0,eth_getUncleByBlockHashAndIndex:!0,eth_getUncleByBlockNumberAndIndex:!0,eth_getUncleCountByBlockHash:!0,eth_getUncleCountByBlockNumber:!0,eth_maxPriorityFeePerGas:!0,eth_newBlockFilter:!0,eth_newFilter:!0,eth_newPendingTransactionFilter:!0,eth_protocolVersion:!0,eth_sendRawTransaction:!0,eth_uninstallFilter:!0,zks_estimateFee:!0,eth_createAccessList:!0,eth_simulateV1:!0},k=e=>!!O[e];export{w as n,E as t};
//# sourceMappingURL=provider-BGfy-ebs.mjs.map