@@ -7,40 +7,68 @@ import (
7
7
"fmt"
8
8
"log"
9
9
"math/big"
10
+ "os"
10
11
11
12
"github.com/ethereum/go-ethereum/common"
12
13
"github.com/ethereum/go-ethereum/common/hexutil"
13
14
"github.com/ethereum/go-ethereum/core/types"
14
15
"github.com/ethereum/go-ethereum/crypto"
16
+ "github.com/ethereum/go-ethereum/ethclient"
17
+ "github.com/gofrs/uuid"
18
+ "github.com/joho/godotenv"
19
+ "github.com/node-real/megafuel-go-sdk/pkg/paymasterclient"
20
+ "github.com/node-real/megafuel-go-sdk/pkg/sponsorclient"
15
21
)
16
22
17
- const TokenContractAddress = "0x.."
18
- const WithdrawRecipientAddress = "0x.."
19
- const SponsorPolicyId = ".."
20
- const HotwalletPrivateKey = ".."
23
+ var (
24
+ PaymasterURL string
25
+ ChainURL string
26
+ SponsorURL string
21
27
22
- const sponsorAPIEndpoint = "https://open-platform.nodereal.io/{Your_API_key}/megafuel"
23
- const paymasterEndpoint = "https://bsc-megafuel.nodereal.io"
28
+ PolicyUUID uuid.UUID
24
29
25
- // testnet endpoint
26
- // const sponsorAPIEndpoint = "https://open-platform.nodereal.io/{Your_API_key}/megafuel-testnet"
27
- // const paymasterEndpoint = "https://bsc-megafuel-testnet.nodereal.io'"
30
+ TokenContractAddress common.Address
31
+ WithdrawRecipientAddress common.Address
32
+ HotwalletPrivateKey string
33
+ )
34
+
35
+ func init () {
36
+ err := godotenv .Load (".env" )
37
+
38
+ if err != nil {
39
+ log .Fatalf ("Error loading .env file" )
40
+ }
41
+
42
+ PaymasterURL = os .Getenv ("PAYMASTER_URL" )
43
+ ChainURL = os .Getenv ("CHAIN_URL" )
44
+ SponsorURL = os .Getenv ("SPONSOR_URL" )
45
+
46
+ PolicyUUID , err = uuid .FromString (os .Getenv ("POLICY_UUID" ))
47
+ if err != nil {
48
+ log .Fatalf ("Error parsing POLICY_UUID" )
49
+ }
50
+
51
+ TokenContractAddress = common .HexToAddress (os .Getenv ("TOKEN_CONTRACT_ADDRESS" ))
52
+ WithdrawRecipientAddress = common .HexToAddress (os .Getenv ("WITHDRAW_RECIPIENT_ADDRESS" ))
53
+ HotwalletPrivateKey = os .Getenv ("HOTWALLET_PRIVATE_KEY" )
54
+ }
28
55
29
56
func main () {
30
57
sponsorSetUpPolicyRules ()
31
58
cexDoGaslessWithdrawl ()
32
59
}
33
60
34
61
func sponsorSetUpPolicyRules () {
35
- sponsorClient , err := NewSponsorClient ( sponsorAPIEndpoint )
62
+ sponsorClient , err := sponsorclient . New ( context . Background (), SponsorURL )
36
63
if err != nil {
37
64
log .Fatal (err )
38
65
}
66
+
39
67
// sponsor the tx that interact with the stable coin ERC20 contract
40
- success , err := sponsorClient .AddToWhitelist (context .Background (), WhitelistParams {
41
- PolicyUUID : SponsorPolicyId ,
42
- WhitelistType : ToAccountWhitelist ,
43
- Values : []string {TokenContractAddress },
68
+ success , err := sponsorClient .AddToWhitelist (context .Background (), sponsorclient. WhiteListArgs {
69
+ PolicyUUID : PolicyUUID ,
70
+ WhitelistType : sponsorclient . ToAccountWhitelist ,
71
+ Values : []string {TokenContractAddress . String () },
44
72
})
45
73
if err != nil || ! success {
46
74
log .Fatal ("failed to add token contract whitelist" , err )
@@ -49,9 +77,9 @@ func sponsorSetUpPolicyRules() {
49
77
// sponsor the tx that from hotwallets
50
78
fromAddress := getAddressFromPrivateKey (HotwalletPrivateKey )
51
79
52
- success , err = sponsorClient .AddToWhitelist (context .Background (), WhitelistParams {
53
- PolicyUUID : SponsorPolicyId ,
54
- WhitelistType : FromAccountWhitelist ,
80
+ success , err = sponsorClient .AddToWhitelist (context .Background (), sponsorclient. WhiteListArgs {
81
+ PolicyUUID : PolicyUUID ,
82
+ WhitelistType : sponsorclient . FromAccountWhitelist ,
55
83
Values : []string {fromAddress .String ()},
56
84
})
57
85
if err != nil || ! success {
@@ -61,8 +89,14 @@ func sponsorSetUpPolicyRules() {
61
89
62
90
func cexDoGaslessWithdrawl () {
63
91
withdrawAmount := big .NewInt (1e17 )
92
+ // Connect to an Ethereum node (for transaction assembly)
93
+ client , err := ethclient .Dial (ChainURL )
94
+ if err != nil {
95
+ log .Fatalf ("Failed to connect to the Ethereum network: %v" , err )
96
+ }
97
+
64
98
// Create a PaymasterClient (for transaction sending)
65
- paymasterClient , err := NewPaymasterClient ( paymasterEndpoint )
99
+ paymasterClient , err := paymasterclient . New ( context . Background (), PaymasterURL )
66
100
if err != nil {
67
101
log .Fatalf ("Failed to create PaymasterClient: %v" , err )
68
102
}
@@ -75,28 +109,24 @@ func cexDoGaslessWithdrawl() {
75
109
76
110
fromAddress := getAddressFromPrivateKey (HotwalletPrivateKey )
77
111
78
- // Token contract address
79
- tokenAddress := common .HexToAddress (TokenContractAddress )
80
-
81
112
// Create ERC20 transfer data
82
- data , err := createERC20TransferData (common . HexToAddress ( WithdrawRecipientAddress ) , withdrawAmount )
113
+ data , err := createERC20TransferData (WithdrawRecipientAddress , withdrawAmount )
83
114
if err != nil {
84
115
log .Fatalf ("Failed to create ERC20 transfer data: %v" , err )
85
116
}
86
117
87
- // Get the pending nonce for the from address, strongly suggest to fetch nonce from paymaster endpoint when
88
- // submitting multiple transactions in rapid succession, to ensure that the nonce are sequential.
89
- nonce , err := paymasterClient .PendingNonceAt (context .Background (), fromAddress )
118
+ // Get the latest nonce for the from address
119
+ nonce , err := client .PendingNonceAt (context .Background (), fromAddress )
90
120
if err != nil {
91
121
log .Fatalf ("Failed to get nonce: %v" , err )
92
122
}
93
123
94
124
// Create the transaction
95
125
gasPrice := big .NewInt (0 )
96
- tx := types .NewTransaction (nonce , tokenAddress , big .NewInt (0 ), 300000 , gasPrice , data )
126
+ tx := types .NewTransaction (nonce , TokenContractAddress , big .NewInt (0 ), 300000 , gasPrice , data )
97
127
98
128
// Get the chain ID
99
- chainID , err := paymasterClient .ChainID (context .Background ())
129
+ chainID , err := client .ChainID (context .Background ())
100
130
if err != nil {
101
131
log .Fatalf ("Failed to get chain ID: %v" , err )
102
132
}
@@ -107,10 +137,15 @@ func cexDoGaslessWithdrawl() {
107
137
log .Fatalf ("Failed to sign transaction: %v" , err )
108
138
}
109
139
140
+ txInput , err := signedTx .MarshalBinary ()
141
+ if err != nil {
142
+ log .Fatalf ("Failed to marshal transaction: %v" , err )
143
+ }
144
+
110
145
// Convert to Transaction struct for IsSponsorable check
111
146
gasLimit := tx .Gas ()
112
- sponsorableTx := Transaction {
113
- To : & tokenAddress ,
147
+ sponsorableTx := paymasterclient. TransactionArgs {
148
+ To : & TokenContractAddress ,
114
149
From : fromAddress ,
115
150
Value : (* hexutil .Big )(big .NewInt (0 )),
116
151
Gas : (* hexutil .Uint64 )(& gasLimit ),
@@ -128,7 +163,7 @@ func cexDoGaslessWithdrawl() {
128
163
129
164
if sponsorableInfo .Sponsorable {
130
165
// Send the transaction using PaymasterClient
131
- err := paymasterClient .SendTransaction (context .Background (), signedTx )
166
+ _ , err := paymasterClient .SendRawTransaction (context .Background (), txInput )
132
167
if err != nil {
133
168
log .Fatalf ("Failed to send sponsorable transaction: %v" , err )
134
169
}
@@ -152,3 +187,16 @@ func getAddressFromPrivateKey(pk string) common.Address {
152
187
}
153
188
return crypto .PubkeyToAddress (* publicKeyECDSA )
154
189
}
190
+
191
+ func createERC20TransferData (to common.Address , amount * big.Int ) ([]byte , error ) {
192
+ transferFnSignature := []byte ("transfer(address,uint256)" )
193
+ methodID := crypto .Keccak256 (transferFnSignature )[:4 ]
194
+ paddedAddress := common .LeftPadBytes (to .Bytes (), 32 )
195
+ paddedAmount := common .LeftPadBytes (amount .Bytes (), 32 )
196
+
197
+ var data []byte
198
+ data = append (data , methodID ... )
199
+ data = append (data , paddedAddress ... )
200
+ data = append (data , paddedAmount ... )
201
+ return data , nil
202
+ }
0 commit comments