diff --git a/cic_net/cicnet.go b/cic_net/cic_net.go similarity index 100% rename from cic_net/cicnet.go rename to cic_net/cic_net.go diff --git a/cic_net/cic_net_test.go b/cic_net/cic_net_test.go new file mode 100644 index 0000000..1e89144 --- /dev/null +++ b/cic_net/cic_net_test.go @@ -0,0 +1,15 @@ +package cic_net + +import ( + "os" +) + +type tConfig struct { + rpcProvider string + tokenIndex string +} + +var conf = &tConfig{ + rpcProvider: os.Getenv("RPC_PROVIDER"), + tokenIndex: os.Getenv("TOKEN_INDEX"), +} diff --git a/cic_net/erc20_demurrage_token.go b/cic_net/erc20_demurrage_token.go index 7ccbca3..e83f699 100644 --- a/cic_net/erc20_demurrage_token.go +++ b/cic_net/erc20_demurrage_token.go @@ -8,32 +8,72 @@ import ( "math/big" ) -type DemurrageToken struct { - Name string - Symbol string - Decimals big.Int +type DemurrageTokenInfo struct { + DemurrageAmount big.Int + DemurrageTimestamp big.Int + MinimumParticipantSpend big.Int + ResolutionFactor big.Int + PeriodStart big.Int + PeriodDuration big.Int + TaxLevel big.Int + ActualPeriod big.Int + RedistributionCount big.Int + IsDemurrageToken bool } -func (c *CicNet) TokenInfo(ctx context.Context, tokenAddress common.Address) (DemurrageToken, error) { +func (c *CicNet) DemurrageTokenInfo(ctx context.Context, tokenAddress common.Address) (DemurrageTokenInfo, error) { var ( - tokenName string - tokenSymbol string - tokenDecimals big.Int + demurrageAmount big.Int + demurrageTimestamp big.Int + minimumParticipantSpend big.Int + resolutionFactor big.Int + periodStart big.Int + periodDuration big.Int + taxLevel big.Int + actualPeriod big.Int + redistributionCount big.Int ) err := c.ethClient.CallCtx( ctx, - eth.CallFunc(w3.MustNewFunc("name()", "string"), tokenAddress).Returns(&tokenName), - eth.CallFunc(w3.MustNewFunc("symbol()", "string"), tokenAddress).Returns(&tokenSymbol), - eth.CallFunc(w3.MustNewFunc("decimals()", "uint256"), tokenAddress).Returns(&tokenDecimals), + eth.CallFunc(w3.MustNewFunc("demurrageAmount()", "uint128"), tokenAddress).Returns(&demurrageAmount), + eth.CallFunc(w3.MustNewFunc("demurrageTimestamp()", "uint256"), tokenAddress).Returns(&demurrageTimestamp), + eth.CallFunc(w3.MustNewFunc("minimumParticipantSpend()", "uint256"), tokenAddress).Returns(&minimumParticipantSpend), + eth.CallFunc(w3.MustNewFunc("resolutionFactor()", "uint256"), tokenAddress).Returns(&resolutionFactor), + eth.CallFunc(w3.MustNewFunc("periodStart()", "uint256"), tokenAddress).Returns(&periodStart), + eth.CallFunc(w3.MustNewFunc("periodDuration()", "uint256"), tokenAddress).Returns(&periodDuration), + eth.CallFunc(w3.MustNewFunc("taxLevel()", "uint256"), tokenAddress).Returns(&taxLevel), + eth.CallFunc(w3.MustNewFunc("actualPeriod()", "uint256"), tokenAddress).Returns(&actualPeriod), + eth.CallFunc(w3.MustNewFunc("redistributionCount()", "uint256"), tokenAddress).Returns(&redistributionCount), ) + if err != nil { - return DemurrageToken{}, err + return DemurrageTokenInfo{}, err } - return DemurrageToken{ - Name: tokenName, - Symbol: tokenSymbol, - Decimals: tokenDecimals, + return DemurrageTokenInfo{ + DemurrageAmount: demurrageAmount, + DemurrageTimestamp: demurrageTimestamp, + MinimumParticipantSpend: minimumParticipantSpend, + ResolutionFactor: resolutionFactor, + PeriodStart: periodStart, + PeriodDuration: periodDuration, + TaxLevel: taxLevel, + ActualPeriod: actualPeriod, + RedistributionCount: redistributionCount, }, nil } + +func (c *CicNet) BaseBalanceOf(ctx context.Context, tokenAddress common.Address, accountAddress common.Address) (big.Int, error) { + var balance big.Int + + err := c.ethClient.CallCtx( + ctx, + eth.CallFunc(w3.MustNewFunc("baseBalanceOf(address _account)", "uint256"), tokenAddress, accountAddress).Returns(&balance), + ) + if err != nil { + return big.Int{}, err + } + + return balance, nil +} diff --git a/cic_net/erc20_demurrage_token_test.go b/cic_net/erc20_demurrage_token_test.go new file mode 100644 index 0000000..7b88e81 --- /dev/null +++ b/cic_net/erc20_demurrage_token_test.go @@ -0,0 +1,133 @@ +package cic_net + +import ( + "context" + "github.com/ethereum/go-ethereum/common" + "github.com/lmittmann/w3" + "math/big" + "testing" +) + +func TestCicNet_DemurrageToken_DemurrageTokeInfo(t *testing.T) { + type args struct { + contractAddress common.Address + } + + tests := []struct { + name string + args args + wantErr bool + isDemurrage bool + }{ + { + name: "Demurrage token at kitabu sarafu", + args: args{ + contractAddress: w3.A("0xaB89822F31c2092861F713F6F34bd6877a8C1878"), + }, + wantErr: false, + }, + { + name: "Giftable token at Muthaa", + args: args{ + contractAddress: w3.A("0x3dad47e5EF13661bbD15aa74132E91a9aBCFDe44"), + }, + wantErr: true, + }, + { + name: "Dead address", + args: args{ + contractAddress: w3.A("0x000000000000000000000000000000000000dEaD"), + }, + wantErr: true, + }, + } + + for _, testcase := range tests { + tt := testcase + + t.Run(tt.name, func(t *testing.T) { + cicnet, err := NewCicNet(conf.rpcProvider, w3.A(conf.tokenIndex)) + + if err != nil { + t.Fatalf("NewCicNet error = %v", err) + } + + got, err := cicnet.DemurrageTokenInfo(context.Background(), tt.args.contractAddress) + + if (err != nil) != tt.wantErr { + t.Errorf("DemurrageTokenInfo() error = %v, wantErr %v", err, tt.wantErr) + } + + if !tt.wantErr { + if got.DemurrageAmount.Cmp(big.NewInt(0)) < 1 { + t.Fatalf("DemurrageAmount = %v, want %d atleast", got, 1) + } + } + }) + } +} + +func TestCicNet_DemurrageToken_BaseBalanceOf(t *testing.T) { + type args struct { + contractAddress common.Address + accountAddress common.Address + } + + tests := []struct { + name string + args args + wantErr bool + balanceGte big.Int + }{ + { + name: "Sarafu sink balance", + args: args{ + contractAddress: w3.A("0xaB89822F31c2092861F713F6F34bd6877a8C1878"), + accountAddress: w3.A("0xBBb4a93c8dCd82465B73A143f00FeD4AF7492a27"), + }, + wantErr: false, + balanceGte: *big.NewInt(1), + }, + { + name: "Dead address balance", + args: args{ + contractAddress: w3.A("0xaB89822F31c2092861F713F6F34bd6877a8C1878"), + accountAddress: w3.A("0x000000000000000000000000000000000000dEaD"), + }, + wantErr: false, + balanceGte: *big.NewInt(0), + }, + { + name: "Giftable token at Muthaa", + args: args{ + contractAddress: w3.A("0x3dad47e5EF13661bbD15aa74132E91a9aBCFDe44"), + accountAddress: w3.A("0xBBb4a93c8dCd82465B73A143f00FeD4AF7492a27"), + }, + wantErr: true, + }, + } + + for _, testcase := range tests { + tt := testcase + + t.Run(tt.name, func(t *testing.T) { + cicnet, err := NewCicNet(conf.rpcProvider, w3.A(conf.tokenIndex)) + + if err != nil { + t.Fatalf("NewCicNet error = %v", err) + } + + got, err := cicnet.BaseBalanceOf(context.Background(), tt.args.contractAddress, tt.args.accountAddress) + + if (err != nil) != tt.wantErr { + t.Errorf("BaseBalanceOf() error = %v, wantErr %v", err, tt.wantErr) + } + + if !tt.wantErr { + if got.Cmp(&tt.balanceGte) < 0 { + t.Fatalf("Token = %v, want %d", got, tt.balanceGte.Int64()) + } + } + }) + } +} diff --git a/cic_net/erc20_token.go b/cic_net/erc20_token.go new file mode 100644 index 0000000..74d4d8d --- /dev/null +++ b/cic_net/erc20_token.go @@ -0,0 +1,52 @@ +package cic_net + +import ( + "context" + "github.com/ethereum/go-ethereum/common" + "github.com/lmittmann/w3" + "github.com/lmittmann/w3/module/eth" + "math/big" +) + +type ERC20Token struct { + Name string + Symbol string + Decimals big.Int +} + +func (c *CicNet) ERC20TokenInfo(ctx context.Context, tokenAddress common.Address) (ERC20Token, error) { + var ( + tokenName string + tokenSymbol string + tokenDecimals big.Int + ) + + err := c.ethClient.CallCtx( + ctx, + eth.CallFunc(w3.MustNewFunc("name()", "string"), tokenAddress).Returns(&tokenName), + eth.CallFunc(w3.MustNewFunc("symbol()", "string"), tokenAddress).Returns(&tokenSymbol), + eth.CallFunc(w3.MustNewFunc("decimals()", "uint256"), tokenAddress).Returns(&tokenDecimals), + ) + if err != nil { + return ERC20Token{}, err + } + + return ERC20Token{ + Name: tokenName, + Symbol: tokenSymbol, + Decimals: tokenDecimals, + }, nil +} +func (c *CicNet) BalanceOf(ctx context.Context, tokenAddress common.Address, accountAddress common.Address) (big.Int, error) { + var balance big.Int + + err := c.ethClient.CallCtx( + ctx, + eth.CallFunc(w3.MustNewFunc("balanceOf(address _account)", "uint256"), tokenAddress, accountAddress).Returns(&balance), + ) + if err != nil { + return big.Int{}, err + } + + return balance, nil +} diff --git a/cic_net/erc20_token_test.go b/cic_net/erc20_token_test.go new file mode 100644 index 0000000..9208fb8 --- /dev/null +++ b/cic_net/erc20_token_test.go @@ -0,0 +1,116 @@ +package cic_net + +import ( + "context" + "github.com/ethereum/go-ethereum/common" + "github.com/lmittmann/w3" + "math/big" + "testing" +) + +func TestCicNet_ERC20Token_ERC20TokenInfo(t *testing.T) { + type args struct { + contractAddress common.Address + } + + tests := []struct { + name string + args args + wantErr bool + symbol string + }{ + { + name: "Token at kitabu sarafu", + args: args{ + contractAddress: w3.A("0xaB89822F31c2092861F713F6F34bd6877a8C1878"), + }, + wantErr: false, + symbol: "SRF", + }, + { + name: "Token at zero address", + args: args{ + contractAddress: w3.A("0x0000000000000000000000000000000000000000"), + }, + wantErr: true, + symbol: "", + }, + } + + for _, testcase := range tests { + tt := testcase + + t.Run(tt.name, func(t *testing.T) { + cicnet, err := NewCicNet(conf.rpcProvider, w3.A(conf.tokenIndex)) + + if err != nil { + t.Fatalf("NewCicNet error = %v", err) + } + + got, err := cicnet.ERC20TokenInfo(context.Background(), tt.args.contractAddress) + + if (err != nil) != tt.wantErr { + t.Errorf("ERC20TokenInfo() error = %v, wantErr %v", err, tt.wantErr) + } + + if got.Symbol != tt.symbol { + t.Fatalf("Token = %v, want %v", got, tt.symbol) + } + }) + } +} + +func TestCicNet_ERC20Token_BalanceOf(t *testing.T) { + type args struct { + contractAddress common.Address + accountAddress common.Address + } + + tests := []struct { + name string + args args + wantErr bool + balanceGte big.Int + }{ + { + name: "Sarafu sink balance", + args: args{ + contractAddress: w3.A("0xaB89822F31c2092861F713F6F34bd6877a8C1878"), + accountAddress: w3.A("0xBBb4a93c8dCd82465B73A143f00FeD4AF7492a27"), + }, + wantErr: false, + balanceGte: *big.NewInt(1), + }, + { + name: "Dead address balance", + args: args{ + contractAddress: w3.A("0xaB89822F31c2092861F713F6F34bd6877a8C1878"), + accountAddress: w3.A("0x000000000000000000000000000000000000dEaD"), + }, + wantErr: false, + balanceGte: *big.NewInt(0), + }, + } + + for _, testcase := range tests { + tt := testcase + + t.Run(tt.name, func(t *testing.T) { + cicnet, err := NewCicNet(conf.rpcProvider, w3.A(conf.tokenIndex)) + + if err != nil { + t.Fatalf("NewCicNet error = %v", err) + } + + got, err := cicnet.BalanceOf(context.Background(), tt.args.contractAddress, tt.args.accountAddress) + + if (err != nil) != tt.wantErr { + t.Errorf("BalanceOf() error = %v, wantErr %v", err, tt.wantErr) + } + + if got.Cmp(&tt.balanceGte) < 0 { + t.Fatalf("Token = %v, want %d", got, tt.balanceGte.Int64()) + } + }) + } +} diff --git a/cic_net/token_index_test.go b/cic_net/token_index_test.go new file mode 100644 index 0000000..48aa3f7 --- /dev/null +++ b/cic_net/token_index_test.go @@ -0,0 +1,83 @@ +package cic_net + +import ( + "context" + "github.com/lmittmann/w3" + "math/big" + "testing" +) + +func TestCicNet_TokenIndex_EntryCount(t *testing.T) { + name := "Entry count" + wantErr := false + + t.Run(name, func(t *testing.T) { + tokenIndex, err := NewCicNet(conf.rpcProvider, w3.A(conf.tokenIndex)) + + if err != nil { + t.Fatalf("NewCicNet error = %v", err) + } + + got, err := tokenIndex.EntryCount(context.Background()) + + if (err != nil) != wantErr { + t.Errorf("EntryCount() error = %v, wantErr %v", err, wantErr) + } + + if got.Cmp(big.NewInt(0)) < 1 { + t.Fatalf("EntryCount() = %v, want %v", got, 1) + } + }) +} + +func TestCicNet_TokenIndex_AddressAtIndex(t *testing.T) { + type args struct { + index *big.Int + } + + tests := []struct { + name string + args args + wantErr bool + address string + }{ + { + name: "Address at index 0", + args: args{ + index: big.NewInt(0), + }, + wantErr: false, + address: "0xaB89822F31c2092861F713F6F34bd6877a8C1878", + }, + { + name: "Address at index 999", + args: args{ + index: big.NewInt(999), + }, + wantErr: true, + address: "", + }, + } + + for _, testcase := range tests { + tt := testcase + + t.Run(tt.name, func(t *testing.T) { + tokenIndex, err := NewCicNet(conf.rpcProvider, w3.A(conf.tokenIndex)) + + if err != nil { + t.Fatalf("NewCicNet error = %v", err) + } + + got, err := tokenIndex.AddressAtIndex(context.Background(), tt.args.index) + + if (err != nil) != tt.wantErr { + t.Errorf("AddressAtIndex() error = %v, wantErr %v", err, tt.wantErr) + } + + if got != tt.address { + t.Fatalf("AddressAtIndex = %v, want %v", got, tt.address) + } + }) + } +}