From 66d43d257d5332ca63675a1dd29648ef1800ef6b Mon Sep 17 00:00:00 2001 From: gabrielfior Date: Mon, 6 Jan 2025 18:48:11 -0300 Subject: [PATCH 1/7] Initial working version --- python_web3_wallet/README | 2 +- python_web3_wallet/__init__.py | 2 +- python_web3_wallet/app.py | 3 +- .../frontend/src/PythonWeb3Wallet.tsx | 58 ++++++++++++++++++- python_web3_wallet/frontend/src/index.tsx | 12 +++- setup.py | 2 +- 6 files changed, 71 insertions(+), 8 deletions(-) diff --git a/python_web3_wallet/README b/python_web3_wallet/README index d067271..5fa268a 100644 --- a/python_web3_wallet/README +++ b/python_web3_wallet/README @@ -13,5 +13,5 @@ python setup.py sdist bdist_wheel # publish on testpy python -m twine upload --repository testpypi dist/* --verbose # upload to pypi -python -m twine upload dist/* --verbose +python -m twine upload dist/* --verbose ``` \ No newline at end of file diff --git a/python_web3_wallet/__init__.py b/python_web3_wallet/__init__.py index 5edd309..88d08c1 100644 --- a/python_web3_wallet/__init__.py +++ b/python_web3_wallet/__init__.py @@ -39,7 +39,7 @@ # `declare_component` and call it done. The wrapper allows us to customize # our component's API: we can pre-process its input args, post-process its # output value, and add a docstring for users. -def my_component(recipient: str, amount_in_ether: str, data: str, key=None): +def my_component(recipient: str, amount_in_ether: str, data: str | None = None, key=None): """Create a new instance of "my_component". Parameters diff --git a/python_web3_wallet/app.py b/python_web3_wallet/app.py index d7220a5..be2abec 100644 --- a/python_web3_wallet/app.py +++ b/python_web3_wallet/app.py @@ -11,4 +11,5 @@ import streamlit as st st.title('My title') -c = component(recipient="0x07354C0aD12741E8F222eB439cFf4c01716cA627", amountInEther="0.01", data=None) \ No newline at end of file +agent2 = "0xb4D8C8BedE2E49b08d2A22485f72fA516116FE7F" +c = component(recipient=agent2, amountInEther="0.00001", data='0x48656c6c6f20776f726c64') \ No newline at end of file diff --git a/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx b/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx index 1ee9571..5d51c78 100644 --- a/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx +++ b/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx @@ -3,12 +3,14 @@ import { withStreamlitConnection, ComponentProps, } from "streamlit-component-lib"; -import { type Hex, getAddress, parseEther } from 'viem'; +import { type Hex, formatEther, formatGwei, formatUnits, getAddress, parseEther } from 'viem'; import React, { useCallback, useEffect, useMemo, useState, ReactElement } from "react" import { ConnectButton } from "@rainbow-me/rainbowkit" import '@rainbow-me/rainbowkit/styles.css'; -import { useAccount, useSendTransaction } from "wagmi"; - +import { useAccount, useSendTransaction, useWriteContract, useChainId, useContractWrite, useWaitForTransactionReceipt, BaseError } from "wagmi"; +import { abi } from './abi'; +import { stringToHex } from 'viem'; +import { waitForTransactionReceipt } from "viem/actions"; /** * This is a React-based component template. The passed props are coming from the * Streamlit library. Your custom args can be accessed via the `args` props. @@ -18,6 +20,17 @@ function PythonWeb3Wallet({ args, disabled, theme }: ComponentProps): ReactEleme const { sendTransaction } = useSendTransaction(); + const { + data: hash, + error, + isPending, + writeContract + } = useWriteContract(); + const { isLoading: isConfirming, isSuccess: isConfirmed } = + useWaitForTransactionReceipt({ + hash, + }); + const chainId = useChainId(); const account = useAccount(); const [isFocused, setIsFocused] = useState(false) @@ -38,6 +51,29 @@ function PythonWeb3Wallet({ args, disabled, theme }: ComponentProps): ReactEleme }, [style, theme]); + const d = () => { + console.log('entered d'); + console.log('data', data as Hex); + writeContract({ + abi, + address: getAddress('0xd422e0059ed819e8d792af936da206878188e34f'), + functionName: 'sendMessage', + args: [ + getAddress(recipient), + data as Hex, + ], + value: parseEther(amountInEther), + }); + + console.log('executed tx hash', hash); + + + console.log('confirmed tx', isConfirmed); + + }; + + + return ( <> + +

chainId {chainId}

+

amountInEther {amountInEther}

+

pending {isPending}

+ {hash &&
Transaction Hash: {hash}
} + {isConfirming &&
Waiting for confirmation...
} + {isConfirmed &&
Transaction confirmed.
} + {error && ( +
Error: {(error as BaseError).shortMessage || error.message}
+ )} + +
Date: Mon, 6 Jan 2025 18:53:57 -0300 Subject: [PATCH 2/7] Small python improvements --- python_web3_wallet/app.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python_web3_wallet/app.py b/python_web3_wallet/app.py index be2abec..8f18a53 100644 --- a/python_web3_wallet/app.py +++ b/python_web3_wallet/app.py @@ -11,5 +11,4 @@ import streamlit as st st.title('My title') -agent2 = "0xb4D8C8BedE2E49b08d2A22485f72fA516116FE7F" -c = component(recipient=agent2, amountInEther="0.00001", data='0x48656c6c6f20776f726c64') \ No newline at end of file +c = component(recipient=0x07354C0aD12741E8F222eB439cFf4c01716cA627, amountInEther="0.00001", data='0x48656c6c6f20776f726c64') \ No newline at end of file From 24e24d10afad31fc03d01cbdd2c20971b37d9974 Mon Sep 17 00:00:00 2001 From: gabrielfior Date: Mon, 6 Jan 2025 19:40:41 -0300 Subject: [PATCH 3/7] Final touches --- python_web3_wallet/app.py | 2 +- .../frontend/src/PythonWeb3Wallet.tsx | 82 ++++++++----------- 2 files changed, 33 insertions(+), 51 deletions(-) diff --git a/python_web3_wallet/app.py b/python_web3_wallet/app.py index 8f18a53..be91bd4 100644 --- a/python_web3_wallet/app.py +++ b/python_web3_wallet/app.py @@ -11,4 +11,4 @@ import streamlit as st st.title('My title') -c = component(recipient=0x07354C0aD12741E8F222eB439cFf4c01716cA627, amountInEther="0.00001", data='0x48656c6c6f20776f726c64') \ No newline at end of file +c = component(recipient="0x07354C0aD12741E8F222eB439cFf4c01716cA627", amountInEther="0.00001", data='0x48656c6c6f20776f726c64') \ No newline at end of file diff --git a/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx b/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx index 5d51c78..8edd54a 100644 --- a/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx +++ b/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx @@ -3,14 +3,13 @@ import { withStreamlitConnection, ComponentProps, } from "streamlit-component-lib"; -import { type Hex, formatEther, formatGwei, formatUnits, getAddress, parseEther } from 'viem'; -import React, { useCallback, useEffect, useMemo, useState, ReactElement } from "react" +import { type Hex, getAddress, parseEther } from 'viem'; +import React, { useEffect, useMemo, useState, ReactElement } from "react" import { ConnectButton } from "@rainbow-me/rainbowkit" import '@rainbow-me/rainbowkit/styles.css'; -import { useAccount, useSendTransaction, useWriteContract, useChainId, useContractWrite, useWaitForTransactionReceipt, BaseError } from "wagmi"; +import { useAccount, useSendTransaction, useWriteContract, useChainId, useWaitForTransactionReceipt, BaseError } from "wagmi"; import { abi } from './abi'; -import { stringToHex } from 'viem'; -import { waitForTransactionReceipt } from "viem/actions"; +import { AGENT_COMMUNICATION_CONTRACT } from "./constants"; /** * This is a React-based component template. The passed props are coming from the * Streamlit library. Your custom args can be accessed via the `args` props. @@ -18,19 +17,14 @@ import { waitForTransactionReceipt } from "viem/actions"; function PythonWeb3Wallet({ args, disabled, theme }: ComponentProps): ReactElement { const { recipient, amountInEther, data } = args; - - const { sendTransaction } = useSendTransaction(); const { data: hash, error, - isPending, - writeContract + writeContractAsync } = useWriteContract(); - const { isLoading: isConfirming, isSuccess: isConfirmed } = - useWaitForTransactionReceipt({ - hash, - }); - const chainId = useChainId(); + // useWaitForTransactionReceipt({ + // hash, + // }); const account = useAccount(); const [isFocused, setIsFocused] = useState(false) @@ -51,25 +45,28 @@ function PythonWeb3Wallet({ args, disabled, theme }: ComponentProps): ReactEleme }, [style, theme]); - const d = () => { - console.log('entered d'); - console.log('data', data as Hex); - writeContract({ - abi, - address: getAddress('0xd422e0059ed819e8d792af936da206878188e34f'), - functionName: 'sendMessage', - args: [ - getAddress(recipient), - data as Hex, - ], - value: parseEther(amountInEther), - }); - - console.log('executed tx hash', hash); + const sendMessage = async () => { + console.log(`sending message with content ${data as Hex} to ${recipient}`); + + try { + const txHash = await writeContractAsync({ + abi, + address: AGENT_COMMUNICATION_CONTRACT, + functionName: 'sendMessage', + args: [ + getAddress(recipient), + data as Hex, + ], + value: parseEther(amountInEther), + }, { + onError: (err) => console.log(err), + }); + console.log(`txHash ${txHash}`); + } catch { + // We simply pass here since errors already logged. + } - console.log('confirmed tx', isConfirmed); - }; @@ -81,32 +78,17 @@ function PythonWeb3Wallet({ args, disabled, theme }: ComponentProps): ReactEleme backgroundColor: !account.isConnected ? 'gray' : 'blue', color: 'white', padding: '15px 30px', + marginBottom: '15px', fontSize: '18px', border: 'none', borderRadius: '10px', }} - onClick={() => - sendTransaction({ - to: getAddress(recipient), - value: parseEther(amountInEther), - data: data as Hex - }) - } + onClick={(sendMessage)} disabled={!account.isConnected} > - Send transaction + Send transaction to agent - -

chainId {chainId}

-

amountInEther {amountInEther}

-

pending {isPending}

- {hash &&
Transaction Hash: {hash}
} - {isConfirming &&
Waiting for confirmation...
} - {isConfirmed &&
Transaction confirmed.
} + {error && (
Error: {(error as BaseError).shortMessage || error.message}
)} From 4d0d445f44fb75a869424a34fa18ee3d45e548da Mon Sep 17 00:00:00 2001 From: gabrielfior Date: Mon, 6 Jan 2025 19:44:19 -0300 Subject: [PATCH 4/7] Missing files --- README.md | 6 +++--- python_web3_wallet/__init__.py | 2 +- python_web3_wallet/frontend/src/abi.ts | 21 ++++++++++++++++++++ python_web3_wallet/frontend/src/constants.ts | 1 + 4 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 python_web3_wallet/frontend/src/abi.ts create mode 100644 python_web3_wallet/frontend/src/constants.ts diff --git a/README.md b/README.md index f12bc2f..7394e4e 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ pip install web3-wallet-connect ```python import streamlit as st -from python_web3_wallet import my_component +from python_web3_wallet import wallet_component -c = my_component(recipient="0x...", amount_in_ether="0.01") # Displays RainbowKit wallet +c = wallet_component(recipient="0x...", amount_in_ether="0.01") # Displays RainbowKit wallet # Optionally data (as a Hex-formatted string) can be passed to populate the data field when sending a transaction. -# c = my_component(recipient="0x...", amount_in_ether="0.01", data="0x78da2b492d2e0100045d01c1") +# c = wallet_component(recipient="0x...", amount_in_ether="0.01", data="0x78da2b492d2e0100045d01c1") ``` \ No newline at end of file diff --git a/python_web3_wallet/__init__.py b/python_web3_wallet/__init__.py index 88d08c1..db74d8e 100644 --- a/python_web3_wallet/__init__.py +++ b/python_web3_wallet/__init__.py @@ -39,7 +39,7 @@ # `declare_component` and call it done. The wrapper allows us to customize # our component's API: we can pre-process its input args, post-process its # output value, and add a docstring for users. -def my_component(recipient: str, amount_in_ether: str, data: str | None = None, key=None): +def wallet_component(recipient: str, amount_in_ether: str, data: str | None = None, key=None): """Create a new instance of "my_component". Parameters diff --git a/python_web3_wallet/frontend/src/abi.ts b/python_web3_wallet/frontend/src/abi.ts new file mode 100644 index 0000000..d238a1d --- /dev/null +++ b/python_web3_wallet/frontend/src/abi.ts @@ -0,0 +1,21 @@ +// Abi from AgentCommunicationContract - see https://gnosisscan.io/address/0xd422e0059ed819e8d792af936da206878188e34f#code +export const abi = [ + { + "type": "function", + "name": "sendMessage", + "inputs": [ + { + "name": "agentAddress", + "type": "address", + "internalType": "address" + }, + { + "name": "message", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + ] as const \ No newline at end of file diff --git a/python_web3_wallet/frontend/src/constants.ts b/python_web3_wallet/frontend/src/constants.ts new file mode 100644 index 0000000..cded707 --- /dev/null +++ b/python_web3_wallet/frontend/src/constants.ts @@ -0,0 +1 @@ +export const AGENT_COMMUNICATION_CONTRACT = '0xd422e0059ed819e8d792af936da206878188e34f'; \ No newline at end of file From 81d8d927d9b427ca8299ebe8cd6c61ebb998c9d5 Mon Sep 17 00:00:00 2001 From: gabrielfior Date: Mon, 6 Jan 2025 19:46:44 -0300 Subject: [PATCH 5/7] Commented out Foundry-specific config --- python_web3_wallet/frontend/src/index.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/python_web3_wallet/frontend/src/index.tsx b/python_web3_wallet/frontend/src/index.tsx index 3a0523e..f91ed01 100644 --- a/python_web3_wallet/frontend/src/index.tsx +++ b/python_web3_wallet/frontend/src/index.tsx @@ -8,21 +8,22 @@ import PythonWeb3Wallet from "./PythonWeb3Wallet"; const queryClient = new QueryClient(); -const gnosisFoundryLocalhost = { - id: 99, - name: 'Gnosis-Fork', - nativeCurrency: { name: 'Ether', symbol: 'xDAI', decimals: 18 }, - rpcUrls: { - default: { http: ['http://127.0.0.1:8545'] }, - }, -} as const satisfies Chain; +// for using with forked-Gnosis chain +// const gnosisFoundryLocalhost = { +// id: 99, +// name: 'Gnosis-Fork', +// nativeCurrency: { name: 'Ether', symbol: 'xDAI', decimals: 18 }, +// rpcUrls: { +// default: { http: ['http://127.0.0.1:8545'] }, +// }, +// } as const satisfies Chain; const config = getDefaultConfig({ appName: 'app', projectId: process.env.REACT_APP_RAINBOW_WALLET_PROJECT_ID!, chains: [ gnosis, - gnosisFoundryLocalhost + //gnosisFoundryLocalhost ], }); From a36d21ecb3dff492ee29423570dfa8ea959cae08 Mon Sep 17 00:00:00 2001 From: gabrielfior Date: Mon, 6 Jan 2025 19:48:15 -0300 Subject: [PATCH 6/7] Removed dead code --- python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx b/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx index 8edd54a..05a17ea 100644 --- a/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx +++ b/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx @@ -22,9 +22,7 @@ function PythonWeb3Wallet({ args, disabled, theme }: ComponentProps): ReactEleme error, writeContractAsync } = useWriteContract(); - // useWaitForTransactionReceipt({ - // hash, - // }); + const account = useAccount(); const [isFocused, setIsFocused] = useState(false) From 54023f3f8f89a00e3d275a26f042f95928559fcc Mon Sep 17 00:00:00 2001 From: Gabriel Fior Date: Tue, 7 Jan 2025 09:32:46 -0300 Subject: [PATCH 7/7] Update python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx Co-authored-by: Peter Jung --- python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx b/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx index 05a17ea..455456e 100644 --- a/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx +++ b/python_web3_wallet/frontend/src/PythonWeb3Wallet.tsx @@ -84,7 +84,7 @@ function PythonWeb3Wallet({ args, disabled, theme }: ComponentProps): ReactEleme onClick={(sendMessage)} disabled={!account.isConnected} > - Send transaction to agent + Send message to agent {error && (