Implement payments for app deployments #17
@ -265,7 +265,7 @@ type Query {
|
|||||||
domains(projectId: String!, filter: FilterDomainsInput): [Domain]
|
domains(projectId: String!, filter: FilterDomainsInput): [Domain]
|
||||||
deployers: [Deployer]
|
deployers: [Deployer]
|
||||||
address: String!
|
address: String!
|
||||||
verifyTx(txhash: String!, amount: String!, senderAddress: String!): Boolean!
|
verifyTx(txHash: String!, amount: String!, senderAddress: String!): Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
|
@ -1406,8 +1406,8 @@ export class Service {
|
|||||||
return this.laconicRegistry.getAddress();
|
return this.laconicRegistry.getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
async verifyTx(txhash: string, amountSent: string, senderAddress: string): Promise<boolean> {
|
async verifyTx(txHash: string, amountSent: string, senderAddress: string): Promise<boolean> {
|
||||||
const txResponse = await this.laconicRegistry.getTxResponse(txhash);
|
const txResponse = await this.laconicRegistry.getTxResponse(txHash);
|
||||||
if (!txResponse) {
|
if (!txResponse) {
|
||||||
log('Transaction response not found');
|
log('Transaction response not found');
|
||||||
return false;
|
return false;
|
||||||
|
@ -56,7 +56,12 @@ const Configure = () => {
|
|||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
|
|
||||||
const methods = useForm<ConfigureFormValues>({
|
const methods = useForm<ConfigureFormValues>({
|
||||||
defaultValues: { option: 'Auction' },
|
defaultValues: {
|
||||||
|
option: 'Auction',
|
||||||
|
maxPrice: '0',
|
||||||
|
lrn: '',
|
||||||
|
numProviders: 0,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedOption = methods.watch('option');
|
const selectedOption = methods.watch('option');
|
||||||
@ -68,7 +73,7 @@ const Configure = () => {
|
|||||||
data: FieldValues,
|
data: FieldValues,
|
||||||
envVariables: AddEnvironmentVariableInput[],
|
envVariables: AddEnvironmentVariableInput[],
|
||||||
senderAddress: string,
|
senderAddress: string,
|
||||||
txHash: string
|
txHash: string,
|
||||||
): Promise<string> => {
|
): Promise<string> => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
let projectId: string | null = null;
|
let projectId: string | null = null;
|
||||||
@ -94,7 +99,7 @@ const Configure = () => {
|
|||||||
name,
|
name,
|
||||||
isPrivate,
|
isPrivate,
|
||||||
paymentAddress: senderAddress,
|
paymentAddress: senderAddress,
|
||||||
txHash
|
txHash,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { addProjectFromTemplate } = await client.addProjectFromTemplate(
|
const { addProjectFromTemplate } = await client.addProjectFromTemplate(
|
||||||
@ -115,7 +120,7 @@ const Configure = () => {
|
|||||||
repository: fullName!,
|
repository: fullName!,
|
||||||
template: 'webapp',
|
template: 'webapp',
|
||||||
paymentAddress: senderAddress,
|
paymentAddress: senderAddress,
|
||||||
txHash
|
txHash,
|
||||||
},
|
},
|
||||||
lrn,
|
lrn,
|
||||||
auctionParams,
|
auctionParams,
|
||||||
@ -166,7 +171,7 @@ const Configure = () => {
|
|||||||
createFormData,
|
createFormData,
|
||||||
environmentVariables,
|
environmentVariables,
|
||||||
senderAddress,
|
senderAddress,
|
||||||
txHash
|
txHash,
|
||||||
);
|
);
|
||||||
|
|
||||||
await client.getEnvironmentVariables(projectId);
|
await client.getEnvironmentVariables(projectId);
|
||||||
@ -305,7 +310,11 @@ const Configure = () => {
|
|||||||
control={methods.control}
|
control={methods.control}
|
||||||
rules={{ required: true }}
|
rules={{ required: true }}
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<Input type="number" value={value} onChange={onChange} />
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => onChange(e)}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -350,7 +359,7 @@ const Configure = () => {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
<ConnectWallet/>
|
<ConnectWallet numProviders={methods.watch('numProviders') || 0} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,39 +1,46 @@
|
|||||||
|
import { useMemo, useState, useCallback } from 'react';
|
||||||
|
import { Select, Option } from '@snowballtools/material-tailwind-react-fork';
|
||||||
import { Button } from '../../shared/Button';
|
import { Button } from '../../shared/Button';
|
||||||
import { useWalletConnectClient } from 'context/WalletConnectContext';
|
import { useWalletConnectClient } from 'context/WalletConnectContext';
|
||||||
import { Select, Option } from '@snowballtools/material-tailwind-react-fork';
|
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from 'context/GQLClientContext';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
const TEST_AMOUNT = "10000"
|
const ConnectWallet = ({ numProviders }: { numProviders: number }) => {
|
||||||
|
|
||||||
const ConnectWallet = () => {
|
|
||||||
const { onConnect, accounts, signClient, session } = useWalletConnectClient();
|
const { onConnect, accounts, signClient, session } = useWalletConnectClient();
|
||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
|
|
||||||
const [selectedAccount, setSelectedAccount] = useState<{
|
const [selectedAccount, setSelectedAccount] = useState<string>();
|
||||||
address: string;
|
const [isTxValid, setIsTxValid] = useState<boolean>(false);
|
||||||
balance?: string;
|
|
||||||
}>();
|
const amount = useMemo(() => numProviders * 10000, [numProviders]);
|
||||||
const [txHash, setTxHash] = useState<string>();
|
|
||||||
const [snowballAddress, setSnowballAddress] = useState<string>();
|
|
||||||
|
|
||||||
const handleConnect = async () => {
|
const handleConnect = async () => {
|
||||||
await onConnect();
|
await onConnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const verifyTx = async (
|
||||||
|
senderAddress: string,
|
||||||
|
txHash: string,
|
||||||
|
): Promise<boolean> => {
|
||||||
|
const isValid = await client.verifyTx(
|
||||||
|
txHash,
|
||||||
|
`${amount.toString()}alnt`,
|
||||||
|
senderAddress,
|
||||||
|
);
|
||||||
|
return isValid;
|
||||||
|
};
|
||||||
|
|
||||||
const cosmosSendTokensHandler = useCallback(
|
const cosmosSendTokensHandler = useCallback(
|
||||||
async (senderAddress: string, amount: string) => {
|
async (selectedAccount: string) => {
|
||||||
if (!signClient || !session || !selectedAccount || !snowballAddress) {
|
if (!signClient || !session || !selectedAccount) {
|
||||||
console.log({signClient, session, selectedAccount})
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chainId = selectedAccount.address.split(':')[1];
|
const chainId = selectedAccount.split(':')[1];
|
||||||
|
const senderAddress = selectedAccount.split(':')[2];
|
||||||
|
const snowballAddress = await client.getAddress();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result: {
|
const result: { signature: string } = await signClient.request({
|
||||||
signature: string;
|
|
||||||
} = await signClient.request({
|
|
||||||
topic: session.topic,
|
topic: session.topic,
|
||||||
chainId: `cosmos:${chainId}`,
|
chainId: `cosmos:${chainId}`,
|
||||||
request: {
|
request: {
|
||||||
@ -47,47 +54,33 @@ const ConnectWallet = () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new Error('Error completing transaction');
|
throw new Error('Error completing transaction');
|
||||||
}
|
}
|
||||||
|
|
||||||
setTxHash(result.signature);
|
const isValid = await verifyTx(senderAddress, result.signature);
|
||||||
|
setIsTxValid(isValid);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[session, signClient, selectedAccount, snowballAddress],
|
[session, signClient, selectedAccount, amount],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(txHash)
|
|
||||||
}, [txHash])
|
|
||||||
|
|
||||||
const fetchSnowballAddress = useCallback(async() => {
|
|
||||||
|
|
||||||
const address = await client.getAddress();
|
|
||||||
setSnowballAddress(address);
|
|
||||||
|
|
||||||
console.log(address)
|
|
||||||
}, [client])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchSnowballAddress()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="p-4 bg-slate-100 rounded-lg mb-6">
|
||||||
{!accounts ? (
|
{!accounts ? (
|
||||||
<Button onClick={handleConnect}>Connect Wallet</Button>
|
<Button onClick={handleConnect}>Connect Wallet</Button>
|
||||||
|
) : isTxValid ? (
|
||||||
|
<div className="mt-4 text-green-600">Tx successful!</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<Select
|
<Select
|
||||||
label="Select Account"
|
label="Select Account"
|
||||||
defaultValue={accounts[0].address}
|
defaultValue={accounts[0].address}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setSelectedAccount({
|
setSelectedAccount(value);
|
||||||
address: value!,
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{accounts.map((account, index) => (
|
{accounts.map((account, index) => (
|
||||||
@ -96,10 +89,14 @@ const ConnectWallet = () => {
|
|||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
<Button onClick={() => cosmosSendTokensHandler(selectedAccount!.address.split(":")[2], TEST_AMOUNT)}>Pay</Button>
|
<Button
|
||||||
|
onClick={() => cosmosSendTokensHandler(selectedAccount || '')}
|
||||||
|
>
|
||||||
|
Pay
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ interface ClientInterface {
|
|||||||
onConnect: () => Promise<void>;
|
onConnect: () => Promise<void>;
|
||||||
onDisconnect: () => Promise<void>;
|
onDisconnect: () => Promise<void>;
|
||||||
onSessionDelete: () => void;
|
onSessionDelete: () => void;
|
||||||
accounts: { address: string; balance?: string }[] | undefined;
|
accounts: { address: string }[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClientContext = createContext({} as ClientInterface);
|
const ClientContext = createContext({} as ClientInterface);
|
||||||
|
@ -3,5 +3,5 @@ import { VITE_WALLET_CONNECT_ID } from 'utils/constants';
|
|||||||
|
|
||||||
export const walletConnectModal = new WalletConnectModal({
|
export const walletConnectModal = new WalletConnectModal({
|
||||||
projectId: VITE_WALLET_CONNECT_ID!,
|
projectId: VITE_WALLET_CONNECT_ID!,
|
||||||
chains:['cosmos:theta-testnet-001', 'cosmos:laconic_9000-1'],
|
chains: ['cosmos:theta-testnet-001', 'cosmos:laconic_9000-1'],
|
||||||
});
|
});
|
||||||
|
@ -441,21 +441,21 @@ export class GQLClient {
|
|||||||
return data.address;
|
return data.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
async verifyTx(txhash: string, amount: string, senderAddress: string): Promise<boolean> {
|
async verifyTx(txHash: string, amount: string, senderAddress: string): Promise<boolean> {
|
||||||
console.log('Verifying Transaction with parameters:', {
|
console.log('Verifying Transaction with parameters:', {
|
||||||
txhash,
|
txHash,
|
||||||
amount,
|
amount,
|
||||||
senderAddress
|
senderAddress
|
||||||
});
|
});
|
||||||
const { data } = await this.client.query({
|
const { data: verifyTx } = await this.client.query({
|
||||||
query: queries.verifyTx,
|
query: queries.verifyTx,
|
||||||
variables: {
|
variables: {
|
||||||
txhash,
|
txHash,
|
||||||
amount,
|
amount,
|
||||||
senderAddress
|
senderAddress
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
return verifyTx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,7 +331,7 @@ query {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const verifyTx = gql`
|
export const verifyTx = gql`
|
||||||
query ($txhash: String!, $amount: String!, $senderAddress: String!) {
|
query ($txHash: String!, $amount: String!, $senderAddress: String!) {
|
||||||
verifyTx(txhash: $txhash, amount: $amount, senderAddress: $senderAddress)
|
verifyTx(txHash: $txHash, amount: $amount, senderAddress: $senderAddress)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
Loading…
Reference in New Issue
Block a user