Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Adds `PermissionedDomain` ledger entry type (XLS-80d).

#### binary-codec

- `Number` and `AssetScale` fields to `definitions.json`

### Fixed

#### xrpl

- `OracleSet` transaction to Flatten correctly and `Oracle` PriceDataSeries array.

#### binary-codec

- `definitions.json` where `LastUpdatedTime` had a typo issue.

## [v0.1.11]

### BREAKING CHANGES
Expand Down
23 changes: 22 additions & 1 deletion binary-codec/definitions/definitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"LedgerEntry": 10002,
"Metadata": 10004,
"NotPresent": 0,
"Number": 9,
"PathSet": 18,
"STArray": 15,
"STObject": 14,
Expand Down Expand Up @@ -236,6 +237,16 @@
"type": "UInt8"
}
],
[
"AssetScale",
{
"isSerialized": true,
"isSigningField": true,
"isVLEncoded": false,
"nth": 5,
"type": "UInt8"
}
],
[
"TickSize",
{
Expand Down Expand Up @@ -527,7 +538,7 @@
}
],
[
"LastUpdateTime",
"LastUpdatedTime",
{
"nth": 15,
"isVLEncoded": false,
Expand Down Expand Up @@ -2416,6 +2427,16 @@
"type": "AccountID"
}
],
[
"Number",
{
"isSerialized": true,
"isSigningField": true,
"isVLEncoded": false,
"nth": 1,
"type": "Number"
}
],
[
"TransactionMetaData",
{
Expand Down
8 changes: 5 additions & 3 deletions binary-codec/types/currency.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ func (c *Currency) FromJSON(json any) ([]byte, error) {
// ToJSON serializes a binary currency value into a JSON-compatible format.
// It requires a length option specifying the byte length to read.
func (c *Currency) ToJSON(p interfaces.BinaryParser, opts ...int) (any, error) {
if len(opts) == 0 {
return nil, ErrMissingCurrencyLengthOption
// default to 20 bytes, https://xrpl.org/docs/references/protocol/ledger-data/ledger-entry-types/oracle#currency-internal-format
length := 20
if len(opts) > 0 && opts[0] > 0 {
length = opts[0]
}

currencyBytes, err := p.ReadBytes(opts[0])
currencyBytes, err := p.ReadBytes(length)
if err != nil {
return nil, err
}
Expand Down
144 changes: 144 additions & 0 deletions examples/oracle/rpc/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package main

import (
"encoding/hex"
"encoding/json"
"fmt"
"time"

"github.com/Peersyst/xrpl-go/examples/clients"
"github.com/Peersyst/xrpl-go/pkg/crypto"
"github.com/Peersyst/xrpl-go/xrpl/currency"
"github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types"
"github.com/Peersyst/xrpl-go/xrpl/rpc/types"
"github.com/Peersyst/xrpl-go/xrpl/transaction"
"github.com/Peersyst/xrpl-go/xrpl/wallet"
)

func safeInt64ToUint32(value int64) uint32 {
if value < 0 {
return 0
}
if value > int64(^uint32(0)) {
return ^uint32(0) // max uint32 value
}
return uint32(value)
}

func printJSON(data interface{}) {
jsonBytes, err := json.MarshalIndent(data, "", " ")
if err != nil {
fmt.Printf("❌ Error marshaling to JSON: %s\n", err)
return
}
fmt.Println(string(jsonBytes))
}

func main() {
//
// Configure client
//
fmt.Println("⏳ Setting up testnet RPC client...")
client := clients.GetTestnetRPCClient()

//
// Configure wallets
//
fmt.Println("⏳ Setting up wallets...")
oracleIssuer, err := wallet.New(crypto.ED25519())
if err != nil {
fmt.Printf("❌ Error creating oracle issuer wallet: %s\n", err)
return
}
err = client.FundWallet(&oracleIssuer)
if err != nil {
fmt.Printf("❌ Error funding oracle issuer wallet: %s\n", err)
return
}
fmt.Println("💸 Oracle issuer wallet funded!")
fmt.Println()

//
// Create oracle set transaction
//
fmt.Println("⏳ Creating oracle set transaction...")

// 1 minute ago
lastUpdatedTime := safeInt64ToUint32(time.Now().Add(-time.Second).Unix())
oracleDocumentID := uint32(1)

oracleSet := transaction.OracleSet{
BaseTx: transaction.BaseTx{
Account: oracleIssuer.ClassicAddress,
},
OracleDocumentID: oracleDocumentID,
LastUpdatedTime: lastUpdatedTime,
URI: hex.EncodeToString([]byte("https://example.com")),
Provider: hex.EncodeToString([]byte("Chainlink")),
AssetClass: hex.EncodeToString([]byte("currency")),
PriceDataSeries: []ledger.PriceDataWrapper{
{
PriceData: ledger.PriceData{
BaseAsset: currency.ConvertStringToHex("ACGB"),
QuoteAsset: "USD",
AssetPrice: 123,
Scale: 3,
},
},
},
}

flatOracleSet := oracleSet.Flatten()

fmt.Println("📄 Oracle Set Transaction JSON:")
printJSON(flatOracleSet)
fmt.Println()

response, err := client.SubmitTxAndWait(flatOracleSet, &types.SubmitOptions{
Wallet: &oracleIssuer,
Autofill: true,
})
if err != nil {
fmt.Println(err)
return
}

fmt.Println("✅ Oracle set transaction submitted")
fmt.Printf("🌐 Hash: %s\n", response.Hash.String())
fmt.Printf("🌐 Validated: %t\n", response.Validated)

if !response.Validated {
fmt.Println("❌ Oracle set transaction failed")
return
}
fmt.Println()

// Delete oracle
fmt.Println("⏳ Deleting oracle...")

oracleDelete := transaction.OracleDelete{
BaseTx: transaction.BaseTx{
Account: oracleIssuer.ClassicAddress,
},
OracleDocumentID: oracleDocumentID,
}

flatOracleDelete := oracleDelete.Flatten()

fmt.Println("📄 Oracle Delete Transaction JSON:")
printJSON(flatOracleDelete)
fmt.Println()

responseDelete, err := client.SubmitTxAndWait(flatOracleDelete, &types.SubmitOptions{
Wallet: &oracleIssuer,
Autofill: true,
})
if err != nil {
fmt.Println(err)
return
}

fmt.Println("✅ Oracle deleted")
fmt.Printf("🌐 Hash: %s\n", responseDelete.Hash.String())
fmt.Printf("🌐 Validated: %t\n", responseDelete.Validated)
}
160 changes: 160 additions & 0 deletions examples/oracle/ws/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package main

import (
"encoding/hex"
"encoding/json"
"fmt"
"time"

"github.com/Peersyst/xrpl-go/examples/clients"
"github.com/Peersyst/xrpl-go/pkg/crypto"
"github.com/Peersyst/xrpl-go/xrpl/currency"
"github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types"
"github.com/Peersyst/xrpl-go/xrpl/transaction"
"github.com/Peersyst/xrpl-go/xrpl/wallet"
wstypes "github.com/Peersyst/xrpl-go/xrpl/websocket/types"
)

func safeInt64ToUint32(value int64) uint32 {
if value < 0 {
return 0
}
if value > int64(^uint32(0)) {
return ^uint32(0) // max uint32 value
}
return uint32(value)
}

func printJSON(data interface{}) {
jsonBytes, err := json.MarshalIndent(data, "", " ")
if err != nil {
fmt.Printf("❌ Error marshaling to JSON: %s\n", err)
return
}
fmt.Println(string(jsonBytes))
}

func main() {
// Setup client
fmt.Println("⏳ Setting up testnet WebSocket client...")
client := clients.GetTestnetWebsocketClient()
defer func() {
if err := client.Disconnect(); err != nil {
fmt.Printf("Error disconnecting: %s\n", err)
}
}()

if err := client.Connect(); err != nil {
fmt.Printf("❌ Error connecting to testnet: %s\n", err)
return
}

if !client.IsConnected() {
fmt.Println("❌ Failed to connect to testnet")
return
}

fmt.Println("✅ Connected to testnet")
fmt.Println()

//
// Configure wallets
//
fmt.Println("⏳ Setting up wallets...")
oracleIssuer, err := wallet.New(crypto.ED25519())
if err != nil {
fmt.Printf("❌ Error creating oracle issuer wallet: %s\n", err)
return
}
err = client.FundWallet(&oracleIssuer)
if err != nil {
fmt.Printf("❌ Error funding oracle issuer wallet: %s\n", err)
return
}
fmt.Println("💸 Oracle issuer wallet funded!")
fmt.Println()

//
// Create oracle set transaction
//
fmt.Println("⏳ Creating oracle set transaction...")

// 1 minute ago
lastUpdatedTime := safeInt64ToUint32(time.Now().Add(-time.Second).Unix())
oracleDocumentID := uint32(1)

oracleSet := transaction.OracleSet{
BaseTx: transaction.BaseTx{
Account: oracleIssuer.ClassicAddress,
},
OracleDocumentID: oracleDocumentID,
LastUpdatedTime: lastUpdatedTime,
URI: hex.EncodeToString([]byte("https://example.com")),
Provider: hex.EncodeToString([]byte("Chainlink")),
AssetClass: hex.EncodeToString([]byte("currency")),
PriceDataSeries: []ledger.PriceDataWrapper{
{
PriceData: ledger.PriceData{
BaseAsset: currency.ConvertStringToHex("ACGB"),
QuoteAsset: "USD",
AssetPrice: 123,
Scale: 3,
},
},
},
}

flatOracleSet := oracleSet.Flatten()

fmt.Println("📄 Oracle Set Transaction JSON:")
printJSON(flatOracleSet)
fmt.Println()

response, err := client.SubmitTxAndWait(flatOracleSet, &wstypes.SubmitOptions{
Wallet: &oracleIssuer,
Autofill: true,
})
if err != nil {
fmt.Println(err)
return
}

fmt.Println("✅ Oracle set transaction submitted")
fmt.Printf("🌐 Hash: %s\n", response.Hash.String())
fmt.Printf("🌐 Validated: %t\n", response.Validated)

if !response.Validated {
fmt.Println("❌ Oracle set transaction failed")
return
}
fmt.Println()

// Delete oracle
fmt.Println("⏳ Deleting oracle...")

oracleDelete := transaction.OracleDelete{
BaseTx: transaction.BaseTx{
Account: oracleIssuer.ClassicAddress,
},
OracleDocumentID: oracleDocumentID,
}

flatOracleDelete := oracleDelete.Flatten()

fmt.Println("📄 Oracle Delete Transaction JSON:")
printJSON(flatOracleDelete)
fmt.Println()

responseDelete, err := client.SubmitTxAndWait(flatOracleDelete, &wstypes.SubmitOptions{
Wallet: &oracleIssuer,
Autofill: true,
})
if err != nil {
fmt.Println(err)
return
}

fmt.Println("✅ Oracle deleted")
fmt.Printf("🌐 Hash: %s\n", responseDelete.Hash.String())
fmt.Printf("🌐 Validated: %t\n", responseDelete.Validated)
}
Loading