diff --git a/solana-client/components/CancelEscrowSpl.tsx b/solana-client/components/CancelEscrowSpl.tsx new file mode 100644 index 00000000..e5334d02 --- /dev/null +++ b/solana-client/components/CancelEscrowSpl.tsx @@ -0,0 +1,148 @@ +import { + Connection, + PublicKey, + Transaction, + clusterApiUrl, + SYSVAR_RENT_PUBKEY +} from "@solana/web3.js" + +import { + getAssociatedTokenAddress, + TOKEN_PROGRAM_ID, + } from '@solana/spl-token'; + +import { + AnchorProvider, + setProvider, + BN +} from "@project-serum/anchor" + +import styles from '../styles/PingButton.module.css' +import idl from "../xfluencer.json" + +import { useAnchorWallet, useWallet } from '@solana/wallet-adapter-react'; +import * as anchor from "@coral-xyz/anchor"; + +import { FC } from "react"; +import { utf8 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; + +import * as utils from "./utils"; +import { log } from "console"; + +const programId = new PublicKey(idl.metadata.address); + +export const findATA = ( + walletKey: PublicKey, + mintKey: PublicKey, + ): Promise => { + return getAssociatedTokenAddress( + mintKey, + walletKey, + true, // allowOwnerOffCurve aka PDA + ); + }; + +interface CancelEscrowSplProps { + business: string, + validatorAuthority: string, + mintTokenAccount: string, + orderCode: number +} + +export const CancelEscrowSpl: FC = ( + {business, + validatorAuthority, + mintTokenAccount, + orderCode}) => { + + const wallet = useAnchorWallet() + const connection = new Connection(clusterApiUrl('devnet'), + { + commitment: "confirmed", + confirmTransactionInitialTimeout: 30000 + }); + + const program = utils.getAnchorProgram(connection); + const provider = new AnchorProvider(connection, wallet, {}) + setProvider(provider) + const { publicKey, signTransaction, sendTransaction } = useWallet() + + if (!connection || !publicKey) { + console.warn("Wallet was not connected") + return ( +
+ +
) + } + + const onClick = async () => { + + // transform strings to publick keys + const business_pk = new PublicKey(business) + const validatorAuthorityPk = new PublicKey(validatorAuthority) ; + const mintPublicKey = new PublicKey(mintTokenAccount); + + console.log(business_pk.toString()) + + // discover ATA for Business + const associatedTokenAccForBusiness + = await findATA(business_pk, mintPublicKey); + + // discover PDA for vault token account + const [vaultAccountPda, vault_account_bump] + = await PublicKey.findProgramAddress( + [Buffer.from(anchor.utils.bytes.utf8.encode("token-seed"+orderCode.toString()))], + program.programId + ); + + // discover PDA for escrow (data) account + const [escrowAccountPda, ] + = await PublicKey.findProgramAddress( + [Buffer.from(anchor.utils.bytes.utf8.encode("escrow-data"+orderCode.toString()))], + program.programId + ); + + // prepare instruction for cancel escrow using SPL + const ix = await program.methods.cancelEscrowSpl( + new BN(orderCode) + ) + .accounts({ + business: business_pk, + businessDepositTokenAccount: associatedTokenAccForBusiness, + vaultAccount: vaultAccountPda, + vaultAuthority: validatorAuthorityPk, + escrowAccount: escrowAccountPda, + tokenProgram: TOKEN_PROGRAM_ID, + rent: SYSVAR_RENT_PUBKEY, + }) + .instruction(); + + const tx = new Transaction().add(ix); + + const options = { + skipPreflight: true + } + + try { + const signature = await sendTransaction(tx, connection, options); + const txSign = await connection.confirmTransaction(signature, "processed"); + console.debug("txSing", txSign); + console.debug("context", txSign.context); + console.debug("value", txSign.value); + if(txSign.value.err != null){ + throw new Error(`Instruction error number found: ` + txSign.value.err['InstructionError'][0].toString()); + } + } + catch(error) + { + console.error(error) + } + } + + return ( + + ) + +} \ No newline at end of file diff --git a/solana-client/components/CreateEscrowSpl.tsx b/solana-client/components/CreateEscrowSpl.tsx index ffc1b9a6..c2ab9a7c 100644 --- a/solana-client/components/CreateEscrowSpl.tsx +++ b/solana-client/components/CreateEscrowSpl.tsx @@ -104,21 +104,22 @@ export const CreateEscrowSpl: FC = ({validator, console.log("Program Id", programId.toString()) const [escrow_account_pda, _escrow_account_bump] - = await PublicKey.findProgramAddress([ - utf8.encode('escrow'), - utf8.encode(orderCode.toString()) - ], - programId - ); + = await PublicKey.findProgramAddress([ + utf8.encode('escrow-data'), + utf8.encode(orderCode.toString()) + ], + programId + ); + console.log("Program Id", programId) console.info("Escrow Address found:", - escrow_account_pda.toString(), _escrow_account_bump) - - const VAULT_SEED = Buffer.from("vault" + orderCode.toString(),"utf8"); + escrow_account_pda.toString(), + _escrow_account_bump) const [_vault_account_pda, _vault_account_bump] = await PublicKey.findProgramAddress( - [VAULT_SEED],programId); + [Buffer.from("token-seed" + orderCode.toString(),"utf8")], + programId); console.info("vault",_vault_account_pda.toString(),_vault_account_bump) @@ -149,15 +150,14 @@ export const CreateEscrowSpl: FC = ({validator, new BN(orderCode)) .accounts( { - initializer: businessPublicKey, business: businessPublicKey, influencer: influencerPublicKey, + vaultAccount: vault_account_pda, validationAuthority: validatorPublicKey, mint: mintPublicKey, businessDepositTokenAccount: businessTokenAccount, influencerReceiveTokenAccount: influencerTokenAccount, escrowAccount: escrow_account_pda, - vaultAccount: vault_account_pda, systemProgram: SystemProgram.programId, tokenProgram: TOKEN_PROGRAM_ID, rent: SYSVAR_RENT_PUBKEY, diff --git a/solana-client/components/ValidateEscrowSpl.tsx b/solana-client/components/ValidateEscrowSpl.tsx new file mode 100644 index 00000000..4c73209d --- /dev/null +++ b/solana-client/components/ValidateEscrowSpl.tsx @@ -0,0 +1,134 @@ +import { + Connection, + PublicKey, + Transaction, + clusterApiUrl, +} from "@solana/web3.js" + +import { + AnchorProvider, + setProvider, +} from "@project-serum/anchor" + +import styles from '../styles/PingButton.module.css' + +import idl from "../xfluencer.json" +import { + useAnchorWallet, + useConnection, + useWallet +} from '@solana/wallet-adapter-react'; +import * as anchor from "@coral-xyz/anchor"; + +import { FC } from "react"; +import { utf8 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; + +import * as utils from "./utils"; +import { TOKEN_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token"; + +const programId = new PublicKey(idl.metadata.address); + +interface ValidateEscrowSplProps { + validator: string, + business: string, + influencer: string, + percentageFee: number, + orderCode: number, + targetState: number, + textButton: string +} + +export const ValidateEscrowSpl: FC = ({ + validator, + business, influencer, + percentageFee, orderCode, + targetState, textButton }) => { + + const wallet = useAnchorWallet() + const connection = new Connection(clusterApiUrl('devnet'), + { + commitment: "confirmed", + confirmTransactionInitialTimeout: 30000 + }); + + const program = utils.getAnchorProgram(connection); + const provider = new AnchorProvider(connection, wallet, {}) + setProvider(provider) + const { publicKey, signTransaction, sendTransaction } = useWallet() + + if (!connection || !publicKey) { + const msg = "Wallet is not connected" + console.warn(msg) + return ( +
+ +
+ ) + } else { + console.log("wallet", wallet.publicKey) + } + + + const onClick = async () => { + + if (!connection || !publicKey) { + console.warn("Wallet is not connected") + return + } + + const validatorPublicKey = new PublicKey(validator); + const businessPublicKey = new PublicKey(business); + const influencerPublicKey = new PublicKey(influencer); + + const [vaultAccountPda] = await PublicKey.findProgramAddress( + [Buffer.from("token-seed" + orderCode.toString(),"utf8")], + programId); + + const [escrowPDA] = await PublicKey.findProgramAddress([ + utf8.encode('escrow-data'), + utf8.encode(orderCode.toString())],programId); + + const ix = await program.methods.validateEscrowSpl( + new anchor.BN(targetState), + new anchor.BN(percentageFee) + ).accounts({ + validationAuthority: validatorPublicKey, + vaultAccount: vaultAccountPda, + influencer: influencerPublicKey, + business: businessPublicKey, + escrowAccount: escrowPDA, + tokenProgram: TOKEN_PROGRAM_ID + }).instruction(); + + const tx = new Transaction().add(ix); + + const options = { + skipPreflight: true + } + + try { + const signature = await sendTransaction(tx, connection, options); + console.debug("signature", signature.valueOf()); + const txSign = await connection.confirmTransaction(signature, "processed"); + console.debug("txSing", txSign.value); + console.debug("context", txSign.context); + console.debug("value", txSign.value); + if (txSign.value.err != null) { + throw new Error(`Instruction error number found: ` + txSign.value.err['InstructionError'][0].toString()); + } + } + catch (error) { + console.error(error) + alert("Error Found on Validation " + error); + } + + + } + + return ( + + ) + +} \ No newline at end of file diff --git a/solana-client/pages/index.tsx b/solana-client/pages/index.tsx index 3a93f4b5..dc8d4f20 100644 --- a/solana-client/pages/index.tsx +++ b/solana-client/pages/index.tsx @@ -7,12 +7,18 @@ import { AppBar } from '../components/AppBar' import Head from 'next/head' import {Input} from "@nextui-org/react"; + +// import components to support escrow using sol import { CreateEscrowSolana } from '../components/CreateEscrowSolana' import { ClaimEscrowSolana } from '../components/ClaimEscrowSolana' import { CancelEscrowSolana } from '../components/CancelEscrowSolana' -import { CreateEscrowSpl } from '../components/CreateEscrowSpl' import { Validate } from '../components/Validate' +// import components to support escrows using spl +import { CreateEscrowSpl } from '../components/CreateEscrowSpl' +import { CancelEscrowSpl } from '../components/CancelEscrowSpl' +import { ValidateEscrowSpl } from '../components/ValidateEscrowSpl' + import { LAMPORTS_PER_SOL } from '@solana/web3.js' import { findATA } from "../components/utils"; @@ -33,7 +39,7 @@ const Home: NextPage = (props) => { const NUM_SOLS : number = 0.1; const LAMPORTS : number = NUM_SOLS * LAMPORTS_PER_SOL; // (10^9 lamports == 1 SOL) const ORDER_CODE : number = 12347 // THIS MUST BE UNIQUE PER business-influencer (1 transaction at a time) OTHERWISE ERROR - const NUM_SPL_TOKENS : number = 1000000; // with 6 deciamls 10**6 is 1 token unit + const NUM_SPL_TOKENS : number = 1000000; // 6 decimals ==> 10 ** 6 == 1 Token Unit const PERCENTAGE_FEE: number = 0; @@ -103,8 +109,6 @@ const Home: NextPage = (props) => { orderCode={ORDER_CODE} targetState={2} textButton={"Validate Escrow Delivery"}/> - -
@@ -143,6 +147,22 @@ const Home: NextPage = (props) => { mint={MINT} tokens={NUM_SPL_TOKENS} orderCode={ORDER_CODE}/> + + + + + +
diff --git a/solana-python/config.json b/solana-python/config.json index 86fbd888..c7a32c58 100644 --- a/solana-python/config.json +++ b/solana-python/config.json @@ -1,5 +1,9 @@ { "network": "devnet", + "rpc":{ + "mainnet":"https://bold-hidden-glade.solana-mainnet.quiknode.pro/bcd715dccef5e699ea43459b691a09c2bc8dc474", + "devnet":"" + }, "payer": { "pubkey": "GQRDv58u1dULSyHSYWPqNTjcWjsFHHi763mbqDaEEgQ3", "usdc_ata":"EN2jBpee542UCU7k8p83qziyvHiYcavddz9kqV7eFZ6C", @@ -24,7 +28,7 @@ "lamports":10000000, "usdc": 1000000 }, - "order_code": 2002, + "order_code": 2005, "program_id":{ "localnet": "7zNs7f6rJyhvu9k4DZwqeqgBa27GqX12mVeQAS528xEq", "devnet": "DmYaabL1PhacWWsRwyZpBqBP9n7tVq7115zG2tznYLb9",