Skip to content

Commit a8e2f7f

Browse files
Add transfer service (#286)
* add transfer service * fix comment * fix comments and requests * fix comments * update index.mdx for transfer api * update comment * add documentation * add description and include in ledger fields and update docs * add validation and fix comment
1 parent 859b7b4 commit a8e2f7f

33 files changed

Lines changed: 2875 additions & 2 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
sidebar_position: 1
3+
---
4+
5+
# Wallet Transfer v1 Service
6+
7+
#### Skip The Details?
8+
- 👉 Jump to **[Package Types](/docs/api-reference/wallet/transfer/v1/type)**
9+
- 👉 Jump to **[Service Methods](/docs/api-reference/wallet/transfer/v1/service)**
10+
11+
{/*
12+
Generated by protoc-gen-meshdoc the first time.
13+
-> This file can be edited manually to add information about the Wallet Transfer Service.
14+
15+
THIS COMMENT AND EVERYTHING ABOVE IT IS AUTOGENERATED
16+
*/}
17+
18+
## Overview
19+
20+
The **TransferService** manages asset transfers between accounts on the same ledger network. This service handles the full lifecycle of a transfer, from creation through on-chain execution, including fee calculation and state tracking.
21+
22+
Transfers are the primary mechanism for moving assets between accounts on the Mesh platform. Each transfer is:
23+
- **Ledger-bound**: Both the source and destination accounts must be on the same ledger network
24+
- **Fee-aware**: Transfer fees and VAT are automatically calculated
25+
- **State-tracked**: Transfers progress through defined states (in progress, successful, failed)
26+
- **Hierarchically scoped**: Owned by a group within your organizational hierarchy
27+
- **Monitorable**: Real-time streaming updates as transfer state changes
28+
29+
## Common Workflows
30+
31+
### Basic Transfer
32+
33+
1. **Create Transfer** - Initiate a transfer specifying source address, destination address, and amount
34+
2. **Monitor Transfer** - Subscribe to real-time state updates via streaming
35+
3. **Verify Completion** - Confirm the transfer reached `TRANSFER_STATE_SUCCESSFUL`
36+
37+
### Transfer Auditing
38+
39+
1. **List Transfers** - Retrieve all transfers within your group hierarchy
40+
2. **Search by Address** - Find all transfers involving a specific ledger address
41+
3. **Get Transfer** - Retrieve details of a specific transfer by resource name
42+
43+
## Key Concepts
44+
45+
### Transfer States
46+
47+
Transfers progress through the following states:
48+
49+
| State | Description |
50+
|-------|-------------|
51+
| `TRANSFER_STATE_IN_PROGRESS` | Transfer has been submitted and is being processed on-chain |
52+
| `TRANSFER_STATE_SUCCESSFUL` | Transfer completed successfully on the ledger |
53+
| `TRANSFER_STATE_FAILED` | Transfer failed during on-chain execution |
54+
55+
### Ledger Addresses
56+
57+
The `from` and `to` fields use ledger-native addresses. Both addresses must be on the same ledger network. The address format determines which ledger the transfer executes on:
58+
59+
| Ledger | Address Format |
60+
|--------|----------------|
61+
| **Stellar** | Ed25519 public key |
62+
| **Solana** | Ed25519 public key |
63+
64+
### Transfer Description
65+
66+
Transfers support an optional `description` field to record the reason for the transfer. When `include_in_ledger` is set to `true`, the description will be included in the on-chain ledger transaction, making it visible on the blockchain.
67+
68+
### Transfer Fees
69+
70+
Each transfer includes a `TransferFee` containing:
71+
- **amount** - The calculated fee charged for the transfer
72+
- **vat_rate** - The VAT rate applied to the fee calculation
73+
74+
Fees are calculated automatically by the system during transfer creation.
75+
76+
### Transfer Numbers
77+
78+
Each transfer receives a unique, monotonically increasing number that serves as a human-readable identifier. This number is system-generated and immutable.
79+
80+
## Authentication & Authorization
81+
82+
The TransferService uses role-based access control:
83+
84+
### Write Operations
85+
Require `ROLE_WALLET_ADMIN` or `ROLE_WALLET_TRANSFER_ADMIN`:
86+
- CreateTransfer
87+
88+
### Read Operations
89+
Require any wallet role (`ADMIN` or `VIEWER` variants):
90+
- GetTransfer
91+
- ListTransfers
92+
- SearchTransfersByAddress
93+
- MonitorTransfer
94+
95+
All operations are scoped to your group's hierarchy - you can only access transfers owned by your group or its descendants.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"log"
6+
7+
typev1 "github.com/meshtrade/api/go/type/v1"
8+
transferv1 "github.com/meshtrade/api/go/wallet/transfer/v1"
9+
)
10+
11+
func main() {
12+
ctx := context.Background()
13+
14+
// Default configuration is used and credentials come from MESH_API_CREDENTIALS
15+
// environment variable or default discovery methods. Zero config required
16+
// unless you want custom configuration.
17+
service, err := transferv1.NewTransferService()
18+
if err != nil {
19+
log.Fatalf("Failed to create service: %v", err)
20+
}
21+
defer service.Close()
22+
23+
// Create request with transfer details
24+
request := &transferv1.CreateTransferRequest{
25+
Transfer: &transferv1.Transfer{
26+
Owner: service.Group(), // Current group from service context
27+
From: "GBZH4LMGAYUDNFPNFGOBKU76DDRJHIAKGKGO2LNZFLQB6DMKV7EYHT", // Source ledger address
28+
To: "GCWNBLOHV5DKRG5UXKMO5IDAJLVSRRPGZJ5REWQPCT2LGXVQZQGWE3F", // Destination ledger address
29+
Amount: &typev1.Amount{
30+
Token: &typev1.Token{
31+
Code: "USDC",
32+
Issuer: "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
33+
Ledger: typev1.Ledger_LEDGER_STELLAR,
34+
},
35+
Value: &typev1.Decimal{Value: "100.50"},
36+
},
37+
Description: "Payment for invoice #1234", // Optional reason for the transfer
38+
IncludeInLedger: true, // Include description in on-chain transaction
39+
},
40+
}
41+
42+
// Call the CreateTransfer method
43+
transfer, err := service.CreateTransfer(ctx, request)
44+
if err != nil {
45+
log.Fatalf("CreateTransfer failed: %v", err)
46+
}
47+
48+
// Transfer has been created and submitted on-chain
49+
log.Printf("Transfer created successfully:")
50+
log.Printf(" Name: %s", transfer.Name)
51+
log.Printf(" Number: %s", transfer.Number)
52+
log.Printf(" State: %s", transfer.State)
53+
log.Printf(" Fee: %s", transfer.Fee.Amount.Value)
54+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import co.meshtrade.api.type.v1.Amount.Amount;
2+
import co.meshtrade.api.type.v1.Decimal.Decimal;
3+
import co.meshtrade.api.type.v1.Ledger;
4+
import co.meshtrade.api.type.v1.Type.Token;
5+
import co.meshtrade.api.wallet.transfer.v1.TransferService;
6+
import co.meshtrade.api.wallet.transfer.v1.Service.CreateTransferRequest;
7+
import co.meshtrade.api.wallet.transfer.v1.Transfer.Transfer;
8+
9+
import java.util.Optional;
10+
11+
public class CreateTransferExample {
12+
public static void main(String[] args) {
13+
// Default configuration is used and credentials come from MESH_API_CREDENTIALS
14+
// environment variable or default discovery methods. Zero config required
15+
// unless you want custom configuration.
16+
try (TransferService service = new TransferService()) {
17+
// Create request with transfer details
18+
CreateTransferRequest request = CreateTransferRequest.newBuilder()
19+
.setTransfer(Transfer.newBuilder()
20+
.setOwner(service.group()) // Current group from service context
21+
.setFrom("GBZH4LMGAYUDNFPNFGOBKU76DDRJHIAKGKGO2LNZFLQB6DMKV7EYHT") // Source ledger address
22+
.setTo("GCWNBLOHV5DKRG5UXKMO5IDAJLVSRRPGZJ5REWQPCT2LGXVQZQGWE3F") // Destination ledger address
23+
.setAmount(Amount.newBuilder()
24+
.setToken(Token.newBuilder()
25+
.setCode("USDC")
26+
.setIssuer("GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN")
27+
.setLedger(Ledger.LEDGER_STELLAR)
28+
.build())
29+
.setValue(Decimal.newBuilder()
30+
.setValue("100.50")
31+
.build())
32+
.build())
33+
.setDescription("Payment for invoice #1234") // Optional reason for the transfer
34+
.setIncludeInLedger(true) // Include description in on-chain transaction
35+
.build())
36+
.build();
37+
38+
// Call the CreateTransfer method
39+
Transfer transfer = service.createTransfer(request, Optional.empty());
40+
41+
// Transfer has been created and submitted on-chain
42+
System.out.println("Transfer created successfully:");
43+
System.out.println(" Name: " + transfer.getName());
44+
System.out.println(" Number: " + transfer.getNumber());
45+
System.out.println(" State: " + transfer.getState());
46+
System.out.println(" Fee: " + transfer.getFee().getAmount().getValue());
47+
} catch (Exception e) {
48+
System.err.println("CreateTransfer failed: " + e.getMessage());
49+
e.printStackTrace();
50+
}
51+
}
52+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from meshtrade.type.v1 import Amount, Decimal, Ledger, Token
2+
from meshtrade.wallet.transfer.v1 import (
3+
CreateTransferRequest,
4+
Transfer,
5+
TransferService,
6+
)
7+
8+
9+
def main():
10+
# Default configuration is used and credentials come from MESH_API_CREDENTIALS
11+
# environment variable or default discovery methods. Zero config required
12+
# unless you want custom configuration.
13+
service = TransferService()
14+
15+
with service:
16+
# Create request with transfer details
17+
request = CreateTransferRequest(
18+
transfer=Transfer(
19+
owner=service.group(), # Current group from service context
20+
from_="GBZH4LMGAYUDNFPNFGOBKU76DDRJHIAKGKGO2LNZFLQB6DMKV7EYHT", # Source ledger address
21+
to="GCWNBLOHV5DKRG5UXKMO5IDAJLVSRRPGZJ5REWQPCT2LGXVQZQGWE3F", # Destination ledger address
22+
amount=Amount(
23+
token=Token(
24+
code="USDC",
25+
issuer="GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
26+
ledger=Ledger.LEDGER_STELLAR,
27+
),
28+
value=Decimal(value="100.50"),
29+
),
30+
description="Payment for invoice #1234", # Optional reason for the transfer
31+
include_in_ledger=True, # Include description in on-chain transaction
32+
)
33+
)
34+
35+
# Call the CreateTransfer method
36+
transfer = service.create_transfer(request)
37+
38+
# Transfer has been created and submitted on-chain
39+
print("Transfer created successfully:")
40+
print(f" Name: {transfer.name}")
41+
print(f" Number: {transfer.number}")
42+
print(f" State: {transfer.state}")
43+
print(f" Fee: {transfer.fee.amount.value}")
44+
45+
46+
if __name__ == "__main__":
47+
main()
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"log"
6+
7+
transferv1 "github.com/meshtrade/api/go/wallet/transfer/v1"
8+
)
9+
10+
func main() {
11+
ctx := context.Background()
12+
13+
// Default configuration is used and credentials come from MESH_API_CREDENTIALS
14+
// environment variable or default discovery methods. Zero config required
15+
// unless you want custom configuration.
16+
service, err := transferv1.NewTransferService()
17+
if err != nil {
18+
log.Fatalf("Failed to create service: %v", err)
19+
}
20+
defer service.Close()
21+
22+
// Create request with the transfer resource name
23+
request := &transferv1.GetTransferRequest{
24+
Name: "wallet/transfers/01HQ3K5M8XYZ2NFVJT9BKR7P4C", // Transfer resource name
25+
}
26+
27+
// Call the GetTransfer method
28+
transfer, err := service.GetTransfer(ctx, request)
29+
if err != nil {
30+
log.Fatalf("GetTransfer failed: %v", err)
31+
}
32+
33+
// Display transfer details
34+
log.Printf("Transfer retrieved successfully:")
35+
log.Printf(" Name: %s", transfer.Name)
36+
log.Printf(" Number: %s", transfer.Number)
37+
log.Printf(" From: %s", transfer.From)
38+
log.Printf(" To: %s", transfer.To)
39+
log.Printf(" Amount: %s %s", transfer.Amount.Value, transfer.Amount.Token.Code)
40+
log.Printf(" State: %s", transfer.State)
41+
log.Printf(" Transaction: %s", transfer.Transaction)
42+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import co.meshtrade.api.wallet.transfer.v1.TransferService;
2+
import co.meshtrade.api.wallet.transfer.v1.Service.GetTransferRequest;
3+
import co.meshtrade.api.wallet.transfer.v1.Transfer.Transfer;
4+
5+
import java.util.Optional;
6+
7+
public class GetTransferExample {
8+
public static void main(String[] args) {
9+
// Default configuration is used and credentials come from MESH_API_CREDENTIALS
10+
// environment variable or default discovery methods. Zero config required
11+
// unless you want custom configuration.
12+
try (TransferService service = new TransferService()) {
13+
// Create request with the transfer resource name
14+
GetTransferRequest request = GetTransferRequest.newBuilder()
15+
.setName("wallet/transfers/01HQ3K5M8XYZ2NFVJT9BKR7P4C") // Transfer resource name
16+
.build();
17+
18+
// Call the GetTransfer method
19+
Transfer transfer = service.getTransfer(request, Optional.empty());
20+
21+
// Display transfer details
22+
System.out.println("Transfer retrieved successfully:");
23+
System.out.println(" Name: " + transfer.getName());
24+
System.out.println(" Number: " + transfer.getNumber());
25+
System.out.println(" From: " + transfer.getFrom());
26+
System.out.println(" To: " + transfer.getTo());
27+
System.out.println(" Amount: " + transfer.getAmount().getValue()
28+
+ " " + transfer.getAmount().getToken().getCode());
29+
System.out.println(" State: " + transfer.getState());
30+
System.out.println(" Transaction: " + transfer.getTransaction());
31+
} catch (Exception e) {
32+
System.err.println("GetTransfer failed: " + e.getMessage());
33+
e.printStackTrace();
34+
}
35+
}
36+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from meshtrade.wallet.transfer.v1 import (
2+
GetTransferRequest,
3+
TransferService,
4+
)
5+
6+
7+
def main():
8+
# Default configuration is used and credentials come from MESH_API_CREDENTIALS
9+
# environment variable or default discovery methods. Zero config required
10+
# unless you want custom configuration.
11+
service = TransferService()
12+
13+
with service:
14+
# Create request with the transfer resource name
15+
request = GetTransferRequest(
16+
name="wallet/transfers/01HQ3K5M8XYZ2NFVJT9BKR7P4C", # Transfer resource name
17+
)
18+
19+
# Call the GetTransfer method
20+
transfer = service.get_transfer(request)
21+
22+
# Display transfer details
23+
print("Transfer retrieved successfully:")
24+
print(f" Name: {transfer.name}")
25+
print(f" Number: {transfer.number}")
26+
print(f" From: {transfer.from_}")
27+
print(f" To: {transfer.to}")
28+
print(f" Amount: {transfer.amount.value} {transfer.amount.token.code}")
29+
print(f" State: {transfer.state}")
30+
print(f" Transaction: {transfer.transaction}")
31+
32+
33+
if __name__ == "__main__":
34+
main()

0 commit comments

Comments
 (0)