package main
import (
"context"
"encoding/json"
"fmt"
"io"
"math/big"
"net/http"
"net/url"
"os"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
)
const (
baseURL = "https://api.paxoslabs.com"
vaultAddress = "0xbbbb000000000000000000000000000000000001"
withdrawQueue = "0xdddd000000000000000000000000000000000001"
wantAsset = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
chainID = 1
shareAmount = "1000000000000000000"
)
func apiGet(path string, params url.Values) (map[string]interface{}, error) {
u := fmt.Sprintf("%s%s?%s", baseURL, path, params.Encode())
req, _ := http.NewRequest("GET", u, nil)
req.Header.Set("x-api-key", os.Getenv("AMPLIFY_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil { return nil, err }
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(body, &result)
return result, nil
}
func main() {
pk, _ := crypto.HexToECDSA(os.Getenv("PRIVATE_KEY"))
fromAddr := crypto.PubkeyToAddress(pk.PublicKey)
client, _ := ethclient.Dial("https://eth.llamarpc.com")
ctx := context.Background()
signer := types.NewEIP155Signer(big.NewInt(chainID))
// Step 1: Approve share spending
fmt.Println("Approving share spending...")
erc20ABI, _ := abi.JSON(strings.NewReader(
`[{"inputs":[{"name":"spender","type":"address"},` +
`{"name":"amount","type":"uint256"}],` +
`"name":"approve","outputs":[{"type":"bool"}],"type":"function"}]`))
amt := new(big.Int)
amt.SetString(shareAmount, 10)
approveData, _ := erc20ABI.Pack("approve", common.HexToAddress(withdrawQueue), amt)
nonce, _ := client.PendingNonceAt(ctx, fromAddr)
gasPrice, _ := client.SuggestGasPrice(ctx)
approveTx := types.NewTransaction(nonce, common.HexToAddress(vaultAddress),
big.NewInt(0), 60000, gasPrice, approveData)
signedApprove, _ := types.SignTx(approveTx, signer, pk)
client.SendTransaction(ctx, signedApprove)
fmt.Printf("Approval submitted: %s\n", signedApprove.Hash().Hex())
// Wait for approval receipt before requesting withdrawal calldata —
// otherwise the withdrawal can race ahead of the allowance.
if _, err := bind.WaitMined(ctx, client, signedApprove); err != nil {
panic(err)
}
fmt.Println("Approval confirmed")
// Step 2: Get withdrawal calldata
fmt.Println("Fetching withdrawal calldata...")
withdrawResp, _ := apiGet("/v2/amplify/withdraw", url.Values{
"vaultAddress": {vaultAddress},
"wantAsset": {wantAsset},
"shareAmount": {shareAmount},
"userAddress": {fromAddr.Hex()},
"chainId": {fmt.Sprint(chainID)},
})
txData := withdrawResp["transaction"].(map[string]interface{})
// Step 3: Sign and submit
fmt.Println("Submitting withdrawal order...")
nonce, _ = client.PendingNonceAt(ctx, fromAddr)
gasPrice, _ = client.SuggestGasPrice(ctx)
withdrawTx := types.NewTransaction(nonce,
common.HexToAddress(txData["to"].(string)),
big.NewInt(0), 300000, gasPrice,
common.FromHex(txData["data"].(string)))
signedWithdraw, _ := types.SignTx(withdrawTx, signer, pk)
client.SendTransaction(ctx, signedWithdraw)
fmt.Printf("Withdrawal submitted: %s\n", signedWithdraw.Hash().Hex())
}