Storm Trade
EN
EnglishРусскийNot available
Menu
On this page

🐹 Go SDK

github.com/storm-trade/sdk-go covers both trading paths. The storm package drives v3: it builds and signs intents, submits them to the sequencer, and manages Smart Account deposits and withdrawals. The stormv2 package drives v2 with direct wallet transactions and appends the executor fee automatically.

go get github.com/storm-trade/sdk-go
PackagePurpose
configNetworks, markets, assets, Direction
stormv3 client: Smart Account plus sequencer
stormv2v2 client: direct wallet transactions
sequencerTrading API (V3) REST client
oracleSigned oracle prices, used by v2 margin operations
client/vamm, client/vault, client/smartaccount, client/positionmanagerOn-chain reads and Smart Account operations
tlb, contractsOrder types, position state, error codes, TL-B schemas

⚑ v3: Smart Account and Intents

Set up

ctx := context.Background()
 
pool := liteclient.NewConnectionPool()
pool.AddConnectionsFromConfigUrl(ctx, "https://ton-blockchain.github.io/testnet-global.config.json")
api := ton.NewAPIClient(pool, ton.ProofCheckPolicyUnsafe).WithRetry(10)
 
w, _ := wallet.FromSeed(api, strings.Split(seedPhrase, " "), wallet.V4R2)
 
factory := smartaccount.NewFactory(api, address.MustParseAddr(config.Networks[config.Testnet].FactoryAddress))
saAddr, _ := factory.GetSmartAccountAddress(ctx, w.WalletAddress())
 
client := storm.NewClient(config.Testnet,
    storm.WithTONApi(api),
    storm.WithWallet(w),
    storm.WithSmartAccount(saAddr),
    storm.WithSigner(ed25519.PrivateKey(signingKey)),
    storm.WithClockSkew(5*time.Second),
)

The signing key is an ED25519 key registered on the Smart Account. It is separate from the TON wallet key: the wallet pays for deposits and withdrawals, the signing key authorizes intents.

First deposit

The first deposit deploys the Smart Account and registers the signing key in one go. Amounts use the asset's own decimals.

amount := tlb.MustFromDecimal("100", 6) // 100 USDT
client.Deposit(ctx, "USDT", &amount, storm.WithInit(), storm.WithPublicKey(pubKey))
 
// later
client.Deposit(ctx, "USDT", &amount)
client.Withdraw(ctx, "USDT", &amount)

Passing a public key without WithInit() on an existing account fails with contract error 115. Use client.AddPublicKey(ctx) to register an extra key later.

Orders

Order amounts and sizes use 9 decimals, leverage is scaled by 10^9.

btc, _ := client.Market("BTC", "USDT")
amount := tlb.MustFromDecimal("100", 9)
 
// Market order with SL/TP attached as extra intents
sl := tlb.MustFromTON("60000")
tp := tlb.MustFromTON("80000")
res, err := client.PlaceMarketOrder(ctx, btc, config.Long, &amount, 3_000_000_000,
    storm.WithStopLoss(&sl), storm.WithTakeProfit(&tp))
 
// Limit and stop-limit
limit := tlb.MustFromTON("65000")
res, _ = client.PlaceLimitOrder(ctx, btc, config.Long, &amount, 3_000_000_000, &limit)
stop := tlb.MustFromTON("64000")
res, _ = client.PlaceStopLimitOrder(ctx, btc, config.Long, &amount, 3_000_000_000, &limit, &stop)
 
// Cancel by hash from the result
client.CancelOrder(ctx, res.OrderHash)

Every order call returns *PlaceOrderResult with QueryID, OrderHash, the ids and hashes of attached SL/TP, and the raw sequencer response including the emulation trace. OrderHash is what you pass to CancelOrder and to GET /intent/{hash}.

Positions

size := tlb.MustFromDecimal("0.001", 9)
client.ClosePosition(ctx, btc, config.Long, &size)
client.ClosePositionFull(ctx, btc, config.Long) // reads the size on-chain
 
trigger := tlb.MustFromTON("60000")
client.PlaceStopLoss(ctx, btc, config.Long, &size, &trigger)
client.PlaceTakeProfit(ctx, btc, config.Long, &size, &trigger)
 
margin := tlb.MustFromDecimal("50", 9)
client.AddMargin(ctx, btc, config.Long, &margin)
client.RemoveMargin(ctx, btc, config.Long, &margin)

Options worth knowing

OptionEffect
WithClockSkew(5*time.Second)Compensates local clock drift in intent expirations. Recommended
WithGasless()Gasless execution mode
WithExpiration(ts)Custom intent expiration, Unix seconds
WithQueryID(id)Override the query id. The client tracks it for you otherwise

Reading state

seq := sequencer.NewClient(sequencer.TestnetURL)
state, _ := seq.GetAccountState(ctx, saAddr)
balances, _ := seq.GetBalances(ctx, saAddr)
positions, _ := seq.GetPositions(ctx, saAddr)
intent, _ := seq.GetIntent(ctx, res.OrderHash)
status, _ := seq.GetStatus(ctx)
 
spot, _ := client.GetSpotPrice(ctx, btc)
amm, _ := client.GetAmmState(ctx, btc)
vault, _ := client.GetVaultData(ctx, "USDT")

πŸ” v2: Direct Wallet Transactions

client := stormv2.NewClient(config.Testnet,
    stormv2.WithWallet(w),
    stormv2.WithTONApi(api),
)
 
btc, _ := client.Market("BTC", "USDT")
amount := tlb.MustFromDecimal("10", 6) // collateral decimals: 6 for USDT
 
res, _ := client.PlaceMarketOrder(ctx, btc, config.Long, &amount, 3_000_000_000,
    stormv2.WithStopLoss(&sl), stormv2.WithTakeProfit(&tp), stormv2.WithReferralID(123))
fmt.Println(res.Hash) // TON transaction hash
 
// Cancel by order type and index: 0 SL, 1 TP, 2 limit, 3 market
client.CancelOrder(ctx, btc, config.Long, 2, 0)

Differences from v3 that matter in code:

v3 stormv2 stormv2
ResultIntent hash, sequencer responseTON transaction hash
CancelBy order hashBy order type and index
Amounts9 decimalsCollateral decimals
Oracle dataInjected by the sequencerFetched by the SDK for margin operations
Executor feeNot neededAppended as a second message

πŸ§ͺ CLI

The repository ships a CLI that exercises every call above. It is the quickest way to check your keys and environment before writing code.

export STORM_SEED="word1 word2 ... word24"
export STORM_PRIVATE_KEY=<ed25519 hex>   # v3 only
export STORM_NETWORK=testnet             # or mainnet
 
go run ./cmd/example keygen
go run ./cmd/example deposit TON 0.5 --init
go run ./cmd/example order market BTC USDT long 100 3 --sl=60000 --tp=80000
go run ./cmd/example positions
go run ./cmd/example close-all BTC USDT long
 
go run ./cmd/v2example order limit BTC USDT long 10 3 --limit=60000
go run ./cmd/v2example orders BTC USDT long
Last updated