Skip to content
Open
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
56 changes: 56 additions & 0 deletions plugins/balance/dao/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import (
"github.com/itering/subscan-plugin/storage"
"github.com/itering/subscan/model"
bModel "github.com/itering/subscan/plugins/balance/model"
"github.com/itering/subscan/util"
"github.com/itering/subscan/util/address"
"github.com/itering/substrate-api-rpc/rpc"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"strings"
)

func GetAccountListCursor(db storage.DB, limit int, before, after *uint) ([]bModel.Account, bool, bool) {
Expand Down Expand Up @@ -58,6 +60,60 @@ func GetAccountByAddress(ctx context.Context, db storage.DB, address string) *bM

}

func GetMultisigAccountInfo(ctx context.Context, db storage.DB, accountID string) (string, string) {
if accountID == "" {
return "", ""
}
d := db.GetDbInstance().(*gorm.DB)
currentBlock, err := db.GetCurrentBlockNum(ctx)
if err != nil {
return "", ""
}
accountID = strings.TrimPrefix(strings.ToLower(accountID), "0x")
maxTableIndex := int(currentBlock / uint64(model.SplitTableBlockNum))
for index := maxTableIndex; index >= 0; index-- {
var events []model.ChainEvent
table := model.TableNameFromInterface(&model.ChainEvent{BlockNum: uint(index) * model.SplitTableBlockNum}, d)
q := d.WithContext(ctx).
Table(table).
Where("module_id = ?", "multisig").
Where("event_id = ?", "NewMultisig").
Order("id desc").
Limit(200).
Find(&events)
if q.Error != nil {
continue
}
for _, event := range events {
if composer, ok := multisigComposerFromEvent(event, accountID); ok {
return "Multisig", composer
}
}
}
return "", ""
}

func multisigComposerFromEvent(event model.ChainEvent, accountID string) (string, bool) {
var composer string
var matched bool
for _, param := range event.Params {
value := strings.TrimPrefix(strings.ToLower(util.ToString(param.Value)), "0x")
switch strings.ToLower(param.Name) {
case "approving":
composer = value
case "multisig":
matched = value == accountID
}
}
if !matched {
return "", false
}
if composer == "" {
return "", true
}
return address.Encode(composer), true
}

func RefreshAccount(ctx context.Context, s *Storage, accountId string) error {
accountId = address.Format(accountId)
if accountId == "" {
Expand Down
40 changes: 40 additions & 0 deletions plugins/balance/dao/account_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dao

import (
"testing"

"github.com/itering/subscan/model"
"github.com/itering/subscan/util"
"github.com/stretchr/testify/assert"
)

func TestMultisigComposerFromEvent(t *testing.T) {
originalAddressType := util.AddressType
t.Cleanup(func() { util.AddressType = originalAddressType })
util.AddressType = "31"
event := model.ChainEvent{
Params: model.EventParams{
{Name: "approving", Value: "0x9c6c86c4936b94ae7772d1045e8f4e36690c84bb6df01c49e167de90902d0817"},
{Name: "multisig", Value: "0x8898bfb77f32226ec1990ed415ce0f215b05e3d5a872a4e4f4e6a4718be04f85"},
{Name: "call_hash", Value: "0xf2472a3093ba21e07c3ed2938da1158e3d03d1f9527b2085180288a804317a21"},
},
}

composer, ok := multisigComposerFromEvent(event, "8898bfb77f32226ec1990ed415ce0f215b05e3d5a872a4e4f4e6a4718be04f85")

assert.True(t, ok)
assert.Equal(t, "49wYitCNCSrF2swm88DekiF1BQmyi3K5sna3SGjDZ78fsLaL", composer)
}

func TestMultisigComposerFromEventIgnoresOtherAccount(t *testing.T) {
event := model.ChainEvent{
Params: model.EventParams{
{Name: "approving", Value: "0x9c6c86c4936b94ae7772d1045e8f4e36690c84bb6df01c49e167de90902d0817"},
{Name: "multisig", Value: "0x8898bfb77f32226ec1990ed415ce0f215b05e3d5a872a4e4f4e6a4718be04f85"},
},
}

_, ok := multisigComposerFromEvent(event, "dbc968c19add01bc24568a02b7d02c68e98965fe7df757d8d2733f82bf3aa941")

assert.False(t, ok)
}
6 changes: 6 additions & 0 deletions plugins/balance/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ type Account struct {
Vested decimal.Decimal `json:"vested" gorm:"type:decimal(65,0);"`
}

type AccountJson struct {
Account
AccountType string `json:"account_type,omitempty"`
MultisigComposer string `json:"multisig_composer,omitempty"`
}

func (a *Account) TableName() string {
return "balance_accounts"
}
Expand Down
9 changes: 7 additions & 2 deletions plugins/balance/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,18 @@ func (s *Service) GetAccountListCursor(_ context.Context, limit int, before, aft
}
}

func (s *Service) GetAccountJson(ctx context.Context, addr string) *model.Account {
func (s *Service) GetAccountJson(ctx context.Context, addr string) *model.AccountJson {
account := dao.GetAccountByAddress(ctx, s.d, addr)
if account == nil {
return nil
}
account.Address = address.Encode(account.Address)
return account
accountType, composer := dao.GetMultisigAccountInfo(ctx, s.d, addr)
return &model.AccountJson{
Account: *account,
AccountType: accountType,
MultisigComposer: composer,
}
}

func (s *Service) GetTransferCursor(ctx context.Context, addr string, blockNum uint, limit int, before, after *uint) ([]model.Transfer, map[string]interface{}) {
Expand Down
23 changes: 23 additions & 0 deletions ui-react/src/pages/sub/account/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { BIG_ZERO } from '@/utils/const'
import { Container, PageContent } from '@/ui'
import { env } from 'next-runtime-env'
import { LoadingSpinner, LoadingText } from '@/components/loading'
import { Link } from '@/components/link'

export default function Page() {
const router = useRouter()
Expand Down Expand Up @@ -54,6 +55,28 @@ export default function Page() {
</div>
<Card>
<CardBody>
{accountData.account_type && (
<>
<div className="flex items-center">
<div className="w-48">Account Type</div>
<div>{accountData.account_type}</div>
</div>
<Divider className="my-2.5" />
</>
)}
{accountData.multisig_composer && (
<>
<div className="flex items-center">
<div className="w-48">Multisig Composer</div>
<div className="break-all">
<Link color={getThemeColor(true)} href={`/sub/account/${accountData.multisig_composer}`}>
{accountData.multisig_composer}
</Link>
</div>
</div>
<Divider className="my-2.5" />
</>
)}
<div className="flex items-center">
<div className="w-48">Total Balance</div>
<div>{getBalanceAmount(new BigNumber(accountData.balance), token?.decimals).toFormat()}</div>
Expand Down
2 changes: 2 additions & 0 deletions ui-react/src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ export type accountType = {
nonce: string
reserved: string
vested?: string
account_type?: string
multisig_composer?: string
}

type getAccountParams = {
Expand Down
Loading