Skip to content

Commit b50ad6b

Browse files
committed
Add batch-transfer example app for TypeScript and Go
Demonstrates sending N APT transfers in parallel using the key pattern of fetching the sender's sequence number once and incrementing locally, avoiding N network round-trips and enabling true parallel submission. Features shown: - Account generation and faucet funding - Gas price estimation - Sequence number pre-fetching (fetch once, increment locally) - Local build + sign before any network submission - Parallel dispatch (Promise.allSettled / goroutines + WaitGroup) - Exponential backoff retry on confirmation - Structured JSON summary output for cross-SDK comparison CLI: --count N --network devnet|testnet|mainnet (default: devnet, 10 txs)
1 parent b69b190 commit b50ad6b

File tree

9 files changed

+962
-0
lines changed

9 files changed

+962
-0
lines changed

examples/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Aptos SDK Examples
2+
3+
Standalone sample applications that demonstrate Aptos SDK features across multiple languages.
4+
Each example is self-contained, runnable, and designed to be a starting point you can expand.
5+
6+
## Examples
7+
8+
| Example | Description | Languages |
9+
| ------- | ----------- | --------- |
10+
| [batch-transfer](./batch-transfer/) | Send N transactions in parallel with retry | TypeScript, Go |
11+
12+
## Design Principles
13+
14+
Each example:
15+
16+
- **Runs end-to-end** against devnet (no mocks)
17+
- **Shows real patterns** (sequence number management, gas estimation, retry)
18+
- **Has configurable parameters** (transaction count, network)
19+
- **Produces structured output** (JSON summary for easy comparison across SDKs)
20+
21+
## Adding a New Example
22+
23+
1. Create `examples/<name>/` directory
24+
2. Add `examples/<name>/README.md` explaining the scenario
25+
3. Implement in each target language under `examples/<name>/<language>/`
26+
4. Each language directory must be runnable with a single command
27+
28+
## Adding a New Language to an Existing Example
29+
30+
1. Create `examples/<name>/<language>/`
31+
2. Follow the same 4-phase structure: Setup → Batch Submit → Track & Confirm → Verify & Report
32+
3. Use the same CLI flags (`--count`, `--network`) for consistency
33+
4. Output the same JSON summary schema for cross-SDK comparison

examples/batch-transfer/README.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Batch Transfer Example
2+
3+
Demonstrates sending **N APT transfers in parallel** using a single funded sender account.
4+
5+
This example showcases:
6+
7+
- Account generation and faucet funding
8+
- Gas price estimation
9+
- **Sequence number pre-fetching** — fetch once, increment locally (avoids N round-trips)
10+
- Building and signing all transactions **locally** before any network calls
11+
- Parallel submission via goroutines / Promise.allSettled
12+
- Retry with exponential backoff on confirmation
13+
- Structured JSON output for cross-SDK comparison
14+
15+
## The Core Pattern: Sequence Number Management
16+
17+
The naive approach to batch transactions fetches the account's sequence number *per transaction*:
18+
19+
```
20+
for each tx:
21+
fetch seq_num from chain ← N network round-trips!
22+
build tx with seq_num
23+
submit
24+
```
25+
26+
This example uses the efficient approach:
27+
28+
```
29+
fetch seq_num from chain once
30+
for each tx (local, no network):
31+
build tx with (seq_num + i)
32+
sign tx
33+
submit all in parallel
34+
```
35+
36+
This reduces N round-trips to 1 and enables true parallel submission.
37+
38+
## Implementations
39+
40+
| Language | Directory | Command |
41+
| -------- | --------- | ------- |
42+
| TypeScript | [typescript/](./typescript/) | `bun src/main.ts` |
43+
| Go | [go/](./go/) | `go run main.go` |
44+
45+
## Expected Output
46+
47+
```
48+
Aptos Batch Transfer Example (TypeScript)
49+
==========================================
50+
Network: devnet
51+
Transactions: 10
52+
53+
[1/4] Setup
54+
✓ Generated sender: 0x3f2a...
55+
✓ Generated 10 recipient accounts
56+
✓ Funded sender with 1 APT (tx: 0xabc...)
57+
✓ Sender balance: 100,000,000 octas
58+
59+
[2/4] Batch Submission (10 transactions)
60+
✓ Gas price estimate: 100 octas/gas
61+
✓ Starting sequence number: 1
62+
✓ Built & signed 10 transactions locally in 45ms
63+
✓ Submitted 10/10 in 312ms
64+
65+
[3/4] Tracking Confirmations
66+
✓ Confirmed: 10/10
67+
68+
[4/4] Verify & Report
69+
✓ Final balance: 99,978,000 octas
70+
✓ Total spent (transfers + gas): 22,000 octas
71+
72+
=== Summary ===
73+
{
74+
"network": "devnet",
75+
"timestamp": "2026-02-21T12:00:00Z",
76+
"transactions": {
77+
"requested": 10,
78+
"submitted": 10,
79+
"confirmed": 10,
80+
"failed": 0
81+
},
82+
"performance": {
83+
"build_and_sign_ms": 45,
84+
"submit_ms": 312
85+
},
86+
"economics": {
87+
"initial_balance_octas": 100000000,
88+
"final_balance_octas": 99978000,
89+
"total_spent_octas": 22000,
90+
"avg_cost_per_tx_octas": 2200
91+
}
92+
}
93+
```
94+
95+
## CLI Options
96+
97+
```
98+
--count N Number of transactions to send (default: 10)
99+
--network NAME Network: devnet, testnet, or mainnet (default: devnet)
100+
```
101+
102+
## Extending This Example
103+
104+
This is intentionally simple to serve as a starting point. Consider adding:
105+
106+
- **Simulate before submit**: Call the simulation API to get exact gas estimates
107+
- **Retry on sequence number error**: Refetch and rebuild if a tx is rejected for invalid seq num
108+
- **Concurrent senders**: Split N transactions across M sender accounts for higher throughput
109+
- **Token transfers**: Replace APT coin transfers with fungible asset or NFT transfers
110+
- **Wait strategies**: Implement polling vs. long-poll vs. webhook confirmation patterns

examples/batch-transfer/go/go.mod

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module github.com/aptos-labs/aptos-sdk-examples/batch-transfer
2+
3+
go 1.24.0
4+
5+
require github.com/aptos-labs/aptos-go-sdk v1.11.0
6+
7+
require (
8+
filippo.io/edwards25519 v1.1.0 // indirect
9+
github.com/coder/websocket v1.8.14 // indirect
10+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
11+
github.com/google/uuid v1.6.0 // indirect
12+
github.com/hasura/go-graphql-client v0.14.4 // indirect
13+
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
14+
golang.org/x/crypto v0.42.0 // indirect
15+
golang.org/x/sys v0.38.0 // indirect
16+
)

examples/batch-transfer/go/go.sum

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
2+
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
3+
github.com/aptos-labs/aptos-go-sdk v1.11.0 h1:vIL1hpjECUiu7zMl9Wz6VV8ttXsrDqKUj0HxoeaIER4=
4+
github.com/aptos-labs/aptos-go-sdk v1.11.0/go.mod h1:8YvYwRg93UcG6pTStCpZdYiscCtKh51sYfeLgIy/41c=
5+
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
6+
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
7+
github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI=
8+
github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0=
9+
github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI=
10+
github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8=
11+
github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI=
12+
github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s=
13+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
14+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
15+
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
16+
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
17+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
18+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
19+
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
20+
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
21+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
22+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
23+
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
24+
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
25+
github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo=
26+
github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y=
27+
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
28+
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
29+
github.com/hasura/go-graphql-client v0.14.4 h1:bYU7/+V50T2YBGdNQXt6l4f2cMZPECPUd8cyCR+ixtw=
30+
github.com/hasura/go-graphql-client v0.14.4/go.mod h1:jfSZtBER3or+88Q9vFhWHiFMPppfYILRyl+0zsgPIIw=
31+
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
32+
github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
33+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
34+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
35+
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
36+
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
37+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
38+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
39+
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
40+
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
41+
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
42+
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
43+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
44+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)