From a91ff808a1cdd4eaa76ac24be455d615e4bc82b2 Mon Sep 17 00:00:00 2001 From: Vladimir Shchukin Date: Fri, 3 Apr 2026 02:59:25 -0400 Subject: [PATCH] add u256/i256 explicit handlers --- .../solana/anchor-go/generator/accounts.go | 4 + .../solana/anchor-go/generator/constants.go | 70 ++++++--- .../solana/anchor-go/generator/u256_test.go | 148 ++++++++++++++++++ 3 files changed, 203 insertions(+), 19 deletions(-) create mode 100644 cmd/generate-bindings/solana/anchor-go/generator/u256_test.go diff --git a/cmd/generate-bindings/solana/anchor-go/generator/accounts.go b/cmd/generate-bindings/solana/anchor-go/generator/accounts.go index efadafe5..4edfdea8 100644 --- a/cmd/generate-bindings/solana/anchor-go/generator/accounts.go +++ b/cmd/generate-bindings/solana/anchor-go/generator/accounts.go @@ -389,6 +389,10 @@ func IDLTypeKind_ToTypeDeclCode(ts idltype.IdlType) *Statement { stat.Qual(PkgBinary, "Uint128") case *idltype.I128: stat.Qual(PkgBinary, "Int128") + case *idltype.U256: + stat.Index(Lit(32)).Byte() + case *idltype.I256: + stat.Index(Lit(32)).Byte() case *idltype.Bytes: stat.Index().Byte() case *idltype.String: diff --git a/cmd/generate-bindings/solana/anchor-go/generator/constants.go b/cmd/generate-bindings/solana/anchor-go/generator/constants.go index 591c4556..e2db01d9 100644 --- a/cmd/generate-bindings/solana/anchor-go/generator/constants.go +++ b/cmd/generate-bindings/solana/anchor-go/generator/constants.go @@ -174,25 +174,57 @@ func (g *Generator) gen_constants() (*OutputFile, error) { Return(Id("val")), ).Call() code.Line() - case *idltype.I128: - _ = ty - // "value":"-100_000_000" - cleanValue := strings.ReplaceAll(co.Value, "_", "") - bigInt := new(big.Int) - _, ok := bigInt.SetString(cleanValue, 10) - if !ok { - return nil, fmt.Errorf("failed to parse i128 constants[%d] %s: invalid format", coi, spew.Sdump(co)) - } - // Generate code that creates a big.Int from string - code.Var().Id(co.Name).Op("=").Func().Params().Op("*").Qual("math/big", "Int").Block( - Id("val").Op(",").Id("ok").Op(":=").New(Qual("math/big", "Int")).Dot("SetString").Call(Lit(cleanValue), Lit(10)), - If(Op("!").Id("ok")).Block( - Panic(Lit(fmt.Sprintf("invalid i128 constant %s", co.Name))), - ), - Return(Id("val")), - ).Call() - code.Line() - case *idltype.F32: + case *idltype.I128: + _ = ty + // "value":"-100_000_000" + cleanValue := strings.ReplaceAll(co.Value, "_", "") + bigInt := new(big.Int) + _, ok := bigInt.SetString(cleanValue, 10) + if !ok { + return nil, fmt.Errorf("failed to parse i128 constants[%d] %s: invalid format", coi, spew.Sdump(co)) + } + // Generate code that creates a big.Int from string + code.Var().Id(co.Name).Op("=").Func().Params().Op("*").Qual("math/big", "Int").Block( + Id("val").Op(",").Id("ok").Op(":=").New(Qual("math/big", "Int")).Dot("SetString").Call(Lit(cleanValue), Lit(10)), + If(Op("!").Id("ok")).Block( + Panic(Lit(fmt.Sprintf("invalid i128 constant %s", co.Name))), + ), + Return(Id("val")), + ).Call() + code.Line() + case *idltype.U256: + _ = ty + cleanValue := strings.ReplaceAll(co.Value, "_", "") + bigInt := new(big.Int) + _, ok := bigInt.SetString(cleanValue, 10) + if !ok { + return nil, fmt.Errorf("failed to parse u256 constants[%d] %s: invalid format", coi, spew.Sdump(co)) + } + code.Var().Id(co.Name).Op("=").Func().Params().Op("*").Qual("math/big", "Int").Block( + Id("val").Op(",").Id("ok").Op(":=").New(Qual("math/big", "Int")).Dot("SetString").Call(Lit(cleanValue), Lit(10)), + If(Op("!").Id("ok")).Block( + Panic(Lit(fmt.Sprintf("invalid u256 constant %s", co.Name))), + ), + Return(Id("val")), + ).Call() + code.Line() + case *idltype.I256: + _ = ty + cleanValue := strings.ReplaceAll(co.Value, "_", "") + bigInt := new(big.Int) + _, ok := bigInt.SetString(cleanValue, 10) + if !ok { + return nil, fmt.Errorf("failed to parse i256 constants[%d] %s: invalid format", coi, spew.Sdump(co)) + } + code.Var().Id(co.Name).Op("=").Func().Params().Op("*").Qual("math/big", "Int").Block( + Id("val").Op(",").Id("ok").Op(":=").New(Qual("math/big", "Int")).Dot("SetString").Call(Lit(cleanValue), Lit(10)), + If(Op("!").Id("ok")).Block( + Panic(Lit(fmt.Sprintf("invalid i256 constant %s", co.Name))), + ), + Return(Id("val")), + ).Call() + code.Line() + case *idltype.F32: _ = ty // "value":"3.14" cleanValue := strings.ReplaceAll(co.Value, "_", "") diff --git a/cmd/generate-bindings/solana/anchor-go/generator/u256_test.go b/cmd/generate-bindings/solana/anchor-go/generator/u256_test.go new file mode 100644 index 00000000..13fb77ae --- /dev/null +++ b/cmd/generate-bindings/solana/anchor-go/generator/u256_test.go @@ -0,0 +1,148 @@ +//nolint:all // Forked from anchor-go generator, maintaining original code structure +package generator + +import ( + "testing" + + "github.com/gagliardetto/anchor-go/idl" + "github.com/gagliardetto/anchor-go/idl/idltype" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIDLTypeKind_ToTypeDeclCode_U256(t *testing.T) { + assert.NotPanics(t, func() { + result := IDLTypeKind_ToTypeDeclCode(&idltype.U256{}) + assert.NotNil(t, result) + }) +} + +func TestIDLTypeKind_ToTypeDeclCode_I256(t *testing.T) { + assert.NotPanics(t, func() { + result := IDLTypeKind_ToTypeDeclCode(&idltype.I256{}) + assert.NotNil(t, result) + }) +} + +func TestGenTypeName_U256(t *testing.T) { + assert.NotPanics(t, func() { + result := genTypeName(&idltype.U256{}) + assert.NotNil(t, result) + }) +} + +func TestGenTypeName_I256(t *testing.T) { + assert.NotPanics(t, func() { + result := genTypeName(&idltype.I256{}) + assert.NotNil(t, result) + }) +} + +func TestGenConstants_U256(t *testing.T) { + idlData := &idl.Idl{ + Constants: []idl.IdlConst{ + { + Name: "MAX_SUPPLY", + Ty: &idltype.U256{}, + Value: "115792089237316195423570985008687907853269984665640564039457584007913129639935", + }, + }, + } + gen := &Generator{ + idl: idlData, + options: &GeneratorOptions{Package: "test"}, + } + + outputFile, err := gen.gen_constants() + require.NoError(t, err) + + generatedCode := outputFile.File.GoString() + assert.Contains(t, generatedCode, "var MAX_SUPPLY = func() *big.Int") + assert.Contains(t, generatedCode, ".SetString(\"115792089237316195423570985008687907853269984665640564039457584007913129639935\", 10)") +} + +func TestGenConstants_I256(t *testing.T) { + idlData := &idl.Idl{ + Constants: []idl.IdlConst{ + { + Name: "MIN_VALUE", + Ty: &idltype.I256{}, + Value: "-57896044618658097711785492504343953926634992332820282019728792003956564819968", + }, + }, + } + gen := &Generator{ + idl: idlData, + options: &GeneratorOptions{Package: "test"}, + } + + outputFile, err := gen.gen_constants() + require.NoError(t, err) + + generatedCode := outputFile.File.GoString() + assert.Contains(t, generatedCode, "var MIN_VALUE = func() *big.Int") + assert.Contains(t, generatedCode, ".SetString(\"-57896044618658097711785492504343953926634992332820282019728792003956564819968\", 10)") +} + +func TestGenConstants_U256_Invalid(t *testing.T) { + idlData := &idl.Idl{ + Constants: []idl.IdlConst{ + { + Name: "INVALID_U256", + Ty: &idltype.U256{}, + Value: "not_a_number", + }, + }, + } + gen := &Generator{ + idl: idlData, + options: &GeneratorOptions{Package: "test"}, + } + + _, err := gen.gen_constants() + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to parse u256") +} + +func TestGenConstants_I256_Invalid(t *testing.T) { + idlData := &idl.Idl{ + Constants: []idl.IdlConst{ + { + Name: "INVALID_I256", + Ty: &idltype.I256{}, + Value: "not_a_number", + }, + }, + } + gen := &Generator{ + idl: idlData, + options: &GeneratorOptions{Package: "test"}, + } + + _, err := gen.gen_constants() + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to parse i256") +} + +func TestGenConstants_U256_WithUnderscores(t *testing.T) { + idlData := &idl.Idl{ + Constants: []idl.IdlConst{ + { + Name: "LARGE_U256", + Ty: &idltype.U256{}, + Value: "1_000_000_000_000_000_000_000_000_000", + }, + }, + } + gen := &Generator{ + idl: idlData, + options: &GeneratorOptions{Package: "test"}, + } + + outputFile, err := gen.gen_constants() + require.NoError(t, err) + + generatedCode := outputFile.File.GoString() + assert.Contains(t, generatedCode, "var LARGE_U256 = func() *big.Int") + assert.Contains(t, generatedCode, ".SetString(\"1000000000000000000000000000\", 10)") +}