github.com/algorand/go-algorand-sdk@v1.24.0/templates/limitOrder.go (about)

     1  package templates
     2  
     3  import (
     4  	"encoding/base64"
     5  
     6  	"github.com/algorand/go-algorand-sdk/crypto"
     7  	"github.com/algorand/go-algorand-sdk/future"
     8  	"github.com/algorand/go-algorand-sdk/types"
     9  )
    10  
    11  // LimitOrder represents a swap between Algos and an Asset at some ratio or better.
    12  //
    13  // Deprecated: Use TealCompile source compilation instead.
    14  type LimitOrder struct {
    15  	ContractTemplate
    16  	assetID uint64
    17  	owner   string
    18  }
    19  
    20  // GetSwapAssetsTransaction returns a group transaction array which transfer funds according to the contract's ratio
    21  // assetAmount: amount of assets to be sent
    22  // contract: byteform of the contract from the payer
    23  // secretKey: secret key for signing transactions
    24  // microAlgoAmount: number of microAlgos to transfer
    25  // params: txn params for the transactions
    26  // the first payment sends money (Algos) from contract to the recipient (we'll call him Buyer), closing the rest of the account to Owner
    27  // the second payment sends money (the asset) from Buyer to the Owner
    28  // these transactions will be rejected if they do not meet the restrictions set by the contract
    29  //
    30  // Deprecated: Use TealCompile source compilation instead.
    31  func (lo LimitOrder) GetSwapAssetsTransaction(assetAmount uint64, microAlgoAmount uint64, contract, secretKey []byte, params types.SuggestedParams) ([]byte, error) {
    32  	var buyerAddress types.Address
    33  	copy(buyerAddress[:], secretKey[32:])
    34  	contractAddress := crypto.AddressFromProgram(contract)
    35  	algosForAssets, err := future.MakePaymentTxn(contractAddress.String(), buyerAddress.String(), microAlgoAmount, nil, "", params)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	assetsForAlgos, err := future.MakeAssetTransferTxn(buyerAddress.String(), lo.owner, assetAmount, nil, params, "", lo.assetID)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	gid, err := crypto.ComputeGroupID([]types.Transaction{algosForAssets, assetsForAlgos})
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	algosForAssets.Group = gid
    49  	assetsForAlgos.Group = gid
    50  
    51  	logicSig, err := crypto.MakeLogicSig(contract, nil, nil, crypto.MultisigAccount{})
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	_, algosForAssetsSigned, err := crypto.SignLogicsigTransaction(logicSig, algosForAssets)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	_, assetsForAlgosSigned, err := crypto.SignTransaction(secretKey, assetsForAlgos)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	var signedGroup []byte
    65  	signedGroup = append(signedGroup, algosForAssetsSigned...)
    66  	signedGroup = append(signedGroup, assetsForAlgosSigned...)
    67  
    68  	return signedGroup, nil
    69  }
    70  
    71  // MakeLimitOrder allows a user to exchange some number of assets for some number of algos.
    72  // Fund the contract with some number of Algos to limit the maximum number of
    73  // Algos you're willing to trade for some other asset.
    74  //
    75  // Works on two cases:
    76  // * trading Algos for some other asset
    77  // * closing out Algos back to the originator after a timeout
    78  //
    79  // trade case, a 2 transaction group:
    80  // gtxn[0] (this txn) Algos from Me to Other
    81  // gtxn[1] asset from Other to Me
    82  //
    83  // We want to get _at least_ some amount of the other asset per our Algos
    84  // gtxn[1].AssetAmount / gtxn[0].Amount >= N / D
    85  // ===
    86  // gtxn[1].AssetAmount * D >= gtxn[0].Amount * N
    87  //
    88  // close-out case:
    89  // txn alone, close out value after timeout
    90  //
    91  // Parameters:
    92  //  - owner: the address to refund funds to on timeout
    93  //  - assetID: ID of the transferred asset
    94  //  - ratn: exchange rate (N asset per D Algos, or better)
    95  //  - ratd: exchange rate (N asset per D Algos, or better)
    96  //  - expiryRound: the round at which the account expires
    97  //  - minTrade: the minimum amount (of Algos) to be traded away
    98  //  - maxFee: maximum fee used by the limit order transaction
    99  //
   100  // Deprecated: Use TealCompile source compilation instead.
   101  func MakeLimitOrder(owner string, assetID, ratn, ratd, expiryRound, minTrade, maxFee uint64) (LimitOrder, error) {
   102  	const referenceProgram = "ASAKAAEFAgYEBwgJCiYBIP68oLsUSlpOp7Q4pGgayA5soQW8tgf8VlMlyVaV9qITMRYiEjEQIxIQMQEkDhAyBCMSQABVMgQlEjEIIQQNEDEJMgMSEDMBECEFEhAzAREhBhIQMwEUKBIQMwETMgMSEDMBEiEHHTUCNQExCCEIHTUENQM0ATQDDUAAJDQBNAMSNAI0BA8QQAAWADEJKBIxAiEJDRAxBzIDEhAxCCISEBA="
   103  	referenceAsBytes, err := base64.StdEncoding.DecodeString(referenceProgram)
   104  	if err != nil {
   105  		return LimitOrder{}, err
   106  	}
   107  
   108  	var referenceOffsets = []uint64{ /*maxFee*/ 5 /*minTrade*/, 7 /*assetID*/, 9 /*ratd*/, 10 /*ratn*/, 11 /*expiryRound*/, 12 /*ownerAddr*/, 16}
   109  	ownerAddr, err := types.DecodeAddress(owner)
   110  	if err != nil {
   111  		return LimitOrder{}, err
   112  	}
   113  	injectionVector := []interface{}{maxFee, minTrade, assetID, ratd, ratn, expiryRound, ownerAddr}
   114  	injectedBytes, err := inject(referenceAsBytes, referenceOffsets, injectionVector)
   115  	if err != nil {
   116  		return LimitOrder{}, err
   117  	}
   118  
   119  	address := crypto.AddressFromProgram(injectedBytes)
   120  	lo := LimitOrder{
   121  		ContractTemplate: ContractTemplate{
   122  			address: address.String(),
   123  			program: injectedBytes,
   124  		},
   125  		owner:   owner,
   126  		assetID: assetID,
   127  	}
   128  	return lo, err
   129  }