2023-12-29 19:54:36 +00:00
|
|
|
//go:build !exclude_crypto_ecdsa
|
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
package main
|
2023-12-28 13:24:32 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/gas"
|
2024-01-12 17:20:37 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
2023-12-28 13:24:32 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Wallet struct {
|
|
|
|
Tokens map[string]int
|
|
|
|
}
|
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
func (w Wallet) getTokenBalance(token string) int {
|
|
|
|
value := getValueFromStringIntMap(w.Tokens, token)
|
|
|
|
if value == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return value.(int)
|
2023-12-28 13:24:32 +00:00
|
|
|
}
|
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
var prices map[string]int
|
|
|
|
|
|
|
|
// All prices are multiplied by 1e10 and rounded to be represented as fixed point int
|
|
|
|
func init() {
|
|
|
|
prices = map[string]int{
|
|
|
|
"XMR": 1521000000000,
|
|
|
|
"XRP": 6035000000,
|
|
|
|
"ADA": 5793000000,
|
|
|
|
"AVAX": 396900000000,
|
|
|
|
"BNB": 3083000000000,
|
|
|
|
"BTC": 466489200000000,
|
|
|
|
"ETH": 26230000000000,
|
|
|
|
"SOL": 1011800000000,
|
2023-12-28 13:24:32 +00:00
|
|
|
}
|
2024-01-12 17:20:37 +00:00
|
|
|
}
|
2023-12-28 13:24:32 +00:00
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
func TopUp(address interop.Hash160, token string, amount int) bool {
|
|
|
|
if !isKnownToken(token) {
|
|
|
|
runtime.Log("Token " + token + " is unkown")
|
|
|
|
return false
|
2023-12-28 13:24:32 +00:00
|
|
|
}
|
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
wallet := getWallet(address)
|
|
|
|
balance := wallet.getTokenBalance(token)
|
|
|
|
wallet.Tokens[token] = balance + amount
|
|
|
|
saveWallet(address, wallet)
|
2023-12-28 13:24:32 +00:00
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
return true
|
2023-12-28 13:24:32 +00:00
|
|
|
}
|
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
func GetTokenBalance(address interop.Hash160, token string) int {
|
|
|
|
return getWallet(address).getTokenBalance(token)
|
2023-12-28 13:24:32 +00:00
|
|
|
}
|
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
func Exchange(address interop.Hash160, amount int, fromToken string, toToken string) bool {
|
2023-12-28 13:24:32 +00:00
|
|
|
if amount <= 0 {
|
|
|
|
runtime.Log("Invalid amount")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
wallet := getWallet(address)
|
|
|
|
fromBalance := wallet.getTokenBalance(fromToken)
|
|
|
|
if fromBalance < amount {
|
2023-12-28 13:24:32 +00:00
|
|
|
runtime.Log("Not enough funds to exchange")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
fromTokenPrice := getPrice(fromToken)
|
|
|
|
toTokenPrice := getPrice(toToken)
|
|
|
|
convertedAmount := amount * fromTokenPrice / toTokenPrice
|
2023-12-28 13:24:32 +00:00
|
|
|
|
|
|
|
wallet.Tokens[fromToken] -= amount
|
2024-01-12 17:20:37 +00:00
|
|
|
wallet.Tokens[toToken] = wallet.getTokenBalance(toToken) + convertedAmount
|
2023-12-28 13:24:32 +00:00
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
saveWallet(address, wallet)
|
2023-12-28 13:24:32 +00:00
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
runtime.Log("Exchange successful: " + std.Itoa10(amount) + " " + fromToken +
|
|
|
|
" exchanged for " + std.Itoa10(convertedAmount) + " " + toToken)
|
2023-12-28 18:16:57 +00:00
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
func PrintWallet(address interop.Hash160) {
|
|
|
|
wallet := getWallet(address)
|
2023-12-28 18:16:57 +00:00
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
runtime.Log("Wallet " + ":")
|
2023-12-28 18:16:57 +00:00
|
|
|
for key, value := range wallet.Tokens {
|
2024-01-12 17:20:37 +00:00
|
|
|
runtime.Log(key + ":" + std.Itoa10(value))
|
2023-12-28 18:16:57 +00:00
|
|
|
}
|
2024-01-12 17:20:37 +00:00
|
|
|
}
|
2023-12-28 13:24:32 +00:00
|
|
|
|
2024-01-12 17:20:37 +00:00
|
|
|
func getWallet(address interop.Hash160) Wallet {
|
|
|
|
ctx := storage.GetContext()
|
|
|
|
walletBytes := storage.Get(ctx, address)
|
|
|
|
if walletBytes == nil {
|
|
|
|
return Wallet{
|
|
|
|
Tokens: make(map[string]int),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
walletBytesAsBytes := walletBytes.([]byte)
|
|
|
|
deserialized := std.Deserialize(walletBytesAsBytes)
|
|
|
|
if deserialized == nil {
|
|
|
|
return Wallet{}
|
|
|
|
}
|
|
|
|
|
|
|
|
return deserialized.(Wallet)
|
|
|
|
}
|
|
|
|
|
|
|
|
func saveWallet(address interop.Hash160, wallet Wallet) {
|
|
|
|
ctx := storage.GetContext()
|
|
|
|
serialized := std.Serialize(wallet)
|
|
|
|
storage.Put(ctx, address, serialized)
|
|
|
|
}
|
|
|
|
|
|
|
|
func getPrice(token string) int {
|
|
|
|
if !isKnownToken(token) {
|
|
|
|
panic("trying to get price for unknown token")
|
|
|
|
}
|
|
|
|
return prices[token]
|
|
|
|
}
|
|
|
|
|
|
|
|
func getValueFromStringIntMap(mp map[string]int, key string) any {
|
|
|
|
defer func() {
|
|
|
|
recover()
|
|
|
|
}()
|
|
|
|
|
|
|
|
return mp[key]
|
|
|
|
}
|
|
|
|
|
|
|
|
func isKnownToken(token string) bool {
|
|
|
|
return getValueFromStringIntMap(prices, token) != nil
|
2023-12-28 13:24:32 +00:00
|
|
|
}
|