Skip to content

Commit

Permalink
chore: standard compliance
Browse files Browse the repository at this point in the history
  • Loading branch information
krigga committed Oct 26, 2023
1 parent 7382544 commit 0b69eb1
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 61 deletions.
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
8. Change `TONCENTER_URI` as needed. That means removing `testnet.` if you want to deploy your collection to mainnet
9. `cd` to the directory where `ctl` and `.env` are located
10. Create a file containing the addresses of owners of your items, one address per line. Empty lines will be ignored. The first one will get item index 0, and so on. We will assume that this file is named `owners.txt` and is located in the same directory
11. Run `./ctl add owners.txt`. This will add the addresses to the database
12. Host your collection metadata and items' metadata with formats as outlined in [Token Data Standard](https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md). The items' metadata files must all have a pattern of `some-common-uri-part + '/' + item-index + '.json'`. Other patterns are possible but will require changes to the API's code
13. Run `./server` in a way that prevents it from closing when your SSH (or any other kind of session) closes. You can do that using the [screen](https://www.gnu.org/software/screen/manual/screen.html) utility for example. Make sure that the assigned `PORT` is visible to the public Internet on some endpoint
14. Navigate to `api-uri + '/admin/rediscover'`. Use your `ADMIN_*` credentials. If all went well, you should see the string `ok` and a file should appear under `DATA_DIR + '/upd/1.json'` (perhaps after some time if the number of items is large)
15. Run `./ctl genupd path-to-update-file collection-owner collection-meta item-meta-prefix royalty-base royalty-factor royalty-recipient api-uri-without-v1` where `path-to-update-file` is the path to the file mentioned in step 15, `collection-owner` is the intended collection owner, `collection-meta` is the full URI to collection metadata file, `item-meta-prefix` is the common item metadata file prefix (for example, if your item 0 has its metadata hosted at `https://example.com/0.json`, then you should use `https://example.com/` here), `royalty-base` is the royalty numerator, `royalty-factor` is the royalty denominator (base = 1 and factor = 100 give 1% royalty), `royalty-recipient` is the address which will get royalties (you can just use the `collection-owner` here), and `api-uri-without-v1` is the part of the publicly visible API URI without the `/v1` postfix (so if you used `https://example.com/admin/rediscover` to create the update file, you should put `https://example.com/` here. Using `localhost` or similar here will not allow users to claim your items, but for testing purposes that's fine)
16. Invoke the `ton://` deeplink that appears
17. Navigate to `api-uri + '/admin/setaddr/' + collection-address` using the address that you saw after step 16
18. Wait for a `commited state` message in `server` logs
19. Done
11. Run `./ctl migrate`. This will create the necessary tables in the database
12. Run `./ctl add owners.txt`. This will add the addresses to the database
13. Host your collection metadata and items' metadata with formats as outlined in [Token Data Standard](https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md). The items' metadata files must all have a pattern of `some-common-uri-part + '/' + item-index + '.json'`. Other patterns are possible but will require changes to the API's code
14. Run `./server` in a way that prevents it from closing when your SSH (or any other kind of session) closes. You can do that using the [screen](https://www.gnu.org/software/screen/manual/screen.html) utility for example. Make sure that the assigned `PORT` is visible to the public Internet on some endpoint
15. Navigate to `api-uri + '/admin/rediscover'`. Use your `ADMIN_*` credentials. If all went well, you should see the string `ok` and a file should appear under `DATA_DIR + '/upd/1.json'` (perhaps after some time if the number of items is large)
16. Run `./ctl genupd path-to-update-file collection-owner collection-meta item-meta-prefix royalty-base royalty-factor royalty-recipient api-uri-including-v1` where `path-to-update-file` is the path to the file mentioned in step 15, `collection-owner` is the intended collection owner, `collection-meta` is the full URI to collection metadata file, `item-meta-prefix` is the common item metadata file prefix (for example, if your item 0 has its metadata hosted at `https://example.com/0.json`, then you should use `https://example.com/` here), `royalty-base` is the royalty numerator, `royalty-factor` is the royalty denominator (base = 1 and factor = 100 give 1% royalty), `royalty-recipient` is the address which will get royalties (you can just use the `collection-owner` here), and `api-uri-including-v1` is the publicly visible API URI with the `/v1` postfix (so if you used `https://example.com/admin/rediscover` to create the update file, you should put `https://example.com/v1` here. Using `localhost` or similar here will not allow users to claim your items, but for testing purposes that's fine)
17. Invoke the `ton://` deeplink that appears
18. Navigate to `api-uri + '/admin/setaddr/' + collection-address` using the address that you saw after step 16
19. Wait for a `commited state` message in `server` logs
20. Done

### Updating

Expand Down
30 changes: 28 additions & 2 deletions address/address.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package address

import (
"encoding/hex"
"encoding/json"
"fmt"

"github.com/xssnick/tonutils-go/address"
)
Expand All @@ -10,19 +12,43 @@ type Address struct {
*address.Address
}

func (a *Address) MarshalJSON() ([]byte, error) {
s := fmt.Sprintf("%v:%v", a.Workchain(), hex.EncodeToString(a.Data()))
return json.Marshal(s)
}

func (a *Address) UnmarshalJSON(b []byte) error {
var s string
err := json.Unmarshal(b, &s)
if err != nil {
return err
}

addr, err := address.ParseAddr(s)
var wc int
var hash string
_, err = fmt.Sscanf(s, "%v:%v", &wc, &hash)
if err != nil {
return err
}

a.Address = addr
var wcByte byte
if wc == 0 {
wcByte = 0
} else if wc == -1 {
wcByte = 0xff
} else {
return fmt.Errorf("unknown workchain value: %v", wc)
}

hashBytes, err := hex.DecodeString(hash)
if err != nil {
return err
}
if len(hashBytes) != 32 {
return fmt.Errorf("incorrect address hash part length: %v", len(hashBytes))
}

a.Address = address.NewAddress(0, wcByte, hashBytes)

return nil
}
45 changes: 45 additions & 0 deletions cmd/ctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ import (
"math/big"
"os"
"strconv"
"strings"

"github.com/golang-migrate/migrate/v4"
_ "github.com/golang-migrate/migrate/v4/database/pgx/v5"
"github.com/golang-migrate/migrate/v4/source/iofs"
"github.com/jackc/pgx/v5"
"github.com/spf13/cobra"
"github.com/ton-community/compressed-nft-api/config"
"github.com/ton-community/compressed-nft-api/migrations"
"github.com/ton-community/compressed-nft-api/updates"
"github.com/xssnick/tonutils-go/address"
"github.com/xssnick/tonutils-go/tlb"
Expand Down Expand Up @@ -287,6 +292,40 @@ func add(cmd *cobra.Command, args []string) error {
return nil
}

func doMigrate() error {
config.LoadConfig()

d, err := iofs.New(migrations.MigrationsFS, ".")
if err != nil {
return err
}

m, err := migrate.NewWithSourceInstance("migrations", d, strings.Replace(config.Config.Database, "postgres", "pgx5", 1))
if err != nil {
return err
}

err = m.Up()
if err != nil && err != migrate.ErrNoChange {
return err
}

err1, err2 := m.Close()
if err1 != nil {
return err1
}

if err2 != nil {
return err2
}

return nil
}

func migr(cmd *cobra.Command, args []string) error {
return doMigrate()
}

func main() {
var rootCmd = &cobra.Command{
Use: "ctl",
Expand All @@ -304,8 +343,14 @@ func main() {
RunE: add,
}

var migrateCmd = &cobra.Command{
Use: "migrate",
RunE: migr,
}

rootCmd.AddCommand(genupdCmd)
rootCmd.AddCommand(addCmd)
rootCmd.AddCommand(migrateCmd)

if err := rootCmd.Execute(); err != nil {
os.Exit(1)
Expand Down
37 changes: 0 additions & 37 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,12 @@ import (
"context"
"fmt"
"path"
"strings"

"github.com/golang-migrate/migrate/v4"
_ "github.com/golang-migrate/migrate/v4/database/pgx/v5"
"github.com/golang-migrate/migrate/v4/source/iofs"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/ton-community/compressed-nft-api/config"
myhttp "github.com/ton-community/compressed-nft-api/http"
"github.com/ton-community/compressed-nft-api/migrations"
"github.com/ton-community/compressed-nft-api/provider"
"github.com/ton-community/compressed-nft-api/provider/file"
"github.com/ton-community/compressed-nft-api/provider/pg"
Expand All @@ -24,41 +19,9 @@ import (
"github.com/xssnick/tonutils-go/address"
)

func doMigrate() error {
d, err := iofs.New(migrations.MigrationsFS, ".")
if err != nil {
return err
}

m, err := migrate.NewWithSourceInstance("migrations", d, strings.Replace(config.Config.Database, "postgres", "pgx5", 1))
if err != nil {
return err
}

err = m.Up()
if err != nil && err != migrate.ErrNoChange {
return err
}

err1, err2 := m.Close()
if err1 != nil {
return err1
}

if err2 != nil {
return err2
}

return nil
}

func main() {
config.LoadConfig()

if err := doMigrate(); err != nil {
panic(err)
}

pool, err := pgxpool.New(context.Background(), config.Config.Database)
if err != nil {
panic(err)
Expand Down
6 changes: 4 additions & 2 deletions data/data.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package data

import (
"strconv"

"github.com/ton-community/compressed-nft-api/address"
"github.com/ton-community/compressed-nft-api/types"
"github.com/xssnick/tonutils-go/tvm/cell"
Expand All @@ -22,13 +24,13 @@ func (d *ItemMetadata) ToNode() types.Node {
type ItemData struct {
Metadata *ItemMetadata `json:"metadata"`
DataCell *cell.Cell `json:"data_cell"`
Index uint64 `json:"index"`
Index string `json:"index"`
}

func NewItemData(index uint64, metadata *ItemMetadata) *ItemData {
return &ItemData{
Metadata: metadata,
DataCell: metadata.ToCell(),
Index: index,
Index: strconv.FormatUint(index, 10),
}
}
22 changes: 12 additions & 10 deletions http/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import (
"errors"
"math/bits"
"net/http"
"strconv"

"github.com/labstack/echo/v4"
"github.com/rs/zerolog/log"
myaddress "github.com/ton-community/compressed-nft-api/address"
"github.com/ton-community/compressed-nft-api/data"
"github.com/ton-community/compressed-nft-api/hash"
"github.com/ton-community/compressed-nft-api/provider"
Expand Down Expand Up @@ -66,7 +68,7 @@ func (h *Handler) getItemsInternal(from uint64, count uint64) (*ItemsResponse, e
return &ItemsResponse{
Items: fi,
Root: state.CurrentState.Root,
LastIndex: state.CurrentState.LastIndex,
LastIndex: strconv.FormatUint(state.CurrentState.LastIndex, 10),
}, nil
}

Expand All @@ -77,7 +79,7 @@ type ItemsRequest struct {

type ItemsResponse struct {
Items []*data.ItemData `json:"items"`
LastIndex uint64 `json:"last_index"`
LastIndex string `json:"last_index"`
Root types.Node `json:"root"`
}

Expand Down Expand Up @@ -184,11 +186,11 @@ func (h *Handler) getItem(c echo.Context) error {
}

type StateResponse struct {
Depth int `json:"depth"`
Capacity uint64 `json:"capacity"`
LastIndex uint64 `json:"last_index"`
Root types.Node `json:"root"`
Address *address.Address `json:"address"`
Depth int `json:"depth"`
Capacity string `json:"capacity"`
LastIndex string `json:"last_index"`
Root types.Node `json:"root"`
Address *myaddress.Address `json:"address"`
}

func (h *Handler) getState(c echo.Context) error {
Expand All @@ -199,9 +201,9 @@ func (h *Handler) getState(c echo.Context) error {
resp := &StateResponse{
Depth: h.Depth,
Root: state.CurrentState.Root,
Capacity: 1 << h.Depth,
LastIndex: state.CurrentState.LastIndex,
Address: state.CurrentState.Address.Address,
Capacity: strconv.Itoa(1 << h.Depth),
LastIndex: strconv.FormatUint(state.CurrentState.LastIndex, 10),
Address: &myaddress.Address{Address: state.CurrentState.Address.Address},
}

return c.JSON(http.StatusOK, resp)
Expand Down
2 changes: 1 addition & 1 deletion http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func (h *Handler) RegisterHandlers(e *echo.Echo) {
v1 := e.Group("/v1")

v1.GET("/items", h.getItems)
v1.GET("/item/:index", h.getItem)
v1.GET("/items/:index", h.getItem)
v1.GET("/state", h.getState)

admin := e.Group("/admin")
Expand Down

0 comments on commit 0b69eb1

Please sign in to comment.