Skip to content

Commit b2419e2

Browse files
authored
feat: Hiero Hooks (#1572)
* chore: update protos Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * feat: update statuses Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * HIP-1195: Structs (#1520) * feat: add structs Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * test: unit Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: refactor Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> --------- Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * HIP-1195: Account related changes (#1525) * feat: account related changes Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: address feedback Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> --------- Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * HIP-1195: Contract changes (#1540) * feat: contract related changes Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * test: unit Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> --------- Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * HIP-1195: Transfer Transaction changes (#1542) * feat: implementation Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: fix hook entity id Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * test: unit and e2e Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * test: add more e2e Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: remove full hookid from hookcall Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * fix: extract sedner and receiver hooks for NFTs separately Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: address PR feedback Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> --------- Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * HIP-1195: LambdaSStoreTransaction (#1544) * feat: lambdasstore Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: refactor Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> --------- Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * HIP-1195: Examples (#1545) * feat: lambdasstore Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: refactor Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * feat: implement examples Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: refactor Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> --------- Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: update protos Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: bump CN Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * chore: fix linter Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> * test: fix e2e Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com> --------- Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com>
1 parent 53b7f04 commit b2419e2

File tree

171 files changed

+11728
-626
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

171 files changed

+11728
-626
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ jobs:
101101
uses: hiero-ledger/hiero-solo-action@dd0048139ef1e40fd6067f01bf94eb42a67294f4 # v0.15.0
102102
with:
103103
installMirrorNode: true
104+
hieroVersion: v0.69.0-alpha.1
104105

105106
- name: Set Operator Account
106107
if: success() && matrix.test-type == 'e2e'
@@ -172,6 +173,7 @@ jobs:
172173
uses: hiero-ledger/hiero-solo-action@dd0048139ef1e40fd6067f01bf94eb42a67294f4 # v0.14.0
173174
with:
174175
installMirrorNode: true
176+
hieroVersion: v0.69.0-alpha.1
175177

176178
- name: Set Operator Account
177179
run: |
@@ -231,6 +233,7 @@ jobs:
231233
uses: hiero-ledger/hiero-solo-action@dd0048139ef1e40fd6067f01bf94eb42a67294f4 # v0.15.0
232234
with:
233235
installMirrorNode: true
236+
hieroVersion: v0.69.0-alpha.1
234237

235238
- name: Set Operator Account
236239
run: |
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity >=0.4.9 <0.9.0;
3+
pragma experimental ABIEncoderV2;
4+
/// The interface for a generic EVM hook.
5+
interface IHieroHook {
6+
/// The context the hook is executing in
7+
struct HookContext {
8+
/// The address of the entity the hook is executing on behalf of
9+
address owner;
10+
/// The fee the transaction payer was charged for the triggering transaction
11+
uint256 txnFee;
12+
/// The gas cost the transaction payer was charged for specifically this hook
13+
uint256 gasCost;
14+
/// The memo of the triggering transaction
15+
string memo;
16+
/// Any extra call data passed to the hook
17+
bytes data;
18+
}
19+
}
20+
/// The interface for an account allowance hook invoked once before a CryptoTransfer.
21+
interface IHieroAccountAllowanceHook {
22+
/// A single balance adjustment in the range of a Hiero native token
23+
struct AccountAmount {
24+
// The address of the account whose balance is changing
25+
address account;
26+
// The amount in atomic units of the change
27+
int64 amount;
28+
}
29+
/// A single NFT ownership change
30+
struct NftTransfer {
31+
// The address of the sender
32+
address sender;
33+
// The address of the receiver
34+
address receiver;
35+
// The serial number being transferred
36+
int64 serialNo;
37+
}
38+
/// A zero-sum list of balance adjustments for a Hiero-native token
39+
struct TokenTransferList {
40+
// The Hiero token address
41+
address token;
42+
// For a fungible token, the zero-sum balance adjustments
43+
AccountAmount[] adjustments;
44+
// For a non-fungible token, the NFT ownership changes
45+
NftTransfer[] nftTransfers;
46+
}
47+
/// Combines HBAR and HTS asset transfers.
48+
struct Transfers {
49+
/// A zero-sum list of balance adjustments for HBAR specifically
50+
AccountAmount[] hbarAdjustments;
51+
/// The HTS token transfers
52+
TokenTransferList[] tokens;
53+
}
54+
/// Combines the full proposed transfers for a Hiero transaction,
55+
/// including both its direct transfers and the implied HIP-18
56+
/// custom fee transfers.
57+
struct ProposedTransfers {
58+
/// The transaction's direct transfers
59+
Transfers direct;
60+
/// The transaction's assessed custom fees
61+
Transfers customFee;
62+
}
63+
/// Decides if the proposed transfers are allowed, optionally in
64+
/// the presence of additional context encoded by the transaction
65+
/// payer in the extra calldata.
66+
/// @param context The context of the hook call
67+
/// @param proposedTransfers The proposed transfers
68+
/// @return true If the proposed transfers are allowed, false or revert otherwise
69+
function allow(
70+
IHieroHook.HookContext calldata context,
71+
ProposedTransfers memory proposedTransfers
72+
) external payable returns (bool);
73+
}
74+
contract AlwaysAllowAccountAllowancePrePostHook is IHieroAccountAllowanceHook {
75+
function allowPre(
76+
IHieroHook.HookContext calldata /* context */,
77+
ProposedTransfers memory /* proposedTransfers */
78+
) external payable returns (bool) {
79+
return true;
80+
}
81+
function allowPost(
82+
IHieroHook.HookContext calldata /* context */,
83+
ProposedTransfers memory /* proposedTransfers */
84+
) external payable returns (bool) {
85+
return true;
86+
}
87+
function allow(
88+
IHieroHook.HookContext calldata context,
89+
ProposedTransfers memory proposedTransfers
90+
) external payable returns (bool) {
91+
return true;
92+
}
93+
}

examples/hooks/account/main.go

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/hiero-ledger/hiero-sdk-go/v2/examples/hooks/utils"
8+
hiero "github.com/hiero-ledger/hiero-sdk-go/v2/sdk"
9+
)
10+
11+
// HIP-1195 example for creating and updating an account with a hook
12+
func main() {
13+
var client *hiero.Client
14+
var err error
15+
16+
// Retrieving network type from environment variable HEDERA_NETWORK
17+
client, err = hiero.ClientForName(os.Getenv("HEDERA_NETWORK"))
18+
if err != nil {
19+
panic(fmt.Sprintf("%v : error creating client", err))
20+
}
21+
defer client.Close()
22+
23+
// Retrieving operator ID from environment variable OPERATOR_ID
24+
operatorAccountID, err := hiero.AccountIDFromString(os.Getenv("OPERATOR_ID"))
25+
if err != nil {
26+
panic(fmt.Sprintf("%v : error converting string to AccountID", err))
27+
}
28+
29+
// Retrieving operator key from environment variable OPERATOR_KEY
30+
operatorKey, err := hiero.PrivateKeyFromString(os.Getenv("OPERATOR_KEY"))
31+
if err != nil {
32+
panic(fmt.Sprintf("%v : error converting string to PrivateKey", err))
33+
}
34+
35+
// Setting the client operator ID and key
36+
client.SetOperator(operatorAccountID, operatorKey)
37+
38+
fmt.Println("Creating hook contract")
39+
hookContractId := utils.CreateHookContractId(client)
40+
fmt.Printf("Hook contract created: %v\n", hookContractId)
41+
42+
fmt.Println("Creating account with hook")
43+
createAccountWithHook(client, hookContractId)
44+
45+
fmt.Println("Updating account to add hook")
46+
addHookToAccount(client, hookContractId)
47+
48+
fmt.Println("Updating account to delete hook")
49+
deleteHookFromAccount(client, hookContractId)
50+
51+
fmt.Println("Example completed")
52+
}
53+
54+
func createAccountWithHook(client *hiero.Client, hookContractId *hiero.ContractID) {
55+
fmt.Println("Creating account with hook...")
56+
57+
// Create hook detail
58+
hookDetail := hiero.NewHookCreationDetails().
59+
SetExtensionPoint(hiero.ACCOUNT_ALLOWANCE_HOOK).
60+
SetHookId(1).
61+
SetLambdaEvmHook(*hiero.NewLambdaEvmHook().SetContractId(hookContractId))
62+
63+
// Generate account private key
64+
fmt.Println("Generating account private key...")
65+
accountPrivateKey, err := hiero.PrivateKeyGenerateEd25519()
66+
if err != nil {
67+
panic(fmt.Sprintf("%v : error generating account private key", err))
68+
}
69+
accountPublicKey := accountPrivateKey.PublicKey()
70+
71+
// Create account create transaction with hook
72+
fmt.Println("Executing account create transaction with hook...")
73+
response, err := hiero.NewAccountCreateTransaction().
74+
SetKeyWithoutAlias(accountPublicKey).
75+
AddHook(*hookDetail).
76+
SetMaxTransactionFee(hiero.NewHbar(10)).
77+
Execute(client)
78+
if err != nil {
79+
panic(fmt.Sprintf("%v : error creating account", err))
80+
}
81+
receipt, err := response.SetValidateStatus(true).GetReceipt(client)
82+
if err != nil {
83+
panic(fmt.Sprintf("%v : error getting account create transaction receipt", err))
84+
}
85+
fmt.Printf("Account created with hook: %v\n", receipt.AccountID)
86+
}
87+
88+
func addHookToAccount(client *hiero.Client, hookContractId *hiero.ContractID) {
89+
fmt.Println("Creating account without hook first...")
90+
91+
// Generate account private key
92+
fmt.Println("Generating account private key...")
93+
accountPrivateKey, err := hiero.PrivateKeyGenerateEd25519()
94+
if err != nil {
95+
panic(fmt.Sprintf("%v : error generating account private key", err))
96+
}
97+
accountPublicKey := accountPrivateKey.PublicKey()
98+
99+
// Create account create transaction without hook
100+
fmt.Println("Executing account create transaction...")
101+
response, err := hiero.NewAccountCreateTransaction().
102+
SetKeyWithoutAlias(accountPublicKey).
103+
Execute(client)
104+
if err != nil {
105+
panic(fmt.Sprintf("%v : error creating account", err))
106+
}
107+
receipt, err := response.SetValidateStatus(true).GetReceipt(client)
108+
if err != nil {
109+
panic(fmt.Sprintf("%v : error getting account create transaction receipt", err))
110+
}
111+
accountId := *receipt.AccountID
112+
fmt.Printf("Account created: %v\n", accountId)
113+
114+
// Create hook detail
115+
fmt.Println(" Creating hook details...")
116+
hookDetail := hiero.NewHookCreationDetails().
117+
SetExtensionPoint(hiero.ACCOUNT_ALLOWANCE_HOOK).
118+
SetHookId(1).
119+
SetLambdaEvmHook(*hiero.NewLambdaEvmHook().SetContractId(hookContractId))
120+
121+
// Create account update transaction to add hook
122+
fmt.Println("Adding hook to account via update transaction...")
123+
frozenUpdateTransaction, err := hiero.NewAccountUpdateTransaction().
124+
SetAccountID(accountId).
125+
AddHookToCreate(*hookDetail).
126+
SetMaxTransactionFee(hiero.NewHbar(15)).
127+
FreezeWith(client)
128+
if err != nil {
129+
panic(fmt.Sprintf("%v : error freezing account update transaction", err))
130+
}
131+
response, err = frozenUpdateTransaction.Sign(accountPrivateKey).Execute(client)
132+
if err != nil {
133+
panic(fmt.Sprintf("%v : error executing account update transaction", err))
134+
}
135+
_, err = response.GetReceipt(client)
136+
if err != nil {
137+
panic(fmt.Sprintf("%v : error getting account update transaction receipt", err))
138+
}
139+
fmt.Println("Hook added to account successfully!")
140+
}
141+
142+
func deleteHookFromAccount(client *hiero.Client, hookContractId *hiero.ContractID) {
143+
fmt.Println(" Creating account with hook first...")
144+
145+
// Create hook detail
146+
hookDetail := hiero.NewHookCreationDetails().
147+
SetExtensionPoint(hiero.ACCOUNT_ALLOWANCE_HOOK).
148+
SetHookId(1).
149+
SetLambdaEvmHook(*hiero.NewLambdaEvmHook().SetContractId(hookContractId))
150+
151+
// Generate account private key
152+
fmt.Println("Generating account private key...")
153+
accountPrivateKey, err := hiero.PrivateKeyGenerateEd25519()
154+
if err != nil {
155+
panic(fmt.Sprintf("%v : error generating account private key", err))
156+
}
157+
accountPublicKey := accountPrivateKey.PublicKey()
158+
159+
// Create account create transaction with hook
160+
fmt.Println("Executing account create transaction with hook...")
161+
response, err := hiero.NewAccountCreateTransaction().
162+
SetKeyWithoutAlias(accountPublicKey).
163+
AddHook(*hookDetail).
164+
SetMaxTransactionFee(hiero.NewHbar(10)).
165+
Execute(client)
166+
if err != nil {
167+
panic(fmt.Sprintf("%v : error creating account", err))
168+
}
169+
receipt, err := response.SetValidateStatus(true).GetReceipt(client)
170+
if err != nil {
171+
panic(fmt.Sprintf("%v : error getting account create transaction receipt", err))
172+
}
173+
accountId := *receipt.AccountID
174+
fmt.Printf(" Account created with hook: %v\n", accountId)
175+
176+
// Create account update transaction to delete hook
177+
fmt.Println("Deleting hook from account via update transaction...")
178+
frozenUpdateTransaction, err := hiero.NewAccountUpdateTransaction().
179+
SetAccountID(accountId).
180+
AddHookToDelete(1).
181+
SetMaxTransactionFee(hiero.NewHbar(15)).
182+
FreezeWith(client)
183+
if err != nil {
184+
panic(fmt.Sprintf("%v : error updating account", err))
185+
}
186+
response, err = frozenUpdateTransaction.Sign(accountPrivateKey).Execute(client)
187+
if err != nil {
188+
panic(fmt.Sprintf("%v : error executing account update transaction", err))
189+
}
190+
_, err = response.GetReceipt(client)
191+
if err != nil {
192+
panic(fmt.Sprintf("%v : error getting account update transaction receipt", err))
193+
}
194+
fmt.Println("Hook deleted from account successfully!")
195+
}

0 commit comments

Comments
 (0)