diff --git a/package.json b/package.json index 2a7c680..6944239 100644 --- a/package.json +++ b/package.json @@ -13,12 +13,13 @@ "typecheck": "vue-tsc --noEmit" }, "dependencies": { + "@albus-finance/sdk": "^0.2.0", + "@albus-finance/swap-sdk": "^0.1.1", + "@albus-finance/transfer-sdk": "^0.2.3", "@coral-xyz/anchor": "^0.28.0", "@metaplex-foundation/beet": "^0.7.1", "@metaplex-foundation/js": "^0.19.4", "@metaplex-foundation/mpl-token-metadata": "^2.12.0", - "@mfactory-lab/albus-sdk": "^0.2.6", - "@mfactory-lab/albus-transfer-sdk": "^0.0.10", "@rollup/plugin-inject": "^5.0.3", "@solana/buffer-layout": "^4.0.1", "@solana/buffer-layout-utils": "^0.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa96867..e9493a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,15 @@ settings: excludeLinksFromLockfile: false dependencies: + '@albus-finance/sdk': + specifier: ^0.2.0 + version: 0.2.0 + '@albus-finance/swap-sdk': + specifier: ^0.1.1 + version: 0.1.1 + '@albus-finance/transfer-sdk': + specifier: ^0.2.3 + version: 0.2.3 '@coral-xyz/anchor': specifier: ^0.28.0 version: 0.28.0 @@ -17,12 +26,6 @@ dependencies: '@metaplex-foundation/mpl-token-metadata': specifier: ^2.12.0 version: 2.13.0 - '@mfactory-lab/albus-sdk': - specifier: ^0.2.6 - version: 0.2.6 - '@mfactory-lab/albus-transfer-sdk': - specifier: ^0.0.10 - version: 0.0.10 '@rollup/plugin-inject': specifier: ^5.0.3 version: 5.0.5 @@ -159,6 +162,77 @@ packages: engines: {node: '>=0.10.0'} dev: true + /@albus-finance/core@0.3.2: + resolution: {integrity: sha512-ZNIjxrFABNh2QrqqkpKFA592z7MCQPlIXYUZCgd/M9CcKQTITvZf7pEogIj6y/mWrc50UZvI17pE3RDzsSZaGw==} + dependencies: + '@metaplex-foundation/mpl-token-metadata': 2.13.0 + '@solana/web3.js': 1.87.1 + '@stablelib/ed25519': 1.0.3 + '@stablelib/random': 1.0.2 + '@stablelib/sha256': 1.0.1 + '@stablelib/x25519': 1.0.3 + '@stablelib/xchacha20poly1305': 1.0.1 + axios: 1.5.1 + did-resolver: 3.2.2 + key-did-resolver: 3.0.0 + snarkjs: 0.7.2 + uint8arrays: 3.1.1 + web-did-resolver: 2.0.27 + transitivePeerDependencies: + - bufferutil + - debug + - encoding + - supports-color + - utf-8-validate + dev: false + + /@albus-finance/sdk@0.2.0: + resolution: {integrity: sha512-w58Ila0WUu/0dfJuFaiCyRbqLyRUOxQAM9VPKvVAR9n+wRmTPqA3TO6Fldt+AYeCzsiomnusi9hFe5iQ6d6PHQ==} + peerDependencies: + snarkjs: '*' + dependencies: + '@albus-finance/core': 0.3.2 + '@coral-xyz/anchor': 0.29.0 + '@metaplex-foundation/beet': 0.7.1 + '@metaplex-foundation/beet-solana': 0.4.0 + '@metaplex-foundation/mpl-token-metadata': 2.13.0 + '@solana/web3.js': 1.87.1 + lodash: 4.17.21 + transitivePeerDependencies: + - bufferutil + - debug + - encoding + - supports-color + - utf-8-validate + dev: false + + /@albus-finance/swap-sdk@0.1.1: + resolution: {integrity: sha512-R/SafP35TUMfw3E7SDkswkXKTi6/pMx1/qvqE/zw7Yz2AN50Q7NgMGmEXyVPJbEXaf/MSEyJdTbqzyUxcZUphw==} + dependencies: + '@coral-xyz/anchor': 0.29.0 + '@metaplex-foundation/beet': 0.7.1 + '@solana/web3.js': 1.87.1 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@albus-finance/transfer-sdk@0.2.3: + resolution: {integrity: sha512-ahVvtG3KsdVN51EpuVdHopdPGMgYB2MUFUhuFBqnPQl0gD4oea5XO8F+ZAKm13QyQH24eUwH6ZjJpqNc+iAlCw==} + dependencies: + '@coral-xyz/anchor': 0.29.0 + '@metaplex-foundation/beet': 0.7.1 + '@solana/spl-token': 0.3.8(@solana/web3.js@1.87.1) + '@solana/web3.js': 1.87.1 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + /@antfu/eslint-config-basic@0.39.8(@typescript-eslint/eslint-plugin@6.8.0)(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2): resolution: {integrity: sha512-HvxNu11NRpX/DHmcMcA2KenY/IIy3THEn5tpizg6vPIp3ZYSNkW3ov6sK2wxCd1S8Rwl/65566wplJ8xTYe0EA==} peerDependencies: @@ -1084,7 +1158,7 @@ packages: resolution: {integrity: sha512-LylnJoZ0CTdgErnKY8OxohvW4K+p6UHD3sxt+3P9AmMyBQjYR4IpoqoYZZ+9aMj89cmCQ21UvdhndAx04er3NA==} dependencies: fastfile: 0.0.20 - ffjavascript: 0.2.60 + ffjavascript: 0.2.62 dev: false /@jnwng/walletconnect-solana@0.2.0(@solana/web3.js@1.87.1): @@ -1401,64 +1475,6 @@ packages: - utf-8-validate dev: false - /@mfactory-lab/albus-core@0.2.5: - resolution: {integrity: sha512-RECdJGK41FPUKVZ5iP/l0inkBmIHjFeRv3x9VzrA0Xk5hllOl1uXhovNbg59rE2VU1mZ9rVlvNTqBx6Ysi63+Q==, tarball: https://npm.pkg.github.com/download/@mfactory-lab/albus-core/0.2.5/e367bf9f9693a4b23b6472ff7ad92720fe1f6a2a} - dependencies: - '@metaplex-foundation/mpl-token-metadata': 2.13.0 - '@solana/web3.js': 1.87.1 - '@stablelib/ed25519': 1.0.3 - '@stablelib/random': 1.0.2 - '@stablelib/sha256': 1.0.1 - '@stablelib/x25519': 1.0.3 - '@stablelib/xchacha20poly1305': 1.0.1 - axios: 1.5.1 - did-resolver: 3.2.2 - key-did-resolver: 3.0.0 - snarkjs: 0.7.1 - uint8arrays: 3.1.1 - web-did-resolver: 2.0.27 - transitivePeerDependencies: - - bufferutil - - debug - - encoding - - supports-color - - utf-8-validate - dev: false - - /@mfactory-lab/albus-sdk@0.2.6: - resolution: {integrity: sha512-lh4TDx29RynZwnj1Pq4DUQYKHN7A/v3LXrpOOID/aD+5eSoE7PgJyGAvcl57qG/ItME6O1Hmms8tYcYkCJC0Qw==, tarball: https://npm.pkg.github.com/download/@mfactory-lab/albus-sdk/0.2.6/d6ff3ce9a2edf46af42ff2db8f607af42380c17b} - peerDependencies: - snarkjs: '*' - dependencies: - '@coral-xyz/anchor': 0.29.0 - '@metaplex-foundation/beet': 0.7.1 - '@metaplex-foundation/beet-solana': 0.4.0 - '@metaplex-foundation/mpl-token-metadata': 2.13.0 - '@mfactory-lab/albus-core': 0.2.5 - '@solana/web3.js': 1.87.1 - lodash: 4.17.21 - transitivePeerDependencies: - - bufferutil - - debug - - encoding - - supports-color - - utf-8-validate - dev: false - - /@mfactory-lab/albus-transfer-sdk@0.0.10: - resolution: {integrity: sha512-MnHcd0Iz9SBVPzSKTssJYwJH2yozFzNX2HGM7ncWvhdEIZHjEuXhc4YfRG85WEuXAvgpDZoi3XEuU0GFX4RB9w==, tarball: https://npm.pkg.github.com/download/@mfactory-lab/albus-transfer-sdk/0.0.10/6da51e862869c37c2ff3527b5a24e4b24c769a3b} - dependencies: - '@coral-xyz/anchor': 0.29.0 - '@metaplex-foundation/beet': 0.7.1 - '@solana/spl-token': 0.3.8(@solana/web3.js@1.87.1) - '@solana/web3.js': 1.87.1 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - dev: false - /@ngraveio/bc-ur@1.1.6: resolution: {integrity: sha512-G+2XgjXde2IOcEQeCwR250aS43/Swi7gw0FuETgJy2c3HqF8f88SXDMsIGgJlZ8jXd0GeHR4aX0MfjXf523UZg==} dependencies: @@ -3602,8 +3618,8 @@ packages: retry: 0.13.1 dev: false - /async@3.2.4: - resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} dev: false /asynckit@0.4.0: @@ -5208,6 +5224,14 @@ packages: web-worker: 1.2.0 dev: false + /ffjavascript@0.2.62: + resolution: {integrity: sha512-uJ7MTrdzhX/3f+hxn0XhdXbJCqYZJSBB6y2/ui4t21vKYVjyTMlU80pPXu40ir6qpqbrdzUeKdlOdJ0aFG9UNA==} + dependencies: + wasmbuilder: 0.0.16 + wasmcurves: 0.2.2 + web-worker: 1.2.0 + dev: false + /figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -5821,7 +5845,7 @@ packages: engines: {node: '>=10'} hasBin: true dependencies: - async: 3.2.4 + async: 3.2.5 chalk: 4.1.2 filelist: 1.0.4 minimatch: 3.1.2 @@ -6273,8 +6297,8 @@ packages: engines: {node: '>=16.0.0', npm: '>=7.0.0'} dev: false - /multiformats@12.1.2: - resolution: {integrity: sha512-6mRIsrZXyw5xNPO31IGBMmxgDXBSgCGDsBAtazkZ02ip4hMwZNrQvfxXZtytRoBSWuzSq5f9VmMnXj76fIz5FQ==} + /multiformats@12.1.3: + resolution: {integrity: sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} dev: false @@ -7315,8 +7339,8 @@ packages: tslib: 2.6.2 dev: false - /snarkjs@0.7.1: - resolution: {integrity: sha512-Qs1oxssa135WZkzfARgEp5SuKHKvKNtcspeJbE5je6MurUpBylD1rzcAzQSTGWA/EH/BV/TmUyTaTD64xScvbA==} + /snarkjs@0.7.2: + resolution: {integrity: sha512-A8yPFm9pRnZ7XYXfPSjSFnugEV1rsHGjb8W7c0Qk7nzXl5h3WANTkpVC5FYxakmw/GKWekz7wjjHaOFtPp823Q==} hasBin: true dependencies: '@iden3/binfileutils': 0.0.11 @@ -7325,7 +7349,7 @@ packages: circom_runtime: 0.1.24 ejs: 3.1.9 fastfile: 0.0.20 - ffjavascript: 0.2.60 + ffjavascript: 0.2.62 js-sha3: 0.8.0 logplease: 1.2.15 r1csfile: 0.0.47 @@ -7760,7 +7784,7 @@ packages: /uint8arrays@4.0.6: resolution: {integrity: sha512-4ZesjQhqOU2Ip6GPReIwN60wRxIupavL8T0Iy36BBHr2qyMrNxsPJvr7vpS4eFt8F8kSguWUPad6ZM9izs/vyw==} dependencies: - multiformats: 12.1.2 + multiformats: 12.1.3 dev: false /underscore@1.12.1: diff --git a/src/config/connection.ts b/src/config/connection.ts index f6fc189..0561059 100644 --- a/src/config/connection.ts +++ b/src/config/connection.ts @@ -12,7 +12,7 @@ export const ENDPOINTS: Endpoint[] = [ url: import.meta.env.DEV ? 'https://restless-blue-valley.solana-mainnet.quiknode.pro/388d47063172de995210b42f44a3483d4269dcf9/' : 'https://rpc.jfactory.ch/', - wsEndpoint: import.meta.env.DEV ? undefined : 'wss://sleek-solemn-rain.solana-mainnet.quiknode.pro/1bac3b4146d57810e23b4263129fda9dbff83fe9/', + wsEndpoint: import.meta.env.DEV ? undefined : 'wss://sleek-solemn-rain.solana-mainnet.quiknode.pro/6e7118f20a84b8d10c8f00ec8f16ab6878f00fb8/', getToken: getJFRpcToken, }, { diff --git a/src/hooks/swap.ts b/src/hooks/swap.ts index d050866..804b1cc 100644 --- a/src/hooks/swap.ts +++ b/src/hooks/swap.ts @@ -2,7 +2,7 @@ import BN from 'bn.js' import { useAnchorWallet } from 'solana-wallets-vue' import type { PublicKey } from '@solana/web3.js' import { Transaction } from '@solana/web3.js' -import { getOrInitAssociatedTokenAddress, lamportsToSol, sendTransaction, solToLamports, startCreteCertificate } from '@/utils' +import { getOrInitAssociatedTokenAddress, lamportsToSol, sendTransaction, solToLamports, startCreateCertificate } from '@/utils' import solToken from '@/assets/img/tokens/sol.png' import usdcToken from '@/assets/img/tokens/usdc.png' @@ -49,7 +49,7 @@ export function useSwap() { async function swapSubmit() { const tokenSwap = swapStore.tokenSwap if (!userStore.certificateValid) { - return startCreteCertificate() + return startCreateCertificate() } if (!tokenSwap) { diff --git a/src/stores/transfer.ts b/src/stores/transfer.ts index a002005..7797125 100644 --- a/src/stores/transfer.ts +++ b/src/stores/transfer.ts @@ -2,13 +2,13 @@ import { defineStore } from 'pinia' import { useAnchorWallet, useWallet } from 'solana-wallets-vue' import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js' import { AnchorProvider } from '@coral-xyz/anchor' -import { AlbusTransferClient } from '@mfactory-lab/albus-transfer-sdk' -import { getAssociatedTokenAddress } from '@solana/spl-token' +import { AlbusTransferClient } from '@albus-finance/transfer-sdk' +import { getAccount, getAssociatedTokenAddress } from '@solana/spl-token' import BN from 'bn.js' import type { SwapData } from './swap' import type { IProofRequestStatus } from '@/stores' -import { createTransaction, getMetadataPDA, startCreteCertificate, transactionFee, validateAddress } from '@/utils' -import { TRANSFER_FEE_CONST } from '@/config' +import { createTransaction, startCreateCertificate, transactionFee, validateAddress } from '@/utils' +import { MIN_TRANSFER_FEE, TRANSFER_FEE_CONST } from '@/config' export const useTransferStore = defineStore('transfer', () => { const connectionStore = useConnectionStore() @@ -16,6 +16,7 @@ export const useTransferStore = defineStore('transfer', () => { const userStore = useUserStore() const { state: tokenState, getUserTokens } = useUserStore() const certificate = computed(() => userStore.certificate) + const requiredPolicy = computed(() => userStore.requiredPolicy) const certificateValid = computed(() => userStore.certificateValid) const defaultFee = 0.00 @@ -61,41 +62,30 @@ export const useTransferStore = defineStore('transfer', () => { }) const receiver = computed(() => validateAddress(state.address) ? new PublicKey(state.address) : '') const destinationTokenAcc = ref() - watch([tokenMint, receiver], async () => { + const hasTokenAccount = ref(false) + watch([tokenMint, receiver, () => state.valid], async () => { + if (state.token.label === 'sol') { + return hasTokenAccount.value = true + } if (tokenMint.value && receiver.value && state.valid) { - return destinationTokenAcc.value = await getAssociatedTokenAddress(tokenMint.value, receiver.value) + try { + destinationTokenAcc.value = await getAssociatedTokenAddress(tokenMint.value, receiver.value) + await getAccount(connectionStore.connection, destinationTokenAcc.value) + return hasTokenAccount.value = true + } catch (e) { + hasTokenAccount.value = false + } } - destinationTokenAcc.value = '' + hasTokenAccount.value = false }) - watch([() => state.valid, () => state.value, destinationTokenAcc], async ([v, s]) => { - if (v && Number(s) > 0) { + watch([() => state.valid, () => state.value, destinationTokenAcc], () => { + if (state.valid && Number(state.value) > 0) { getTransactionFee() } else { state.fee = defaultFee } }) - async function getTokenAccount() { - const symbol = state.token.label - if (symbol === 'sol') { - return true - } else if (!destinationTokenAcc.value) { - return false - } else { - // TODO: valid check if receiver has token account - return !!getMetadataPDA(destinationTokenAcc.value) - } - } - - async function getTransactionFee() { - const isAccountExist = await getTokenAccount() - const transaction = await createTransaction( - wallet.value?.publicKey as PublicKey, state.address, Number(state.value), connectionStore.connection) - - const fee = await transactionFee(transaction, connectionStore.connection) + TRANSFER_FEE_CONST - state.fee = !isAccountExist ? fee + 0.02 : fee - } - const transferClient = computed(() => { return new AlbusTransferClient( new AnchorProvider( @@ -106,6 +96,50 @@ export const useTransferStore = defineStore('transfer', () => { ) }) + async function getTransactionFee() { + const transaction = await createTransaction( + wallet.value?.publicKey as PublicKey, state.address, Number(state.value), connectionStore.connection) + + const fee = await transactionFee(transaction, connectionStore.connection) + TRANSFER_FEE_CONST + return state.fee = !hasTokenAccount.value ? fee + MIN_TRANSFER_FEE : fee + // TODO: fee from sdk + const policy = new PublicKey(requiredPolicy.value) + if (!publicKey.value) { + return + } + if (state.token.label === 'sol') { + const amount = new BN(Number(state.value) * LAMPORTS_PER_SOL) + const receiver = new PublicKey(state.address) + state.fee = await transferClient.value.getTransferFee({ + policy, + amount, + receiver, + proofRequest: certificate.value.pubkey, + }) / LAMPORTS_PER_SOL + } else { + if (!publicKey.value || !state.token.mint) { + return + } + const tokenInfo = tokenState.tokens.find(t => t.mint === state.token.mint) + if (!tokenInfo || !tokenMint.value || !receiver.value || !wallet.value) { + return + } + + const source = await getAssociatedTokenAddress(tokenMint.value, publicKey.value) + const amount = new BN(Number(state.value) * (10 ** tokenInfo.decimals)) + + state.fee = await transferClient.value.getTransferTokenFee({ + policy, + destination: destinationTokenAcc.value, + source, + tokenMint: tokenMint.value, + amount, + receiver: receiver.value, + proofRequest: certificate.value.pubkey, + }) / LAMPORTS_PER_SOL + } + } + async function verifyTransfer() { try { state.loading = true @@ -133,7 +167,7 @@ export const useTransferStore = defineStore('transfer', () => { reset() await getUserTokens() } else { - startCreteCertificate() + startCreateCertificate() } } catch (e) { console.error('verifyTransfer error: ', e) @@ -153,6 +187,7 @@ export const useTransferStore = defineStore('transfer', () => { amount, receiver, proofRequest: certificate.value.pubkey, + policy: new PublicKey(requiredPolicy.value), }) } @@ -161,9 +196,10 @@ export const useTransferStore = defineStore('transfer', () => { return } const tokenInfo = tokenState.tokens.find(t => t.mint === state.token.mint) - if (!tokenInfo || !tokenMint.value || !receiver.value) { + if (!tokenInfo || !tokenMint.value || !receiver.value || !wallet.value) { return } + const source = await getAssociatedTokenAddress(tokenMint.value, publicKey.value) const amount = new BN(Number(state.value) * (10 ** tokenInfo.decimals)) return await transferClient.value.transferToken({ @@ -173,6 +209,7 @@ export const useTransferStore = defineStore('transfer', () => { amount, receiver: receiver.value, proofRequest: certificate.value.pubkey, + policy: new PublicKey(requiredPolicy.value), }) } diff --git a/src/stores/user.ts b/src/stores/user.ts index c5e28d1..e96d402 100644 --- a/src/stores/user.ts +++ b/src/stores/user.ts @@ -3,8 +3,8 @@ import { useWallet } from 'solana-wallets-vue' import type { PublicKey, PublicKeyInitData } from '@solana/web3.js' import debounce from 'lodash-es/debounce' import { lowerCase } from 'lodash-es' -import type { Policy, ServiceProvider } from '@mfactory-lab/albus-sdk' -import { AlbusClient, ProofRequestStatus } from '@mfactory-lab/albus-sdk' +import type { Policy, ServiceProvider } from '@albus-finance/sdk' +import { AlbusClient, ProofRequestStatus } from '@albus-finance/sdk' import { getSolanaBalance, getTokensByOwner } from '@/utils' import { APP_CONFIG } from '@/config' @@ -35,7 +35,7 @@ export const useUserStore = defineStore('user', () => { const policySpec = ref('') // @ts-expect-error not all of clusters in config const appConfig = computed(() => APP_CONFIG[connectionStore.cluster]) - const requiredPolicy = computed(() => { + const requiredPolicy = computed(() => { if (route.name) { const pagePolicy = appConfig.value?.policy[route.name] if (pagePolicy) { diff --git a/src/utils/create-certificate.ts b/src/utils/create-certificate.ts index 8aabe75..82b8d00 100644 --- a/src/utils/create-certificate.ts +++ b/src/utils/create-certificate.ts @@ -2,7 +2,7 @@ const { emit } = useEmitter() export const CREATE_CERTIFICATE_EVENT = Symbol('CREATE_CERTIFICATE_EVENT') -export function startCreteCertificate() { +export function startCreateCertificate() { console.log('CREATE_CERTIFICATE_EVENT') emit(CREATE_CERTIFICATE_EVENT) }