Skip to content

Commit

Permalink
Merge pull request #16 from portto/spl-name-service
Browse files Browse the repository at this point in the history
feat: support spl name service query
  • Loading branch information
yihau authored Sep 2, 2021
2 parents b5072bf + 0cc6414 commit 047053d
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 0 deletions.
1 change: 1 addition & 0 deletions common/program_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ var (
Secp256k1ProgramID = PublicKeyFromString("KeccakSecp256k11111111111111111111111111111")
TokenProgramID = PublicKeyFromString("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
SPLAssociatedTokenAccountProgramID = PublicKeyFromString("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")
SPLNameServiceProgramID = PublicKeyFromString("namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX")
)
26 changes: 26 additions & 0 deletions program/nsprog/state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package nsprog

import (
"fmt"

"github.com/portto/solana-go-sdk/common"
)

type NameRecordHeader struct {
ParentName common.PublicKey
Owner common.PublicKey
Class common.PublicKey
Data []byte
}

func NameRecordHeaderFromData(data []byte) (NameRecordHeader, error) {
if len(data) < 96 {
return NameRecordHeader{}, fmt.Errorf("data length should bigger than 96")
}
return NameRecordHeader{
ParentName: common.PublicKeyFromBytes(data[:32]),
Owner: common.PublicKeyFromBytes(data[32:64]),
Class: common.PublicKeyFromBytes(data[64:96]),
Data: data[96:],
}, nil
}
48 changes: 48 additions & 0 deletions program/nsprog/state_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package nsprog

import (
"fmt"
"testing"

"github.com/portto/solana-go-sdk/common"
"github.com/stretchr/testify/assert"
)

func TestNameRecordHeaderFromData(t *testing.T) {
type args struct {
data []byte
}
tests := []struct {
name string
args args
want NameRecordHeader
err error
}{
{
args: args{
data: []byte{0x3d, 0x53, 0xc2, 0x4b},
},
want: NameRecordHeader{},
err: fmt.Errorf("data length should bigger than 96"),
},
{
args: args{
data: []byte{0x3d, 0x53, 0xc2, 0x4b, 0x38, 0x36, 0xe, 0xd3, 0x81, 0x3a, 0x23, 0xdf, 0xb2, 0xdf, 0xd8, 0x20, 0xab, 0x58, 0x21, 0xcb, 0x79, 0x29, 0xa3, 0x8d, 0x2e, 0xaa, 0xb2, 0x52, 0xe8, 0x38, 0x25, 0x95, 0x58, 0x7f, 0x6a, 0x3d, 0xab, 0x65, 0xe7, 0x3e, 0x12, 0xde, 0x67, 0xbc, 0x31, 0x73, 0x2d, 0xa0, 0x4e, 0xea, 0xfb, 0x12, 0x83, 0xdd, 0x21, 0x10, 0x82, 0x5c, 0xcb, 0x1e, 0xdf, 0x79, 0xa2, 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x65, 0x61, 0x63, 0x68, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x6a, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x6d, 0x37, 0x37, 0x32, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x73, 0x61, 0x6c, 0x65, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
},
want: NameRecordHeader{
ParentName: common.PublicKeyFromString("58PwtjSDuFHuUkYjH9BYnnQKHfwo9reZhC2zMJv9JPkx"),
Class: common.PublicKey{},
Owner: common.PublicKeyFromString("6xTZhtNA8aaipc2hHFP616gFvDcvWmYMGsDFHwrsF3m1"),
Data: []byte{0x52, 0x65, 0x61, 0x63, 0x68, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x6a, 0x61, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x6d, 0x37, 0x37, 0x32, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x73, 0x61, 0x6c, 0x65, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
},
err: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NameRecordHeaderFromData(tt.args.data)
assert.Equal(t, tt.err, err)
assert.Equal(t, tt.want, got)
})
}
}
39 changes: 39 additions & 0 deletions program/nsprog/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package nsprog

import (
"crypto/sha256"

"github.com/portto/solana-go-sdk/common"
)

var TwitterVerificationAuthority = common.PublicKeyFromString("FvPH7PrVrLGKPfqaf3xJodFTjZriqrAXXLTVWEorTFBi")
var TwitterRootParentRegisteryKey = common.PublicKeyFromString("4YcexoW3r78zz16J2aqmukBLRwGq6rAvWzJpkYAXqebv")
var SolTldAuthority = common.PublicKeyFromString("58PwtjSDuFHuUkYjH9BYnnQKHfwo9reZhC2zMJv9JPkx")

const HashPrefix = "SPL Name Service"

// GetHashName ...
func GetHashName(name string) []byte {
h := sha256.Sum256([]byte(HashPrefix + name))
return h[:]
}

// GetNameAccountKey return the pubkey correspond to name
func GetNameAccountKey(hashName []byte, nameClass, nameParent common.PublicKey) common.PublicKey {
seed := [][]byte{
hashName,
nameClass.Bytes(),
nameParent.Bytes(),
}
pubkey, _, _ := common.FindProgramAddress(seed, common.SPLNameServiceProgramID)
return pubkey
}

// GetTwitterRegistryKey return the pubkey corespond to twitter handle
func GetTwitterRegistryKey(twitterHandle string) common.PublicKey {
return GetNameAccountKey(
GetHashName(twitterHandle),
common.PublicKey{},
TwitterRootParentRegisteryKey,
)
}
96 changes: 96 additions & 0 deletions program/nsprog/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package nsprog

import (
"reflect"
"testing"

"github.com/portto/solana-go-sdk/common"
"github.com/stretchr/testify/assert"
)

func TestGetTwitterRegistryKey(t *testing.T) {
type args struct {
twitterHandle string
}
tests := []struct {
name string
args args
want common.PublicKey
}{
{
args: args{
twitterHandle: "gghost07114721",
},
want: common.PublicKeyFromString("5r2pKbCFibGZp18u51tcvzQpsNsA98TyCF1UbDmbSUk5"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, GetTwitterRegistryKey(tt.args.twitterHandle))
})
}
}

func TestGetHashName(t *testing.T) {
type args struct {
name string
}
tests := []struct {
name string
args args
want []byte
}{
{
args: args{
name: "blocto",
},
want: []byte{0x62, 0x94, 0x3a, 0xc2, 0x9e, 0x7b, 0x9d, 0x4e, 0x38, 0x53, 0xb2, 0x84, 0xdd, 0x7f, 0x1, 0x66, 0xeb, 0x5f, 0x0, 0xe3, 0x1f, 0x25, 0x53, 0x51, 0x83, 0x61, 0x38, 0x33, 0xcd, 0xc5, 0xf9, 0x3},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetHashName(tt.args.name); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetHashName() = %v, want %v", got, tt.want)
}
})
}
}

func TestGetNameAccountKey(t *testing.T) {
type args struct {
hashName []byte
nameClass common.PublicKey
nameParent common.PublicKey
}
tests := []struct {
name string
args args
want common.PublicKey
}{
{
name: "domain: blocto.sol",
args: args{
hashName: GetHashName("blocto"),
nameClass: common.PublicKey{},
nameParent: SolTldAuthority,
},
want: common.PublicKeyFromString("6yAP2rFW7wQiqVmySE4DTfQSWmp6fR1geGyWx6SQMAhS"),
},
{
name: "domain yihau.blocto.sol",
args: args{
hashName: GetHashName("\x00yihau"),
nameClass: common.PublicKey{},
nameParent: GetNameAccountKey(GetHashName("blocto"), common.PublicKey{}, SolTldAuthority),
},
want: common.PublicKeyFromString("5Cjg2Xah4Cc24yM7zsfbyBuXKZ6Wm9ZJqHa5n47vnvNz"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetNameAccountKey(tt.args.hashName, tt.args.nameClass, tt.args.nameParent); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetNameAccountKey() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit 047053d

Please sign in to comment.