Skip to content

Commit a7cecc6

Browse files
authored
HIP-583: Add test case for creating hollow account in the dapp example (#855)
* Add tests Signed-off-by: nikolay <[email protected]> * Add log Signed-off-by: nikolay <[email protected]> * Bump the local node version Signed-off-by: nikolay <[email protected]> * Pull main Signed-off-by: nikolay <[email protected]> --------- Signed-off-by: nikolay <[email protected]>
1 parent 213d7cb commit a7cecc6

File tree

8 files changed

+378
-66
lines changed

8 files changed

+378
-66
lines changed

dapp-example/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ yarn-error.log*
2626
/screenshots
2727
/cypress
2828

29-
src/contracts/.htsTokenInfo.json
29+
src/contracts/.bootstrapInfo.json

dapp-example/src/App.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import useHederaSdk from "./hooks/useHederaSdk";
88
import ContractInteractions from "./components/ContractInteractions";
99
import TransferHTSTokensForm from './components/TransferHTSTokensForm';
1010
import AssociateHTSTokensForm from './components/AssociateHTSTokensForm';
11+
import ActivateHollowAccountForm from './components/ActivateHollowAccountForm';
1112

1213
function App() {
1314
const [errorMessage, setErrorMessage] = useState(null);
@@ -19,6 +20,7 @@ function App() {
1920
const [hbarsAmount, setHbarsAmount] = useState(0);
2021
const [hbarsToAddress, setHbarsToAddress] = useState('');
2122
const [sendHbarMsg, setSendHbarMsg] = useState(null);
23+
const [toBalanceAfterTransfer, setToBalanceAfterTransfer] = useState('');
2224

2325
const { recoveredPublicKeyToAccountId } = useHederaSdk();
2426

@@ -38,6 +40,7 @@ function App() {
3840
setHbarsAmount(0)
3941
setHbarsToAddress('')
4042
setHbarsToAddress(null)
43+
setToBalanceAfterTransfer('')
4144
});
4245
}
4346
}, []);
@@ -123,10 +126,17 @@ function App() {
123126
}, [signer, address]);
124127

125128
const sendHbarsBtnHandle = useCallback(async () => {
126-
await signer.sendTransaction({
129+
const tx = await signer.sendTransaction({
127130
to: hbarsToAddress,
128-
value: hbarsAmount
131+
value: hbarsAmount,
132+
gasLimit: 600_000
129133
});
134+
await tx.wait();
135+
136+
setToBalanceAfterTransfer(ethers.utils.formatEther(await window.ethereum.request({
137+
method: 'eth_getBalance',
138+
params: [hbarsToAddress, 'latest']
139+
})));
130140
setSendHbarMsg('Done');
131141
}, [signer, hbarsToAddress, hbarsAmount]);
132142

@@ -190,6 +200,7 @@ function App() {
190200
value={hbarsAmount}
191201
onChange={(e) => setHbarsAmount(e.target.value)}
192202
/>
203+
<Typography variant="h6" id="toBalanceAfterTransfer"> Balance after transfer: {toBalanceAfterTransfer} </Typography>
193204
<Button id="sendHbarsBtn" onClick={sendHbarsBtnHandle} disabled={!isConnected} size="medium" variant="contained" color="primary">
194205
Send
195206
</Button>
@@ -206,6 +217,9 @@ function App() {
206217
<Box sx={{ mt: '2em', mb: '2em' }}>
207218
<AssociateHTSTokensForm isConnected={isConnected} signer={signer} chain={chain} address={address} />
208219
</Box>
220+
<Box sx={{ mt: '2em', mb: '2em' }}>
221+
<ActivateHollowAccountForm isConnected={isConnected} signer={signer} chain={chain} address={address} />
222+
</Box>
209223
</Grid>
210224
</Grid>
211225
</Container>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React, { useState, useCallback, useEffect } from 'react'
2+
import { Button, TextField, Typography } from "@mui/material";
3+
import { ethers } from 'ethers';
4+
import ContractTransferTx from '../contracts/ContractTransferTx.json'
5+
import bootstrapInfo from '../contracts/.bootstrapInfo.json'
6+
7+
const ActivateHollowAccountForm = ({ signer, isConnected, chain, address }) => {
8+
const [isLoading, setIsLoading] = useState(false);
9+
const [hollowAccountAddress, setHollowAccountAddress] = useState('');
10+
const [activateHollowAccountMsg, setActivateHollowAccountMsg] = useState(null);
11+
12+
// clear state vars on a chain or address have changed
13+
useEffect(() => {
14+
setIsLoading(false);
15+
setHollowAccountAddress('');
16+
setActivateHollowAccountMsg(null);
17+
}, [chain, address])
18+
19+
const activateHollowAccount = useCallback(async () => {
20+
const contract = new ethers.Contract(bootstrapInfo.CONTRACT_TRANSFER_TX_ADDRESS, ContractTransferTx.abi, signer);
21+
22+
try {
23+
setIsLoading(true);
24+
setActivateHollowAccountMsg('Loading...');
25+
26+
const tx = await contract.transferTo(hollowAccountAddress, 1_000_000_000, { gasLimit: 1_000_0000 });
27+
const receipt = await tx.wait();
28+
29+
setActivateHollowAccountMsg(receipt.events[0].event == 'Transferred' ? 'Done' : 'There was an error.');
30+
setIsLoading(false);
31+
32+
} catch (e) {
33+
console.error(e);
34+
setActivateHollowAccountMsg('There was an error.');
35+
setIsLoading(false);
36+
}
37+
}, [signer, hollowAccountAddress]);
38+
39+
return (
40+
<>
41+
<Typography variant="h5" sx={{ textDecoration: 'underline' }}> Activate Hollow Account </Typography>
42+
<br />
43+
<TextField
44+
id="hollowAccountAddressField"
45+
fullWidth
46+
label="Hollow account address"
47+
sx={{ m: 1 }}
48+
variant="standard"
49+
value={hollowAccountAddress}
50+
onChange={(e) => setHollowAccountAddress(e.target.value)}
51+
/>
52+
<br />
53+
<Button id="activateHollowAccountBtn" onClick={activateHollowAccount} disabled={!isConnected || isLoading} size="medium" variant="contained" color="primary">
54+
Activate
55+
</Button>
56+
<br />
57+
<Typography id="activateHollowAccountMsg" variant="h6"> {activateHollowAccountMsg} </Typography>
58+
</>
59+
)
60+
}
61+
62+
export default ActivateHollowAccountForm;

dapp-example/src/components/AssociateHTSTokensForm.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useState, useCallback, useEffect } from 'react'
22
import { Button, TextField, Typography } from "@mui/material";
33
import { ethers } from 'ethers';
44
import HederaTokenService from '../contracts/HederaTokenService.json'
5-
import htsTokenInfo from '../contracts/.htsTokenInfo.json'
5+
import bootstrapInfo from '../contracts/.bootstrapInfo.json'
66

77
const AssociateHTSTokensForm = ({ signer, isConnected, chain, address }) => {
88
const [isLoading, setIsLoading] = useState(false);
@@ -12,12 +12,12 @@ const AssociateHTSTokensForm = ({ signer, isConnected, chain, address }) => {
1212
// clear state vars on a chain or address have changed
1313
useEffect(() => {
1414
setIsLoading(false);
15-
setHtsTokenAddress(htsTokenInfo.HTS_SECOND_ADDRESS);
15+
setHtsTokenAddress(bootstrapInfo.HTS_SECOND_ADDRESS);
1616
setHtsTokenAssocaiteMsg(null);
1717
}, [chain, address])
1818

1919
const htsTokenAssociate = useCallback(async () => {
20-
const contract = new ethers.Contract(htsTokenInfo.HTS_CONTRACT_ADDRESS, HederaTokenService.abi, signer);
20+
const contract = new ethers.Contract(bootstrapInfo.HTS_CONTRACT_ADDRESS, HederaTokenService.abi, signer);
2121

2222
try {
2323
setIsLoading(true);
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
{
2+
"_format": "hh-sol-artifact-1",
3+
"contractName": "ContractTransferTx",
4+
"sourceName": "contracts/hip-583/ContractTransferTx.sol",
5+
"abi": [
6+
{
7+
"anonymous": false,
8+
"inputs": [
9+
{
10+
"indexed": false,
11+
"internalType": "bool",
12+
"name": "_success",
13+
"type": "bool"
14+
},
15+
{
16+
"indexed": false,
17+
"internalType": "bytes",
18+
"name": "_data",
19+
"type": "bytes"
20+
}
21+
],
22+
"name": "Success",
23+
"type": "event"
24+
},
25+
{
26+
"anonymous": false,
27+
"inputs": [
28+
{
29+
"indexed": false,
30+
"internalType": "address",
31+
"name": "_from",
32+
"type": "address"
33+
},
34+
{
35+
"indexed": false,
36+
"internalType": "address",
37+
"name": "_to",
38+
"type": "address"
39+
},
40+
{
41+
"indexed": false,
42+
"internalType": "uint256",
43+
"name": "_amount",
44+
"type": "uint256"
45+
}
46+
],
47+
"name": "Transferred",
48+
"type": "event"
49+
},
50+
{
51+
"stateMutability": "payable",
52+
"type": "fallback"
53+
},
54+
{
55+
"inputs": [
56+
{
57+
"internalType": "address",
58+
"name": "tokenContract",
59+
"type": "address"
60+
},
61+
{
62+
"internalType": "address",
63+
"name": "_from",
64+
"type": "address"
65+
},
66+
{
67+
"internalType": "address",
68+
"name": "_to",
69+
"type": "address"
70+
},
71+
{
72+
"internalType": "uint256",
73+
"name": "_tokenId",
74+
"type": "uint256"
75+
}
76+
],
77+
"name": "transferFromNonFungibleTokenTo",
78+
"outputs": [],
79+
"stateMutability": "nonpayable",
80+
"type": "function"
81+
},
82+
{
83+
"inputs": [
84+
{
85+
"internalType": "address",
86+
"name": "tokenContract",
87+
"type": "address"
88+
},
89+
{
90+
"internalType": "address",
91+
"name": "_to",
92+
"type": "address"
93+
},
94+
{
95+
"internalType": "uint256",
96+
"name": "_amount",
97+
"type": "uint256"
98+
}
99+
],
100+
"name": "transferFungibleTokenTo",
101+
"outputs": [],
102+
"stateMutability": "nonpayable",
103+
"type": "function"
104+
},
105+
{
106+
"inputs": [
107+
{
108+
"internalType": "address payable",
109+
"name": "_to",
110+
"type": "address"
111+
},
112+
{
113+
"internalType": "uint256",
114+
"name": "_amount",
115+
"type": "uint256"
116+
}
117+
],
118+
"name": "transferTo",
119+
"outputs": [],
120+
"stateMutability": "nonpayable",
121+
"type": "function"
122+
},
123+
{
124+
"stateMutability": "payable",
125+
"type": "receive"
126+
}
127+
],
128+
"bytecode": "0x608060405234801561001057600080fd5b506104b1806100206000396000f3fe6080604052600436106100355760003560e01c80632ccb1b301461003e578063cae6b2621461005e578063e8178a6a1461007e57005b3661003c57005b005b34801561004a57600080fd5b5061003c610059366004610335565b61009e565b34801561006a57600080fd5b5061003c610079366004610361565b61018f565b34801561008a57600080fd5b5061003c6100993660046103b2565b610279565b8047116100f15760405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e6365000000604482015260640160405180910390fd5b6040516001600160a01b038316908290600081818185875af1925050503d806000811461013a576040519150601f19603f3d011682016040523d82523d6000602084013e61013f565b606091505b5050604080513381526001600160a01b03851660208201529081018390527fd1ba4ac2e2a11b5101f6cb4d978f514a155b421e8ec396d2d9abaf0bb02917ee915060600160405180910390a15050565b6040516001600160a01b038481166024830152838116604483015260648201839052600091829187169060840160408051601f198184030181529181526020820180516001600160e01b03166323b872dd60e01b179052516101f19190610423565b6000604051808303816000865af19150503d806000811461022e576040519150601f19603f3d011682016040523d82523d6000602084013e610233565b606091505b50915091507fc939de2540668c9bbcd5df58c1a1a88520e87daddfe8f47a40c9584513d3dc8b828260405161026992919061043f565b60405180910390a1505050505050565b6040516001600160a01b038381166024830152604482018390526000919085169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516102d29190610423565b6000604051808303816000865af19150503d806000811461030f576040519150601f19603f3d011682016040523d82523d6000602084013e610314565b606091505b50505050505050565b6001600160a01b038116811461033257600080fd5b50565b6000806040838503121561034857600080fd5b82356103538161031d565b946020939093013593505050565b6000806000806080858703121561037757600080fd5b84356103828161031d565b935060208501356103928161031d565b925060408501356103a28161031d565b9396929550929360600135925050565b6000806000606084860312156103c757600080fd5b83356103d28161031d565b925060208401356103e28161031d565b929592945050506040919091013590565b60005b8381101561040e5781810151838201526020016103f6565b8381111561041d576000848401525b50505050565b600082516104358184602087016103f3565b9190910192915050565b821515815260406020820152600082518060408401526104668160608501602087016103f3565b601f01601f191691909101606001939250505056fea2646970667358221220f30f24e7cb53cec0f19dea9429a8b0b0d0e5ee387de9de13fb9f36354c569cdc64736f6c63430008090033",
129+
"deployedBytecode": "0x6080604052600436106100355760003560e01c80632ccb1b301461003e578063cae6b2621461005e578063e8178a6a1461007e57005b3661003c57005b005b34801561004a57600080fd5b5061003c610059366004610335565b61009e565b34801561006a57600080fd5b5061003c610079366004610361565b61018f565b34801561008a57600080fd5b5061003c6100993660046103b2565b610279565b8047116100f15760405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e6365000000604482015260640160405180910390fd5b6040516001600160a01b038316908290600081818185875af1925050503d806000811461013a576040519150601f19603f3d011682016040523d82523d6000602084013e61013f565b606091505b5050604080513381526001600160a01b03851660208201529081018390527fd1ba4ac2e2a11b5101f6cb4d978f514a155b421e8ec396d2d9abaf0bb02917ee915060600160405180910390a15050565b6040516001600160a01b038481166024830152838116604483015260648201839052600091829187169060840160408051601f198184030181529181526020820180516001600160e01b03166323b872dd60e01b179052516101f19190610423565b6000604051808303816000865af19150503d806000811461022e576040519150601f19603f3d011682016040523d82523d6000602084013e610233565b606091505b50915091507fc939de2540668c9bbcd5df58c1a1a88520e87daddfe8f47a40c9584513d3dc8b828260405161026992919061043f565b60405180910390a1505050505050565b6040516001600160a01b038381166024830152604482018390526000919085169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516102d29190610423565b6000604051808303816000865af19150503d806000811461030f576040519150601f19603f3d011682016040523d82523d6000602084013e610314565b606091505b50505050505050565b6001600160a01b038116811461033257600080fd5b50565b6000806040838503121561034857600080fd5b82356103538161031d565b946020939093013593505050565b6000806000806080858703121561037757600080fd5b84356103828161031d565b935060208501356103928161031d565b925060408501356103a28161031d565b9396929550929360600135925050565b6000806000606084860312156103c757600080fd5b83356103d28161031d565b925060208401356103e28161031d565b929592945050506040919091013590565b60005b8381101561040e5781810151838201526020016103f6565b8381111561041d576000848401525b50505050565b600082516104358184602087016103f3565b9190910192915050565b821515815260406020820152600082518060408401526104668160608501602087016103f3565b601f01601f191691909101606001939250505056fea2646970667358221220f30f24e7cb53cec0f19dea9429a8b0b0d0e5ee387de9de13fb9f36354c569cdc64736f6c63430008090033",
130+
"linkReferences": {},
131+
"deployedLinkReferences": {}
132+
}

dapp-example/tests/e2e/bootstrap.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,22 @@ const deployHederaTokenService = async function(wallet) {
121121
return contractAddress;
122122
};
123123

124+
const deployAndFundContractTransferTx = async function(wallet) {
125+
const contractArtifact = require('../../src/contracts/ContractTransferTx.json');
126+
127+
const contractFactory = new ethers.ContractFactory(contractArtifact.abi, contractArtifact.bytecode, wallet);
128+
const contract = await contractFactory.deploy({ gasLimit: 1_000_000 });
129+
const { contractAddress } = await contract.deployTransaction.wait();
130+
131+
await (new HederaSDK.TransferTransaction()
132+
.addHbarTransfer(HederaSDK.AccountId.fromEvmAddress(0,0, contractAddress), new HederaSDK.Hbar(100))
133+
.addHbarTransfer(HederaSDK.AccountId.fromString(process.env.OPERATOR_ID_MAIN), new HederaSDK.Hbar(-100)))
134+
.setTransactionMemo('relay dapp ContractTransferTx funding')
135+
.execute(client);
136+
137+
return contractAddress;
138+
};
139+
124140
(async () => {
125141
let mainPrivateKeyString = process.env.PRIVATE_KEY;
126142
if (mainPrivateKeyString === '') {
@@ -140,12 +156,14 @@ const deployHederaTokenService = async function(wallet) {
140156
const receiverAccountId = (await createAccountFromCompressedPublicKey(receiverCompressedKey)).accountId;
141157
console.log(`Receiver wallet account private: ${receiverPrivateKeyString}, public: ${receiverCompressedKey}, id: ${receiverAccountId}`);
142158

159+
const ContractTransferTxAddress = await deployAndFundContractTransferTx(mainWallet);
160+
console.log(`Contract Transfer Tx Address: ${ContractTransferTxAddress}`);
143161
const HTSContractAddress = await deployHederaTokenService(mainWallet);
144162
console.log(`HTS Contract Address: ${HTSContractAddress}`);
145163
const { tokenId, tokenAddress } = await createHTSToken();
146164
const token2 = await createHTSToken();
147-
fs.writeFileSync(path.resolve(__dirname + '../../../src/contracts/') + '/.htsTokenInfo.json',
148-
`{"HTS_ADDRESS":"${tokenAddress}", "HTS_SECOND_ADDRESS":"${token2.tokenAddress}", "HTS_CONTRACT_ADDRESS": "${HTSContractAddress}"}`);
165+
fs.writeFileSync(path.resolve(__dirname + '../../../src/contracts/') + '/.bootstrapInfo.json',
166+
`{"HTS_ADDRESS":"${tokenAddress}", "HTS_SECOND_ADDRESS":"${token2.tokenAddress}", "HTS_CONTRACT_ADDRESS": "${HTSContractAddress}", "CONTRACT_TRANSFER_TX_ADDRESS": "${ContractTransferTxAddress}"}`);
149167

150168
await associateHTSToken(mainAccountId, tokenId, mainPrivateKeyString);
151169
await approveHTSToken(mainAccountId, tokenId);

0 commit comments

Comments
 (0)