Implement payments for app deployments #17
@ -85,16 +85,16 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
|||||||
return service.getAddress();
|
return service.getAddress();
|
||||||
},
|
},
|
||||||
|
|
||||||
verifyTx: async (
|
// verifyTx: async (
|
||||||
_: any,
|
// _: any,
|
||||||
{
|
// {
|
||||||
txHash,
|
// txHash,
|
||||||
amount,
|
// amount,
|
||||||
senderAddress,
|
// senderAddress,
|
||||||
}: { txHash: string; amount: string; senderAddress: string },
|
// }: { txHash: string; amount: string; senderAddress: string },
|
||||||
) => {
|
// ) => {
|
||||||
return service.verifyTx(txHash, amount, senderAddress);
|
// return service.verifyTx(txHash, amount, senderAddress);
|
||||||
},
|
// },
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Return error in GQL response
|
// TODO: Return error in GQL response
|
||||||
|
@ -23,6 +23,7 @@ import { useGQLClient } from '../../../context/GQLClientContext';
|
|||||||
import EnvironmentVariablesForm from 'pages/org-slug/projects/id/settings/EnvironmentVariablesForm';
|
import EnvironmentVariablesForm from 'pages/org-slug/projects/id/settings/EnvironmentVariablesForm';
|
||||||
import { EnvironmentVariablesFormValues } from 'types/types';
|
import { EnvironmentVariablesFormValues } from 'types/types';
|
||||||
import ConnectWallet from './ConnectWallet';
|
import ConnectWallet from './ConnectWallet';
|
||||||
|
import { useWalletConnectClient } from 'context/WalletConnectContext';
|
||||||
|
|
||||||
type ConfigureDeploymentFormValues = {
|
type ConfigureDeploymentFormValues = {
|
||||||
option: string;
|
option: string;
|
||||||
@ -35,8 +36,11 @@ type ConfigureFormValues = ConfigureDeploymentFormValues &
|
|||||||
EnvironmentVariablesFormValues;
|
EnvironmentVariablesFormValues;
|
||||||
|
|
||||||
const Configure = () => {
|
const Configure = () => {
|
||||||
|
const { signClient, session } = useWalletConnectClient();
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [deployers, setDeployers] = useState<Deployer[]>([]);
|
const [deployers, setDeployers] = useState<Deployer[]>([]);
|
||||||
|
const [selectedAccount, setSelectedAccount] = useState<string>();
|
||||||
|
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const templateId = searchParams.get('templateId');
|
const templateId = searchParams.get('templateId');
|
||||||
@ -148,12 +152,41 @@ const Configure = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// const verifyTx = async (
|
||||||
|
// senderAddress: string,
|
||||||
|
// txHash: string,
|
||||||
|
// ): Promise<boolean> => {
|
||||||
|
// const isValid = await client.verifyTx(
|
||||||
|
// txHash,
|
||||||
|
// `${amount.toString()}alnt`,
|
||||||
|
// senderAddress,
|
||||||
|
// );
|
||||||
|
// return isValid;
|
||||||
|
// };
|
||||||
|
|
||||||
const handleFormSubmit = useCallback(
|
const handleFormSubmit = useCallback(
|
||||||
async (createFormData: FieldValues) => {
|
async (createFormData: FieldValues) => {
|
||||||
// Send tx request to wallet -> amount = createFormData.maxPrice * createFormData.numProviders
|
// Send tx request to wallet -> amount = createFormData.maxPrice * createFormData.numProviders
|
||||||
// Get address of sender account(from wallet connect session) and txHash(result.signature)
|
// Get address of sender account(from wallet connect session) and txHash(result.signature)
|
||||||
const senderAddress = 'address';
|
if (!selectedAccount) {
|
||||||
const txHash = 'txHash';
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const senderAddress = selectedAccount;
|
||||||
|
|
||||||
|
const amount = createFormData.numProviders * createFormData.maxPrice;
|
||||||
|
const txHash = await cosmosSendTokensHandler(
|
||||||
|
selectedAccount,
|
||||||
|
String(amount),
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(txHash);
|
||||||
|
|
||||||
|
// const isTxHashValid = verifyTx(senderAddress, txHash);
|
||||||
|
// if (!isTxHashValid) {
|
||||||
|
// console.error("Invalid Tx hash", txHash)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
const environmentVariables = createFormData.variables.map(
|
const environmentVariables = createFormData.variables.map(
|
||||||
(variable: any) => {
|
(variable: any) => {
|
||||||
@ -171,7 +204,7 @@ const Configure = () => {
|
|||||||
createFormData,
|
createFormData,
|
||||||
environmentVariables,
|
environmentVariables,
|
||||||
senderAddress,
|
senderAddress,
|
||||||
txHash,
|
txHash!,
|
||||||
);
|
);
|
||||||
|
|
||||||
await client.getEnvironmentVariables(projectId);
|
await client.getEnvironmentVariables(projectId);
|
||||||
@ -202,6 +235,48 @@ const Configure = () => {
|
|||||||
setDeployers(res.deployers);
|
setDeployers(res.deployers);
|
||||||
}, [client]);
|
}, [client]);
|
||||||
|
|
||||||
|
const onAccountChange = useCallback((account: string) => {
|
||||||
|
setSelectedAccount(account);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const cosmosSendTokensHandler = useCallback(
|
||||||
|
async (selectedAccount: string, amount: string) => {
|
||||||
|
if (!signClient || !session || !selectedAccount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chainId = selectedAccount.split(':')[1];
|
||||||
|
const senderAddress = selectedAccount.split(':')[2];
|
||||||
|
const snowballAddress = await client.getAddress();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result: { signature: string } = await signClient.request({
|
||||||
|
topic: session.topic,
|
||||||
|
chainId: `cosmos:${chainId}`,
|
||||||
|
request: {
|
||||||
|
method: 'cosmos_sendTokens',
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
from: senderAddress,
|
||||||
|
to: snowballAddress,
|
||||||
|
value: amount,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
throw new Error('Error completing transaction');
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.signature;
|
||||||
|
} catch (error: any) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[session, signClient],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchDeployers();
|
fetchDeployers();
|
||||||
}, []);
|
}, []);
|
||||||
@ -340,7 +415,10 @@ const Configure = () => {
|
|||||||
<div className="p-4 bg-slate-100 rounded-lg mb-6">
|
<div className="p-4 bg-slate-100 rounded-lg mb-6">
|
||||||
<EnvironmentVariablesForm />
|
<EnvironmentVariablesForm />
|
||||||
</div>
|
</div>
|
||||||
|
<Heading as="h4" className="md:text-lg font-medium mb-3">
|
||||||
|
Connect to your wallet
|
||||||
|
</Heading>
|
||||||
|
<ConnectWallet onAccountChange={onAccountChange} />
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
{...buttonSize}
|
{...buttonSize}
|
||||||
@ -359,7 +437,6 @@ const Configure = () => {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
<ConnectWallet numProviders={methods.watch('numProviders') || 0} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,86 +1,33 @@
|
|||||||
import { useMemo, useState, useCallback } from 'react';
|
|
||||||
import { Select, Option } from '@snowballtools/material-tailwind-react-fork';
|
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 { useGQLClient } from 'context/GQLClientContext';
|
|
||||||
|
|
||||||
const ConnectWallet = ({ numProviders }: { numProviders: number }) => {
|
const ConnectWallet = ({
|
||||||
const { onConnect, accounts, signClient, session } = useWalletConnectClient();
|
onAccountChange,
|
||||||
const client = useGQLClient();
|
}: {
|
||||||
|
onAccountChange: (selectedAccount: string) => void;
|
||||||
const [selectedAccount, setSelectedAccount] = useState<string>();
|
}) => {
|
||||||
const [isTxValid, setIsTxValid] = useState<boolean>(false);
|
const { onConnect, accounts } = useWalletConnectClient();
|
||||||
|
|
||||||
const amount = useMemo(() => numProviders * 10000, [numProviders]);
|
|
||||||
|
|
||||||
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(
|
|
||||||
async (selectedAccount: string) => {
|
|
||||||
if (!signClient || !session || !selectedAccount) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const chainId = selectedAccount.split(':')[1];
|
|
||||||
const senderAddress = selectedAccount.split(':')[2];
|
|
||||||
const snowballAddress = await client.getAddress();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result: { signature: string } = await signClient.request({
|
|
||||||
topic: session.topic,
|
|
||||||
chainId: `cosmos:${chainId}`,
|
|
||||||
request: {
|
|
||||||
method: 'cosmos_sendTokens',
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
from: senderAddress,
|
|
||||||
to: snowballAddress,
|
|
||||||
value: amount,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
throw new Error('Error completing transaction');
|
|
||||||
}
|
|
||||||
|
|
||||||
const isValid = await verifyTx(senderAddress, result.signature);
|
|
||||||
setIsTxValid(isValid);
|
|
||||||
} catch (error: any) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[session, signClient, selectedAccount, amount],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-4 bg-slate-100 rounded-lg mb-6">
|
<div className="p-4 bg-slate-100 rounded-lg mb-6">
|
||||||
{!accounts ? (
|
{!accounts ? (
|
||||||
<Button onClick={handleConnect}>Connect Wallet</Button>
|
<div>
|
||||||
) : isTxValid ? (
|
<Button type={'button'} onClick={handleConnect}>
|
||||||
<div className="mt-4 text-green-600">Tx successful!</div>
|
Connect Wallet
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<Select
|
<Select
|
||||||
label="Select Account"
|
label="Select Account"
|
||||||
defaultValue={accounts[0].address}
|
defaultValue={accounts[0].address}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setSelectedAccount(value);
|
value && onAccountChange(value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{accounts.map((account, index) => (
|
{accounts.map((account, index) => (
|
||||||
@ -89,11 +36,6 @@ const ConnectWallet = ({ numProviders }: { numProviders: number }) => {
|
|||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
<Button
|
|
||||||
onClick={() => cosmosSendTokensHandler(selectedAccount || '')}
|
|
||||||
>
|
|
||||||
Pay
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user