TokenPay
für Entwickler

Verstehe mehr über die innovative Funktionsweise von TokenPay und lerne unterschiedliche Integrations- und Whitelabelingmöglichkeiten kennen.

TokenPay löst mit technischen Innovationen grundlegende Strukturprobleme der Blockchain im Zahlungsverkehr

Die innovativen TokenPay Smart-Contracts lösen bekannte Strukturprobleme dezentraler Tauschprozesse im Hinblick auf Arbitrage- und Wechselkursrisiken unter optimaler Verwendung der verfügbaren Liquidität. Überwiegend auf bekannte Liquidity-Pool-Schemata aufbauend, bilden diese Smart-Contracts den Kern der TokenPay Technologie, welcher um unterschiedliche dezentral verfügbare Systeme, wie beispielsweise Bridges und dezentrale Exchanges, erweitert wird. Dabei werden immer bestehende verifizierte Smart-Contracts zum kontinuierlichen Monitoring der Marktsituation und einem erweiterten dezentralen Liquiditätsmanagement verwendet. 

Wechselkursrisiko

Arbitrage

Das Wechselkursrisiko bei der Nutzung der Blockchain entsteht durch den Einsatz eines Intermediär.

TokenPay schafft es technisch das Wechselkursrisiko vollständig aus dem Transaktionsprozess herauszunehmen. Die technische Lösung involiert neue Smart-Contracts und eine besondere Art Transaktionen zu verknüpfen.

Cross-Hierarchy Smart-Contracts

Die neuen Smart-Contracts von TokenPay erlauben es bei einer Liqudity-Pool-Transaktion „cross-hierarchy“ wechselnd eine andere Empfänger-Adresse anzugeben. Dadurch wird das Ergebnis des Liquidity-Pool-Swaps, die Stablecoins, direkt an die Wallet-Adresse des Händlers gesendet.

Bündelung von Transaktionen

Die neue Liquidity-Pool-Implementierung sowie das besondere Broadcasting der Transaktionen an die Nodes ermöglichen es mehrere Transaktionen direkt hintereinander innerhalb eines Blocks auszuführen, sodass sich der Wechselkurs des genutzten Intermediärs zwischen den beiden Transaktionen technisch nicht verändern kann.

Die Arbitrage bei der Nutzung der Blockchain entsteht durch den fehlenden Ausgleich des Geldflusses

TokenPay gelingt es durch technische Maßnahmen, die Arbitrage aus dem Transaktionsprozess herauszunehmen. Dazu werden Utility-Tokens, welche den Umlauf unterschiedlicher Assets effizienter bemessen und dezentrale Liquidity-Pools mit integrierten Market-Making-Algorithmen kombiniert.

Dezentrale Market-Maker-Pools

Die neuartige mehrstufige Pool-Struktur von TokenPay ermöglicht es, dass die jeweiligen Währungen eines Pools über einen übergeordneten Pool gegeneinander ausgeglichen werden. Dieser Ausgleich findet anhand der stattgefundenen Transaktionen statt und simuliert so die Funktion einer Zentralbank in klassischen Währungsmärkten. Zusätzlich werden Oracles und Bridging- sowie DEX-Protokolle miteinbezogen, um die verfügbare Liquidität möglichst effizient zu verwenden.

Umlauf-Bemessungs-Tokens

Auf der Blockchain können nicht einfach „Variablen“ gespeichert werden. Deshalb haben wir verschiedene Utility-Tokens im Hintergund geschaffen, die es den einzelnen Smart-Contracts dezentral ermöglichen, mithilfe des Account-Stands der jeweiligen Utility-Tokens einen Umlaufbestand und eine zeitliche Veränderung des Intermediärs abzulesen. Basierend darauf kann ohne ein externe Instanz und die damit verbundenen Integritätsrisiken der Geldfluss verschiedener Währungen sowie Stablecoins ausgeglichen werden.

TokenPay Smart-Contracts sind dezentral und haben keinen Einfluss auf die Transaktionen

Geld

TokenPay hat zu keinem Zeitpunkt, weder während, vor oder nach einer Transaktion, Zugriff auf Gelder von Dritten und erhält auch keine besonderen Transaktionsgebühren.

Daten

TokenPay kennt keine personenbezogenen Transaktionsdaten, keine Einkaufshistorie und bezieht sich grundsätzlich nur auf die öffentlichen Daten der Blockchain, sowie durch den Kunden angegebene Kundendaten.

Einfluss

TokenPay kann weder Transaktionen verhindern, noch Transaktionen rückgängig machen. Grundsätzlich hat TokenPay keinen direkten Einfluss auf Transaktionen, Sender oder Empfänger und verwendete Währungen.

TokenPay in wenigen Schritten in Deine Anwendung integrieren

TokenPay E-Commerce per Plug-In integrieren

Voraussetzungen

Aktuell stehen für TokenPay E-Commerce Plug-Ins für die Online-Shop Baukastensysteme WordPress/WooCommerce und Shopware zur Verfügung. Zudem befindet sich ein Plug-In für das Online-Shop Baukastensystem Shopify in der Entwicklung.
Zur Integration benötigst Du Zugriff auf die Administrations-Oberfläche des jeweiligen Baukastensystems. 
Bitte frage das jeweilig benötigte Plug-In über das Kontaktformular an. 

 

Ähnlich wie andere Zahlungs-Lösungen erfordert TokenPay eine Verbindung mit Deinem Online-Shop und dem Unternehmenskunden-Dashboard. Im Zahlungsprozess wird der Endkunde von der Checkout-Seite auf eine einmalige Zahlungs-Seite geleitet, welche auf https://checkout.usetokenpay.com gehostet ist. Nach der finalisierten Zahlung wird der Endkunde auf eine individuell einstellbare Seite weitergeleitet.

Für WordPress:

Stelle sicher, das WooCommerce auf Deiner WordPress-Seite installiert und eingerichtet ist. Lade Die ZIP-Quellcodedatei, welche Du von unserem Support-Team erhalten hast, als neues Plug-In hoch. Bestätige die Installation und aktiviere das Plug-In. Anschließend kannst Du die Zahlungsmodalität unter WooCommerce / Einstellungen / Zahlungen / TokenPay aktivieren und den auf Deiner Checkout-Seite angezeigten Titel und Beschreibungstext individualisieren. Speichere Deine Änderungen.

Kopiere ebenfalls die angezeigte Webhook. Diese muss anschließend mit dem Unternehmenskunden-Dashboard verknüpft werden.

Für Shopware:

Öffne das Shopware-Admin-Panel. Um darauf zugreifen zu können, ist es möglicherweise notwendig, ein separates Browser-Fenster zu öffnen und Deinen Cache zu leeren. Lade die ZIP-Quellcodedatei, welche Du von unserem Support-Team erhalten hast, als neues Plug-In hoch. Bestätige die Installation und aktiviere das Plug-In. 

Anschließend findest Du unter den „Storefront“ Einstellungen den Bereich „Zahlungen und Versand“. Aktiviere hier das TokenPay Zahlungs-Gateway. 

Navigiere danach zu Einstellungen / Zahlungsmethode und aktiviere das Gateway ebenfalls. Hier kannst du zudem unter „technischen Details“ die aktuelle Webhook einsehen. Diese muss anschließend mit dem Unternehmenskunden-Dashboard verknüpft werden. Speichere Deine Änderungen.

Der Access Key ist ein einmaliger Schlüssel, welcher benötigt wird, um Checkout-Sessions generieren zu können. Dieser ist eindeutig Deinem Unternehmenskunden-Account zugeordnet. 

Bitte eine vertretungsberechtigte Person oder eine durch diese autorisierte Person einen Unternehmenskunden-Account für TokenPay zu erstellen. Anschließend müssen die öffentlich einsehbaren Einstellungen zur Konfiguration der Checkout-Session unter „Einstellungen“ (rechts oben) vervollständigt werden. Hierbei ist es verpflichtend, die vollständigen Impressums-Informationen sowie ein Unternehmens-Logo und eine Hintergrundfarbe zur Individualisierung der Checkout-Sessions hochzuladen. Zudem können hier die Weiterleitungs-URLs für einen erfolgreiche und eine fehlgeschlagene Zahlung festgelegt werden. Um auf die automatisch generierten „Thank You“-Seiten der Baukasten-Systeme zurückzuleiten, ist es meistens ausreichend die Basis-URL des Online-Shops anzugeben. Füge im letzten Schritt unter „Erfolgs-URL“ und „Fehler-URL“ die kopierte Endpunkt-URL ein – diese ist für beide Felder identisch. Speichere anschließend Deine Daten. Nun kannst Du Deinen Access Key kopieren.

Füge nun auf den entsprechenden Einstellungs-Seiten Deines Baukastensystems den Access Key ein. Ab jetzt ist es möglich mit TokenPay E-Commerce Zahlungen zu akzeptieren.

TokenPay E-Commerce per API integrieren

Voraussetzungen

Zur Integration von TokenPay in individuelle Online-Shops steht eine RESTful-API zur Verfügung.

 

Ähnlich wie andere Zahlungs-Lösungen erfordert TokenPay eine Verbindung mit Deinem Online-Shop und dem Unternehmenskunden-Dashboard. Im Zahlungsprozess wird der Endkunde von der Checkout-Seite auf eine einmalige Zahlungs-Seite geleitet, welche auf https://checkout.usetokenpay.com gehostet ist. Nach der finalisierten Zahlung wird der Endkunde auf eine individuell einstellbare Seite weitergeleitet.

Die bereitgestellte API bietet einen detaillierten Mechanismus für die Annahme von Krypto-Zahlungen, deren Verifizierung und die Reaktion auf verschiedene Szenarien. Eines der Hauptmerkmale dieser Zahlungsinfrastruktur ist die Verwendung von Webhooks, um den Transaktionsstatus an den Server des Online-Shops weiterzuleiten.

Wenn eine Webhook ausgelöst wird, sendet sie eine POST-Anfrage an den konfigurierten Endpunkt mit einer JSON-Antwort.

				
					/*
Webhook Types:

payment_success:
Triggered when a payment has been successfully verified.
payment_failed: 
Triggered when a payment verification fails, or when there's an issue with the payment.

Events:
Payment Success:
type: Always`payment_success`
customId: Custom identifier for the session or order
Payment Failed:
type: Always `payment_failed`
customId: Custom identifier for the session or order
*/
				
			

Best-Practices beim Aufsetzen von Webhooks:

  • Die Webhooks werden in jedem Fall eine „200 OK“ Response zurückgeben, auch wenn das Event „payment_failed“ ist.
  • Logge alle erhaltenen Webhooks. Dies hilft für eine mögliche Fehlerbehebung und stellt sicher, dass alle Events verarbeitet werden.
  • Redundante Webhook-Listener einrichten: Wenn ein primärer Listener ausfällt, kann ein Backup den Tag retten.
  • Überwachen: Überprüfe in regelmäßigen Abständen, ob Deine Webhook-Listener funktionsfähig sind. Warnmechanismen können von unschätzbarem Wert sein.
  • Performance: Entwerfe den Webhook-Handler so, dass er den Empfang sofort bestätigt und die Nutzdaten erst danach verarbeitet. Auf diese Weise wird sichergestellt, dass der sendende Dienst nicht warten muss, und die Gefahr redundanter Zustellungen wird verringert.

Der Access Key ist ein einmaliger Schlüssel, welcher benötigt wird, um Checkout-Sessions generieren zu können. Dieser ist eindeutig Deinem Unternehmenskunden-Account zugeordnet. 

Bitte eine vertretungsberechtigte Person oder eine durch diese autorisierte Person einen Unternehmenskunden-Account für TokenPay zu erstellen. Anschließend müssen die öffentlich einsehbaren Einstellungen zur Konfiguration der Checkout-Session unter „Einstellungen“ (rechts oben) vervollständigt werden. Hierbei ist es verpflichtend, die vollständigen Impressums-Informationen sowie ein Unternehmens-Logo und eine Hintergrundfarbe zur Individualisierung der Checkout-Sessions hochzuladen. Zudem können hier die Weiterleitungs-URLs für einen erfolgreiche und eine fehlgeschlagene Zahlung festgelegt werden. Füge im letzten Schritt unter „Erfolgs-URL“ und „Fehler-URL“ die erstellten Webhook-Endpunkt-URLs ein – es ist ebenfalls möglich, denselben Endpunkt für beide Event-Typen anzugeben. Speichere anschließend Deine Daten. Nun kannst Du Deinen Access Key / API-Endpunkt kopieren.

Die Funktion „createCheckoutSession“ dient als Endpunkt zum erstellen von einmaligen Checkout-Sessions.

 

				
					/*
Parameters:

- req (Object): The incoming request object.
    - req.query.accessKey (String): A UUID4 key to access the checkout configuration.
    - req.body.items (Array): An array of items for the checkout session. This is mandatory and must adhere to the specified format.
    - req.body.customId (String): An optional custom identifier for the checkout session.
    - req.body.successUrl (String): An optional URL where the user is redirected upon successful checkout.
- res (Object): The response object used to send responses back to the caller.
- next (Function): Express middleware function to pass control to the next handler.

Items Format:

Items provided in the req.body.items should be an array of objects with the following format:

items: [
  {
    name: "Special Item",   // Item name
    price: 0.001,           // Item price
    quantity: 1             // Quantity of the item
  },
  {
    name: "Another Item",
    price: 0.001,
    quantity: 1
  }
]

Response Format

The successful response will contain:

- url (String): A URL redirecting to the frontend checkout page with the session's ID.
- session (Object): An object containing:
    - id (String): The session's ID.
    - total (Number): The total amount for the checkout session.
    - items (Array): The items for the checkout session.
    - paymentStatus (String): The payment status for the checkout session.
    - customId (String): An optional custom identifier for the checkout session.
    - successUrl (String): The URL where the user is redirected upon a successful checkout.

Errors and Status Codes

The function can return various HTTP status codes and errors:

- 400: For invalid access keys, invalid items format or count, items missing required fields, invalid `successUrl` formats.
- 404: When the provided `accessKey` does not match any existing checkout configurations.
- 500: If any internal server errors occur.

Example Usage

Initiate a checkout session by sending a `POST` request to the endpoint where this function is mounted, with the required parameters in the body and query string.

Example Request:

POST https://BASE_URL/checkoutSession/V1/createCheckoutSession?accessKey=YOUR_ACCESS_KEY
{
  "items": [
    {
      "name": "Special Item",
      "price": 0.001,
      "quantity": 1
    },
    {
      "name": "Another Item",
      "price": 0.001,
      "quantity": 1
    }
  ],
  "customId": "YOUR_CUSTOM_ID",
  "successUrl": "http://example.com/success"
}

Example Response:

{
  "url": "https://BASE_URL/SESSION_ID",
  "session": {
    "id": "SESSION_ID",
    "total": 0.002,
    "items": [...],
    "paymentStatus": "pending",
    "customId": "YOUR_CUSTOM_ID",
    "successUrl": "http://example.com/success"
  }
}
*/
				
			

TokenPay Point of Sale per API integrieren

Informationen

Zur Integration von TokenPay in individuelle Online-Shops steht eine RESTful-API zur Verfügung.

TokenPay Point of Sale steht als statische QR-Code-Lösung oder als dynamische QR-Code-Lösung in Verbindung mit einem Endgerät Deiner Wahl vor Ort zur Verfügung. Um die bestmöglichste Effizienz und Nutzererfahrung vor Ort zu erreichen, individualisieren wir die Schnittstellen und Nutzeroberflächen gerne nach Deinem Bedarf.

Zudem stellen wir gerne eine Schnittstelle zu Deinen Kassensystemen oder eine individualisierte Übersicht auf Deinen Endgeräten vor Ort bereit. Ebenfalls ist es möglich, die Checkout-Sessions individuell anzupassen, und beispielsweise Umfrage-Elemente zu ergänzen. Nimm‘ jetzt Kontakt auf um mehr über die Möglichkeiten zu erfahren.

TokenPay Blockchain in Ihre Anwendung integrieren

Informationen

TokenPay nutzt zur Bündelung aller Daten und zum Settlement der meisten Transaktionen die Polygon-Blockchain. Weitere Blockchains werden über Bridges angebunden. 

Ähnlich wie andere Zahlungs-Lösungen erfordert TokenPay eine Verbindung mit Deinem Online-Shop und dem Unternehmenskunden-Dashboard. Im Zahlungsprozess wird der Endkunde von der Checkout-Seite auf eine einmalige Zahlungs-Seite geleitet, welche auf https://checkout.usetokenpay.com gehostet ist. Nach der finalisierten Zahlung wird der Endkunde auf eine individuell einstellbare Seite weitergeleitet. Dieser Ablauf wird ebenfalls verwendet, wenn Du TokenPay Blockchain in Deine zentrale Schnittstelle einbindest.

Darüber hinaus ist es ebenfalls möglich, TokenPay Blockchain direkt auf Smart-Contract-Ebene zu integrieren. In diesem Fall ist eine Integration auf der Polygon-Blockchain notwendig. Sollte Dein Projekt nicht oder nicht primär auf Polygon aktiv sein, ist es ebenfalls möglich, Interchain-Messaging-Protokolle, die mit den emittierten Events der TokenPay Smart-Contracts interagieren, aufzusetzen. So bleibt TokenPay Blockchain auch innerhalb der Blockchain-Welt technologieoffen. Gerne unterstützen wir Dich auch bei der Entwicklung einer maßgeschneiderten Lösung.

Den aktuellen TokenPay-Factory-Contract findest Du hier.

Den aktuellen TokenPay-Router-Contract findest Du hier.

Den aktuellen Intermediär-Token-Contract findest Du hier.

Bitte beachte, dass sich alle Deployment-Adressen auf Polygon-Mainnet beziehen.

Weitere Routings, Kalkulationen und Integrationen von Partnern finden zentral statt und werden jeweils durch die Endnutzer in den Genehmigungs-Anfragen mit jeweiligen Wallets einzeln bestätigt. 

Die Integration von TokenPay Blockchain in zentrale Systeme erfolgt analog zu der Integration von TokenPay E-Commerce.

Die Integration der TokenPay Smart-Contracts kann flexibel nach Deinem Bedarf erfolgen. Folgend findest Du die Code-Referenz des aktuellen TokenPay SwapRouter-Entrypoint-Contracts – weitere Interfaces findest Du hier:

				
					// SPDX-License-Identifier: unlicensed
// (c) Copyright 2024 Kolibri GmbH, all rights reserved
pragma solidity ^0.8.9;

import '../../core/interfaces/one-to-one/ISwapFactory.sol';
import '../interfaces/one-to-one/ISwapRouter.sol';
import '../../core/interfaces/ISwapPair.sol';
import '../../core/interfaces/ISwapERC20.sol';
import '../libraries/SafeMath.sol';

contract SwapRouter is ISwapRouter {
  using SafeMath for uint;

  address public immutable override factory;
  address public immutable override WETH;

  modifier ensure(uint deadline) {
    require(deadline >= block.timestamp, 'SwapRouter: EXPIRED');
    _;
  }

  uint private unlocked = 1;
  modifier lock() {
    require(unlocked == 1, 'Swap: LOCKED');
    unlocked = 0;
    _;
    unlocked = 1;
  }

  modifier onlyNormal() {
    if (ISwapFactory(factory).getEoaWhitelist(msg.sender)) {
    } else {
      require(tx.origin == msg.sender, 'SwapRouter: onlyNormal failed'); 
    }
    _;
  }

  modifier once(address pair) {
    if (!ISwapFactory(factory).getOnce(pair, msg.sender)) {
    } else {
      if (ISwapFactory(factory).getEoaWhitelist(msg.sender)) {
      } else {
        require(false, 'SwapRouter: Once failed');
      }
    }
    _;
    ISwapFactory(factory).addOnce(pair, msg.sender);
  }

  constructor(address _factory, address _WETH) {
    factory = _factory;
    WETH = _WETH;
  }

  receive() external payable {
    assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
  }

  function getBlockNumber() private view onlyNormal returns (uint blockNumber) {
    blockNumber = block.number;
  }

  // **** ADD LIQUIDITY ****
  function _addLiquidity(
    address tokenA,
    address tokenB,
    uint amountADesired,
    uint amountBDesired
  ) private onlyNormal returns (uint amountA, uint amountB) {
    // create the pair if it doesn't exist yet
    if (ISwapFactory(factory).getPair(tokenA, tokenB) == address(0)) {
      ISwapFactory(factory).createPair(tokenA, tokenB);
    }
    (amountA, amountB) = (amountADesired, amountBDesired);
  }

  function addLiquidity(
    address tokenA,
    address tokenB,
    uint amountADesired,
    uint amountBDesired,
    address to,
    uint deadline
  ) external override ensure(deadline) lock onlyNormal once(pairFor(tokenA, tokenB)) returns (uint amountA, uint amountB, uint liquidity) {
    (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired);
    address pair = pairFor(tokenA, tokenB);
    safeTransferFrom(tokenA, msg.sender, pair, amountA);
    safeTransferFrom(tokenB, msg.sender, pair, amountB);
    liquidity = ISwapPair(pair).mint(to);
    ISwapFactory(factory).addTime(pair, msg.sender);
  }

  // **** REMOVE LIQUIDITY ****
  function removeLiquidity(
    address tokenA,
    address tokenB,
    uint liquidity,
    address to,
    uint deadline
  ) public override ensure(deadline) lock onlyNormal returns (uint amountA, uint amountB) {
    address pair = pairFor(tokenA, tokenB);
    require(ISwapFactory(factory).getTime(pair, msg.sender) + ISwapFactory(factory).getTimeToElapse() < getBlockNumber(), 'SwapRouter: Wait for elapsed time');
    ISwapPair(pair).transferFrom(msg.sender, pair, liquidity, factory); // send liquidity to pair
    (uint amount0, uint amount1) = ISwapPair(pair).burn(to);
    (address token0, ) = sortTokens(tokenA, tokenB);
    (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
  }

  // **** SWAP ****
  // requires the initial amount to have already been sent to the first pair
  function _swap(uint[] memory amounts, address[] memory path, address _to) private {
    for (uint i; i < path.length - 1; i++) {
      (address input, address output) = (path[i], path[i + 1]);
      (address token0, ) = sortTokens(input, output);
      uint amountOut = amounts[i + 1];
      (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
      address to = i < path.length - 2 ? pairFor(output, path[i + 2]) : _to;
      ISwapPair(pairFor(input, output)).swap(amount0Out, amount1Out, to, new bytes(0));
    }
  }

  function swapExactTokensForTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
  ) external override ensure(deadline) lock onlyNormal returns (uint[] memory amounts) {
    amounts = getAmountsOutInternal(amountIn, path);
    require(amounts[amounts.length - 1] >= amountOutMin, 'SwapRouter: INSUFFICIENT_OUTPUT_AMOUNT');
    safeTransferFrom(path[0], msg.sender, pairFor(path[0], path[1]), amounts[0]);
    _swap(amounts, path, to);
  }

  function doubleSwapExactTokensForTokens(
    uint amountInFirst,
    uint amountInSecond,
    uint amountOutMinFirst,
    uint amountOutMinSecond,
    address[] calldata pathFirst,
    address[] calldata pathSecond,
    address toSecond,
    uint deadline
  ) external override ensure(deadline) lock onlyNormal returns (uint[] memory amountsFirst, uint[] memory amountsSecond) {

    // Make sure it is a double swap
    require(pathFirst[0] == pathSecond[1] && pathFirst[1] == pathSecond[0], 'SwapRouter: INPUT_PATH_MISMATCHING');

    // First swap
    amountsFirst = getAmountsOutInternal(amountInFirst, pathFirst);
    require(amountsFirst[amountsFirst.length - 1] >= amountOutMinFirst, 'SwapRouter: INSUFFICIENT_OUTPUT_AMOUNT');
    safeTransferFrom(pathFirst[0], msg.sender, pairFor(pathFirst[0], pathFirst[1]), amountsFirst[0]);
    _swap(amountsFirst, pathFirst, msg.sender);

    // Second swap
    amountsSecond = getAmountsOutInternal(amountInSecond, pathSecond);
    require(amountsSecond[amountsSecond.length - 1] >= amountOutMinSecond, 'SwapRouter: INSUFFICIENT_OUTPUT_AMOUNT');
    safeTransferFrom(pathSecond[0], msg.sender, pairFor(pathSecond[0], pathSecond[1]), amountsSecond[0]);
    _swap(amountsSecond, pathSecond, toSecond);
  }

  function getAmountsOut(
    uint amountIn,
    address[] memory path
  ) public override lock onlyNormal returns (uint[] memory amounts) {
    return getAmountsOutInternal(amountIn, path);
  }

  function safeTransferFrom(
    address token,
    address from,
    address to,
    uint256 value
  ) private onlyNormal {
      // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
      (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
      require(
          success && (data.length == 0 || abi.decode(data, (bool))),
          'SwapRouter::transferFrom: transferFrom failed'
      );
  }

  // returns sorted token addresses, used to handle return values from pairs sorted in this order
  function sortTokens(address tokenA, address tokenB) private view onlyNormal returns (address token0, address token1) {
    require(tokenA != tokenB, 'SwapRouter: IDENTICAL_ADDRESSES');
    (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
    require(token0 != address(0), 'SwapRouter: ZERO_ADDRESS');
  }

  function pairFor(address tokenA, address tokenB) private view onlyNormal returns (address pair) {
    (address token0, address token1) = sortTokens(tokenA, tokenB);
    pair = ISwapFactory(factory).getPair(token0, token1);
  }

  // fetches and sorts the reserves for a pair
  function getReserves(
    address tokenA,
    address tokenB
  ) private view onlyNormal returns (uint reserveA, uint reserveB) {
    (address token0, ) = sortTokens(tokenA, tokenB);
    (uint reserve0, uint reserve1, ) = ISwapPair(pairFor(tokenA, tokenB)).getReserves();
    (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
  }

    // given an input amount of an asset returns the maximum output amount of the other asset
  function getAmountOut(
    uint amountIn,
    uint reserveIn,
    uint reserveOut,
    address outTokenAddr,
    address inTokenAddr
  ) private view onlyNormal returns (uint amountOut) {
    require(amountIn > 0, 'SwapRouter: INSUFFICIENT_INPUT_AMOUNT');
    require(reserveIn > 0 && reserveOut > 0, 'SwapRouter: INSUFFICIENT_LIQUIDITY');
    ISwapERC20 outToken = ISwapERC20(outTokenAddr);
    ISwapERC20 inToken = ISwapERC20(inTokenAddr);
    uint amount;
    if (outToken.decimals() == inToken.decimals()) {
      amount = amountIn;
    } else {
      if (outToken.decimals() > inToken.decimals()) {
        uint8 decimalsDiff = outToken.decimals() - inToken.decimals();
        amount = amountIn * 10 ** decimalsDiff;
      } else {
        uint8 decimalsDiff = inToken.decimals() - outToken.decimals();
        amount = amountIn / 10 ** decimalsDiff;
      }
    }
    ISwapFactory factoryInstance = ISwapFactory(factory);

    // If swapped from any to UHU / ALPHA / ...: Deduct fee
    uint amountAfterSwappingFee;
    if (factoryInstance.feeableTokens(outTokenAddr)) {
      amountAfterSwappingFee = amount.mul((1000 - factoryInstance.getFeeBase())) / 1000;
    } else { 
      // If swapped from any to any: Deduct no fee; 1:1 curve
      amountAfterSwappingFee = amount;
    }
    
    // If inToken is feeable
    if (factoryInstance.feeableTokens(inTokenAddr)) {
      if (factoryInstance.feeableTokens(outTokenAddr)) {
        amountOut = amountAfterSwappingFee;
      } else {
        amountOut = amountAfterSwappingFee * 1000 / factoryInstance.getCurrencyConversion(outTokenAddr);
      }
    } else { // If inToken is not feeable (all other tokens)
      if (factoryInstance.feeableTokens(outTokenAddr)) {
        amountOut = amountAfterSwappingFee.mul(factoryInstance.getCurrencyConversion(inTokenAddr)) / 1000;
      } else {
        amountOut = amountAfterSwappingFee * factoryInstance.getCurrencyConversion(inTokenAddr) / factoryInstance.getCurrencyConversion(outTokenAddr);
      }
    }
  }

  // performs chained getAmountOut calculations on any number of pairs
  function getAmountsOutInternal(
    uint amountIn,
    address[] memory path
  ) private view onlyNormal returns (uint[] memory amounts) {
    require(path.length >= 2, 'SwapRouter: INVALID_PATH');
    amounts = new uint[](path.length);
    amounts[0] = amountIn;
    for (uint i; i < path.length - 1; i++) {
      (uint reserveIn, uint reserveOut) = getReserves(path[i], path[i + 1]);
      amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut, path[i + 1], path[i]);
    }
  }

}
				
			

TokenPay Payment Links per API integrieren

Informationen

TokenPay Payment Links sind als No-Code-Lösung konzeptioniert und ermöglichen Dir eine vollständige Konfiguration und Verwaltung in Deinem TokenPay Unternehmenskunden-Account.

Solltest Du dennoch an einer individualiserten Lösung zur Massen-Verwaltung von Payment Links interessiert sein, kontaktiere uns gerne.

 

Kontakt aufnehmen

de_DE_formalGerman