Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stonfi swap #263

Merged
merged 1 commit into from
Jun 13, 2024
Merged
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
98 changes: 98 additions & 0 deletions abi/get_methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package abi
import (
"context"
"fmt"

"github.com/tonkeeper/tongo/boc"
"github.com/tonkeeper/tongo/tlb"
"github.com/tonkeeper/tongo/ton"
Expand All @@ -23,6 +24,7 @@ var KnownGetMethodsDecoder = map[string][]func(tlb.VmStack) (string, any, error)
"get_collection_data": {DecodeGetCollectionDataResult},
"get_domain": {DecodeGetDomainResult},
"get_editor": {DecodeGetEditorResult},
"get_expected_outputs": {DecodeGetExpectedOutputs_StonfiResult},
"get_full_domain": {DecodeGetFullDomainResult},
"get_jetton_data": {DecodeGetJettonDataResult},
"get_last_clean_time": {DecodeGetLastCleanTimeResult},
Expand All @@ -47,6 +49,7 @@ var KnownGetMethodsDecoder = map[string][]func(tlb.VmStack) (string, any, error)
"get_order_data": {DecodeGetOrderDataResult},
"get_params": {DecodeGetParams_WhalesNominatorResult},
"get_plugin_list": {DecodeGetPluginListResult},
"get_pool_address": {DecodeGetPoolAddress_StonfiResult},
"get_pool_data": {DecodeGetPoolData_StonfiResult, DecodeGetPoolData_TfResult},
"get_pool_full_data": {DecodeGetPoolFullDataResult},
"get_pool_status": {DecodeGetPoolStatusResult},
Expand Down Expand Up @@ -156,6 +159,7 @@ var resultTypes = []interface{}{
&GetCollectionDataResult{},
&GetDomainResult{},
&GetEditorResult{},
&GetExpectedOutputs_StonfiResult{},
&GetFullDomainResult{},
&GetJettonDataResult{},
&GetLastCleanTimeResult{},
Expand All @@ -180,6 +184,7 @@ var resultTypes = []interface{}{
&GetOrderDataResult{},
&GetParams_WhalesNominatorResult{},
&GetPluginListResult{},
&GetPoolAddress_StonfiResult{},
&GetPoolData_StonfiResult{},
&GetPoolData_TfResult{},
&GetPoolFullDataResult{},
Expand Down Expand Up @@ -672,6 +677,52 @@ func DecodeGetEditorResult(stack tlb.VmStack) (resultType string, resultAny any,
return "GetEditorResult", result, err
}

type GetExpectedOutputs_StonfiResult struct {
Out tlb.Int257
ProtocolFeeOut tlb.Int257
RefFeeOut tlb.Int257
}

func GetExpectedOutputs(ctx context.Context, executor Executor, reqAccountID ton.AccountID, amount tlb.Int257, tokenWallet tlb.MsgAddress) (string, any, error) {
stack := tlb.VmStack{}
var (
val tlb.VmStackValue
err error
)
val = tlb.VmStackValue{SumType: "VmStkInt", VmStkInt: amount}
stack.Put(val)
val, err = tlb.TlbStructToVmCellSlice(tokenWallet)
if err != nil {
return "", nil, err
}
stack.Put(val)

// MethodID = 115709 for "get_expected_outputs" method
errCode, stack, err := executor.RunSmcMethodByID(ctx, reqAccountID, 115709, stack)
if err != nil {
return "", nil, err
}
if errCode != 0 && errCode != 1 {
return "", nil, fmt.Errorf("method execution failed with code: %v", errCode)
}
for _, f := range []func(tlb.VmStack) (string, any, error){DecodeGetExpectedOutputs_StonfiResult} {
s, r, err := f(stack)
if err == nil {
return s, r, nil
}
}
return "", nil, fmt.Errorf("can not decode outputs")
}

func DecodeGetExpectedOutputs_StonfiResult(stack tlb.VmStack) (resultType string, resultAny any, err error) {
if len(stack) != 3 || (stack[0].SumType != "VmStkTinyInt" && stack[0].SumType != "VmStkInt") || (stack[1].SumType != "VmStkTinyInt" && stack[1].SumType != "VmStkInt") || (stack[2].SumType != "VmStkTinyInt" && stack[2].SumType != "VmStkInt") {
return "", nil, fmt.Errorf("invalid stack format")
}
var result GetExpectedOutputs_StonfiResult
err = stack.Unmarshal(&result)
return "GetExpectedOutputs_StonfiResult", result, err
}

type GetFullDomainResult struct {
Domain string
}
Expand Down Expand Up @@ -1568,6 +1619,53 @@ func DecodeGetPluginListResult(stack tlb.VmStack) (resultType string, resultAny
return "GetPluginListResult", result, err
}

type GetPoolAddress_StonfiResult struct {
PoolAddress tlb.MsgAddress
}

func GetPoolAddress(ctx context.Context, executor Executor, reqAccountID ton.AccountID, token0 tlb.MsgAddress, token1 tlb.MsgAddress) (string, any, error) {
stack := tlb.VmStack{}
var (
val tlb.VmStackValue
err error
)
val, err = tlb.TlbStructToVmCellSlice(token0)
if err != nil {
return "", nil, err
}
stack.Put(val)
val, err = tlb.TlbStructToVmCellSlice(token1)
if err != nil {
return "", nil, err
}
stack.Put(val)

// MethodID = 101789 for "get_pool_address" method
errCode, stack, err := executor.RunSmcMethodByID(ctx, reqAccountID, 101789, stack)
if err != nil {
return "", nil, err
}
if errCode != 0 && errCode != 1 {
return "", nil, fmt.Errorf("method execution failed with code: %v", errCode)
}
for _, f := range []func(tlb.VmStack) (string, any, error){DecodeGetPoolAddress_StonfiResult} {
s, r, err := f(stack)
if err == nil {
return s, r, nil
}
}
return "", nil, fmt.Errorf("can not decode outputs")
}

func DecodeGetPoolAddress_StonfiResult(stack tlb.VmStack) (resultType string, resultAny any, err error) {
if len(stack) != 1 || (stack[0].SumType != "VmStkSlice") {
return "", nil, fmt.Errorf("invalid stack format")
}
var result GetPoolAddress_StonfiResult
err = stack.Unmarshal(&result)
return "GetPoolAddress_StonfiResult", result, err
}

type GetPoolData_StonfiResult struct {
Reserve0 tlb.Int257
Reserve1 tlb.Int257
Expand Down
22 changes: 22 additions & 0 deletions abi/schemas/ston-fi.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,28 @@
</output>
</get_method>

<get_method name="get_pool_address">
<input>
<slice name="token0">msgaddress</slice>
<slice name="token1">msgaddress</slice>
</input>
<output version="stonfi" fixed_length="true">
<slice name="pool_address">msgaddress</slice>
</output>
</get_method>

<get_method name="get_expected_outputs">
<input>
<int name="amount">int257</int>
<slice name="token_wallet">msgaddress</slice>
</input>
<output version="stonfi" fixed_length="true">
<int name="out">int257</int>
<int name="protocol_fee_out">int257</int>
<int name="ref_fee_out">int257</int>
</output>
</get_method>

<get_method name="get_pool_data">
<output version="stonfi" fixed_length="true">
<int name="reserve0">int257</int>
Expand Down
97 changes: 97 additions & 0 deletions contract/stonfi/stonfi_swap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package stonfi

import (
"context"
"math/big"

"github.com/tonkeeper/tongo/abi"
"github.com/tonkeeper/tongo/boc"
"github.com/tonkeeper/tongo/contract/jetton"
"github.com/tonkeeper/tongo/liteapi"
"github.com/tonkeeper/tongo/tlb"
"github.com/tonkeeper/tongo/ton"
)

// Stonfi creates a swap message.
type Stonfi struct {
cli *liteapi.Client

router ton.AccountID
master0, token0 ton.AccountID
master1, token1 ton.AccountID
}

var TestnetRouter = ton.MustParseAccountID("kQBsGx9ArADUrREB34W-ghgsCgBShvfUr4Jvlu-0KGc33a1n")
var MainnetRouter = ton.MustParseAccountID("EQB3ncyBUTjZUA5EnFKR5_EnOMI9V1tTEAAPaiU71gc4TiUt")
var PTON = ton.MustParseAccountID("EQCM3B12QK1e4yZSf8GtBRT0aLMNyEsBc_DhVfRRtOEffLez")

func NewStonfi(ctx context.Context, cli *liteapi.Client, router, master0, master1 ton.AccountID) (*Stonfi, error) {
j0 := jetton.New(master0, cli)
token0, err := j0.GetJettonWallet(ctx, router)
if err != nil {
return nil, err
}
j1 := jetton.New(master1, cli)
token1, err := j1.GetJettonWallet(ctx, router)
if err != nil {
return nil, err
}
return &Stonfi{
cli: cli,
router: router,
master0: master0,
token0: token0,
master1: master1,
token1: token1,
}, nil
}

func (s *Stonfi) EstimateMinOut(ctx context.Context, amount big.Int) (*big.Int, error) {
_, value, err := abi.GetPoolAddress(ctx, s.cli, s.router, s.token0.ToMsgAddress(), s.token1.ToMsgAddress())
if err != nil {
return nil, err
}
result, ok := value.(abi.GetPoolAddress_StonfiResult)
if !ok {
return nil, err
}
pool, err := ton.AccountIDFromTlb(result.PoolAddress)
if err != nil {
return nil, err
}
_, output, err := abi.GetExpectedOutputs(context.Background(), s.cli, *pool, tlb.Int257(amount), s.token0.ToMsgAddress())
if err != nil {
return nil, err
}
result2, ok := output.(abi.GetExpectedOutputs_StonfiResult)
if !ok {
return nil, err
}
outputValue := big.Int(result2.Out)
return &outputValue, nil
}

func (s *Stonfi) MakeSwapMessage(attachedTON tlb.Grams, forwardTONAmount tlb.Grams, jettonAmount big.Int, minOut big.Int, address ton.AccountID) (*jetton.TransferMessage, error) {
payload := abi.StonfiSwapJettonPayload{
TokenWallet: s.token1.ToMsgAddress(),
MinOut: tlb.VarUInteger16(minOut),
ToAddress: address.ToMsgAddress(),
}
c := boc.NewCell()
if err := c.WriteUint(0x25938561, 32); err != nil {
return nil, err
}
if err := tlb.Marshal(c, payload); err != nil {
return nil, err
}
jettonTransfer := jetton.TransferMessage{
Sender: address,
Jetton: jetton.New(s.master0, s.cli),
JettonAmount: &jettonAmount,
Destination: s.router,
AttachedTon: attachedTON,
ForwardTonAmount: forwardTONAmount,
ForwardPayload: c,
}
return &jettonTransfer, nil
}
Loading