Skip to content
Merged
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) starting with the *v1.0.0-beta.1* release.

## [v2.0.0-preview] - 2025-1-22
[v2.0.0-preview release page](https://github.com/1inch/1inch-sdk-go/releases/tag/v2.0.0-preview)

### Breaking Changes
- a new `surplus=true` query parameter must be added to Fusion quote requests

### Changed
- Fusion implementation updated to support new Fusion backend
- Fusion+ is disabled until refactor is complete

## [v1.0.0-beta.3] - 2025-1-22
[v1.0.0-beta.3 release page](https://github.com/1inch/1inch-sdk-go/releases/tag/v1.0.0-beta.3)
### Changed
Expand Down
Empty file added MIGRATIONS.md
Empty file.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ Jump To:
## Supported APIs

### Token Swaps
*Swap API* - [[Docs](https://portal.1inch.dev/documentation/apis/swap/classic-swap/introduction) | [SDK Example](https://github.com/1inch/1inch-sdk-go/blob/main/sdk-clients/aggregation/examples/quote/main.go)]
*Classic Swap API* - [[Docs](https://portal.1inch.dev/documentation/apis/swap/classic-swap/introduction) | [SDK Example](https://github.com/1inch/1inch-sdk-go/blob/main/sdk-clients/aggregation/examples/quote/main.go)]

*Fusion API* - [[Docs](https://portal.1inch.dev/documentation/apis/swap/intent-swap/introduction) | [SDK Example](https://github.com/1inch/1inch-sdk-go/blob/main/sdk-clients/fusion/examples/place_order/main.go)] (now called Intent Swap)
*Intent-based Swap (Fusion) API* - [[Docs](https://portal.1inch.dev/documentation/apis/swap/intent-swap/introduction) | [SDK Example](https://github.com/1inch/1inch-sdk-go/blob/main/sdk-clients/fusion/examples/place_order/main.go)]

*Fusion Plus API* - [[Docs](https://portal.1inch.dev/documentation/apis/swap/fusion-plus/introduction) | [SDK Example](https://github.com/1inch/1inch-sdk-go/blob/main/sdk-clients/fusionplus/examples/place_order/main.go)]
*Cross-chain Swap (Fusion+) API* - [[Docs](https://portal.1inch.dev/documentation/apis/swap/fusion-plus/introduction) | [SDK Example](https://github.com/1inch/1inch-sdk-go/blob/main/sdk-clients/fusionplus/examples/place_order/main.go)]

*Orderbook API* - [[Docs](https://portal.1inch.dev/documentation/apis/orderbook/introduction) | [SDK Example](https://github.com/1inch/1inch-sdk-go/blob/main/sdk-clients/orderbook/examples/create_order/main.go)]

Expand Down Expand Up @@ -147,4 +147,4 @@ an [issue](https://github.com/1inch/1inch-sdk/issues) here on GitHub
## Development

Please see our [SDK Developer Guide](https://github.com/1inch/1inch-sdk-go/blob/main/DEVELOPMENT.md) if you would
like to contribute
like to contribute
3 changes: 3 additions & 0 deletions internal/addresses/addresses.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package addresses

const ZeroAddress string = "0x0000000000000000000000000000000000000000"
3 changes: 3 additions & 0 deletions internal/bigint/bigint.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import (
"math/big"
)

var Base1E5 = big.NewInt(100000)
var Base1E2 = big.NewInt(100)

func FromString(s string) (*big.Int, error) {
bigInt, ok := new(big.Int).SetString(s, 10) // base 10 for decimal
if !ok {
Expand Down
13 changes: 13 additions & 0 deletions internal/bytesbuilder/bytesbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ func New() *BytesBuilder {
return &BytesBuilder{data: []byte{}}
}

func (b *BytesBuilder) AddUint256(val *big.Int) {
bytes := val.Bytes()
if len(bytes) < 32 {
// Pad on the left (big-endian) to 32 bytes
padded := make([]byte, 32-len(bytes))
bytes = append(padded, bytes...)
} else if len(bytes) > 32 {
// Truncate to last 32 bytes if larger (high bits ignored)
bytes = bytes[len(bytes)-32:]
}
b.data = append(b.data, bytes...)
}

func (b *BytesBuilder) AddUint24(val *big.Int) {
bytes := val.Bytes()
switch {
Expand Down
16 changes: 16 additions & 0 deletions internal/times/time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package times

import "time"

var Now func() int64 = NowImpl

func NowImpl() int64 {
return time.Now().Unix()
}

var CalculateAuctionStartTime func(uint32, uint32) uint32 = CalculateAuctionStartTimeImpl

func CalculateAuctionStartTimeImpl(startAuctionIn uint32, additionalWaitPeriod uint32) uint32 {
currentTime := time.Now().Unix()
return uint32(currentTime) + additionalWaitPeriod + startAuctionIn
}
66 changes: 0 additions & 66 deletions internal/validate/integration_check_cleanup_test.go

This file was deleted.

16 changes: 0 additions & 16 deletions internal/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"math/big"
"regexp"
"strings"
"time"

"github.com/1inch/1inch-sdk-go/constants"
"github.com/1inch/1inch-sdk-go/internal/bigint"
Expand Down Expand Up @@ -460,21 +459,6 @@ func CheckPermitHash(parameter interface{}, variableName string) error {
return nil
}

func CheckExpireAfterUnix(parameter interface{}, variableName string) error {
value, ok := parameter.(int64)
if !ok {
return fmt.Errorf("for parameter '%v' to be validated as '%v', it must be a string", variableName, "ExpireAfterUnix")
}
if value == 0 {
return nil
}

if value < time.Now().Unix() {
return NewParameterValidationError(variableName, "must be a future timestamp")
}
return nil
}

func CheckFiatCurrency(parameter interface{}, variableName string) error {
value, ok := parameter.(string)
if !ok {
Expand Down
33 changes: 0 additions & 33 deletions internal/validate/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -955,39 +955,6 @@ func TestCheckPermitHash(t *testing.T) {
}
}

func TestExpireAfter(t *testing.T) {
testcases := []struct {
description string
value int64
expectError bool
}{
{
description: "Valid timestamp - empty",
value: 0,
},
{
description: "Valid timestamp - year 2030",
value: 1897205247,
},
{
description: "Invalid timestamp - past",
value: 1707791247,
expectError: true,
},
}

for _, tc := range testcases {
t.Run(tc.description, func(t *testing.T) {
err := CheckExpireAfterUnix(tc.value, "testValue")
if tc.expectError {
require.Error(t, err, fmt.Sprintf("%s should have caused an error", tc.description))
} else {
require.NoError(t, err, fmt.Sprintf("%s should not have caused an error", tc.description))
}
})
}
}

func TestIsBigInt(t *testing.T) {
testCases := []struct {
description string
Expand Down
148 changes: 148 additions & 0 deletions sdk-clients/aggregation/examples/approve_and_swap/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package main

import (
"context"
"fmt"
"log"
"math/big"
"os"
"time"

"github.com/1inch/1inch-sdk-go/constants"
"github.com/1inch/1inch-sdk-go/sdk-clients/aggregation"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)

var (
privateKey = os.Getenv("WALLET_KEY")
nodeUrl = os.Getenv("NODE_URL")
devPortalToken = os.Getenv("DEV_PORTAL_TOKEN")
)

const (
UsdcBase = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
WethBase = "0x4200000000000000000000000000000000000006"
amountUsdc = "100000" // 0.1 USDC (6 decimals)
)

func main() {
config, err := aggregation.NewConfiguration(aggregation.ConfigurationParams{
NodeUrl: nodeUrl,
PrivateKey: privateKey,
ChainId: constants.BaseChainId,
ApiUrl: "https://api.1inch.dev",
ApiKey: devPortalToken,
})
if err != nil {
log.Fatalf("Failed to create configuration: %v\n", err)
}
client, err := aggregation.NewClient(config)
if err != nil {
log.Fatalf("Failed to create client: %v\n", err)
}
ctx := context.Background()

walletAddr := client.Wallet.Address().Hex()

// Step 1: Check Allowance
allowanceData, err := client.GetApproveAllowance(ctx, aggregation.GetAllowanceParams{
TokenAddress: UsdcBase,
WalletAddress: walletAddr,
})
if err != nil {
log.Fatalf("Failed to get allowance: %v\n", err)
}
allowance := new(big.Int)
allowance.SetString(allowanceData.Allowance, 10)

amountToSwap := new(big.Int)
amountToSwap.SetString(amountUsdc, 10)

// Step 2: Approve if needed
if allowance.Cmp(amountToSwap) < 0 {
fmt.Println("Insufficient allowance. Approving...")
approveData, err := client.GetApproveTransaction(ctx, aggregation.GetApproveParams{
TokenAddress: UsdcBase,
Amount: amountUsdc,
})
if err != nil {
log.Fatalf("Failed to get approve data: %v\n", err)
}
data, err := hexutil.Decode(approveData.Data)
if err != nil {
log.Fatalf("Failed to decode approve data: %v\n", err)
}
to := common.HexToAddress(approveData.To)

tx, err := client.TxBuilder.New().SetData(data).SetTo(&to).Build(ctx)
if err != nil {
log.Fatalf("Failed to build approve transaction: %v\n", err)
}
signedTx, err := client.Wallet.Sign(tx)
if err != nil {
log.Fatalf("Failed to sign approve transaction: %v\n", err)
}
err = client.Wallet.BroadcastTransaction(ctx, signedTx)
if err != nil {
log.Fatalf("Failed to broadcast approve transaction: %v\n", err)
}

fmt.Printf("Approve transaction sent: https://basescan.org/tx/%s\n", signedTx.Hash().Hex())

// Wait for approval to be mined
for {
receipt, _ := client.Wallet.TransactionReceipt(ctx, signedTx.Hash())
if receipt != nil {
fmt.Println("Approve transaction confirmed.")
break
}
time.Sleep(2 * time.Second)
}
} else {
fmt.Println("Sufficient allowance already present.")
}

// Step 3: Perform Swap
swapData, err := client.GetSwap(ctx, aggregation.GetSwapParams{
Src: UsdcBase,
Dst: WethBase,
Amount: amountUsdc,
From: walletAddr,
Slippage: 1, // 1% slippage
})
if err != nil {
log.Fatalf("Failed to get swap data: %v\n", err)
}

tx, err := client.TxBuilder.New().
SetData(swapData.TxNormalized.Data).
SetTo(&swapData.TxNormalized.To).
SetGas(swapData.TxNormalized.Gas).
SetValue(swapData.TxNormalized.Value).
Build(ctx)
if err != nil {
log.Fatalf("Failed to build transaction: %v\n", err)
}
signedTx, err := client.Wallet.Sign(tx)
if err != nil {
log.Fatalf("Failed to sign transaction: %v\n", err)
}

err = client.Wallet.BroadcastTransaction(ctx, signedTx)
if err != nil {
log.Fatalf("Failed to broadcast transaction: %v\n", err)
}

fmt.Printf("Swap transaction sent: https://basescan.org/tx/%s\n", signedTx.Hash().Hex())

// Wait for swap transaction to be mined
for {
receipt, _ := client.Wallet.TransactionReceipt(ctx, signedTx.Hash())
if receipt != nil {
fmt.Println("Swap transaction confirmed!")
break
}
time.Sleep(2 * time.Second)
}
}
Loading