├── packages ├── sdk │ ├── .gitignore │ ├── src │ │ ├── adaptors │ │ │ ├── zksync │ │ │ │ ├── ZksyncAdaptor.ts │ │ │ │ └── index.ts │ │ │ ├── ethers │ │ │ │ ├── EthersAdaptor.ts │ │ │ │ ├── index.ts │ │ │ │ └── extendProvider.ts │ │ │ ├── bitcoin │ │ │ │ └── BtcClient.ts │ │ │ ├── starknet │ │ │ │ ├── parse │ │ │ │ │ ├── v1.json │ │ │ │ │ ├── v0.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── execute.json │ │ │ │ └── StarkWallet.ts │ │ │ ├── types.ts │ │ │ ├── tron │ │ │ │ ├── index.ts │ │ │ │ ├── TronWallet.ts │ │ │ │ └── TronContract.ts │ │ │ ├── aptos │ │ │ │ └── AptosWallet.ts │ │ │ ├── solana │ │ │ │ └── SolanaWallet.ts │ │ │ └── ton │ │ │ │ ├── types │ │ │ │ └── index.ts │ │ │ │ └── TonWallet.ts │ │ ├── index.ts │ │ ├── SwapWithSigner.ts │ │ ├── Rpc.ts │ │ └── SignedSwap.ts │ ├── tsconfig.json │ ├── package.json │ └── tests │ │ ├── SwapWithSigner.spec.ts │ │ └── shared │ │ └── index.ts ├── presets │ ├── .gitignore │ ├── src │ │ ├── index.ts │ │ ├── providers.ts │ │ └── CustomFeeProvider.ts │ ├── tsconfig.json │ ├── package.json │ └── scripts │ │ ├── make-mainnets.js │ │ └── make-testnets.js ├── client │ ├── .gitignore │ ├── src │ │ ├── index.ts │ │ └── types.ts │ ├── tsconfig.json │ ├── package.json │ └── test │ │ └── demo.ts ├── rpc │ ├── .gitignore │ ├── src │ │ ├── rpcs.ts │ │ ├── index.ts │ │ ├── types.ts │ │ ├── MesonRpcs.ts │ │ ├── MesonRpcStatusCache.ts │ │ └── MesonRpcMonitor.ts │ ├── tsconfig.json │ └── package.json ├── adaptors │ ├── .gitignore │ ├── src │ │ ├── tron │ │ │ ├── address.ts │ │ │ ├── type.ts │ │ │ ├── index.ts │ │ │ ├── wallet.ts │ │ │ └── contract.ts │ │ ├── starknet │ │ │ ├── address.ts │ │ │ ├── parse │ │ │ │ ├── v1.json │ │ │ │ ├── v0.json │ │ │ │ ├── index.ts │ │ │ │ └── execute.json │ │ │ ├── type.ts │ │ │ └── index.ts │ │ ├── ethers │ │ │ ├── address.ts │ │ │ ├── wallet.ts │ │ │ ├── type.ts │ │ │ ├── index.ts │ │ │ └── client.ts │ │ ├── index.ts │ │ ├── solana │ │ │ ├── address.ts │ │ │ ├── index.ts │ │ │ └── type.ts │ │ ├── ton │ │ │ ├── address.ts │ │ │ ├── index.ts │ │ │ ├── type.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── sui │ │ │ ├── address.ts │ │ │ ├── index.ts │ │ │ └── type.ts │ │ ├── aptos │ │ │ ├── address.ts │ │ │ ├── index.ts │ │ │ ├── type.ts │ │ │ └── wallet.ts │ │ ├── ckb │ │ │ ├── address.ts │ │ │ ├── index.ts │ │ │ └── type.ts │ │ ├── adaptors.ts │ │ ├── bitcoin │ │ │ ├── address.ts │ │ │ ├── index.ts │ │ │ └── type.ts │ │ ├── all.ts │ │ ├── MesonAdaptorConfigManager.ts │ │ └── MesonNetworkClientBase.ts │ ├── tsconfig.json │ └── package.json ├── clients │ ├── .gitignore │ ├── src │ │ ├── index.ts │ │ └── MesonClients.ts │ ├── tsconfig.json │ └── package.json └── base │ ├── .gitignore │ ├── src │ ├── types │ │ ├── MesonBalance.ts │ │ ├── index.ts │ │ ├── MesonPresets.ts │ │ ├── MesonToken.ts │ │ ├── MesonContract.ts │ │ ├── MesonSalt.ts │ │ └── MesonNetwork.ts │ ├── const │ │ ├── AddressFormat.ts │ │ ├── index.ts │ │ └── CategoryTokenMap.ts │ ├── index.ts │ ├── utils │ │ └── salt.ts │ └── meson │ │ ├── MesonToken.ts │ │ └── MesonPresets.ts │ ├── tsconfig.json │ └── package.json ├── scripts ├── data │ └── .gitignore ├── deploy-forward.js ├── lib │ ├── getAdaptor.js │ ├── updatePresets.js │ ├── CustomGasFeeProviderWrapper.js │ └── deploy.js ├── copy-abis.js ├── upgrade.js ├── copy-types.js ├── pool.js ├── config │ ├── set-chain-config.js │ └── MesonConfig.sol ├── deploy.js └── estimate-gas.js ├── .env.local ├── .gitattributes ├── funding.json ├── .gitignore ├── .vscode └── settings.json ├── test └── shared │ ├── expect.ts │ ├── wallet.ts │ ├── meson.ts │ └── fixtures.ts ├── contracts ├── Meson.sol ├── test │ ├── MesonPoolsTest.sol │ ├── MockToken.sol │ ├── MesonSwapTest.sol │ ├── ForwardTokenContract.sol │ └── MesonStatesTest.sol ├── UpgradableMeson.sol ├── Proxy2ToMeson.sol ├── interfaces │ ├── IDepositWithBeneficiary.sol │ └── IERC20Minimal.sol ├── ProxyToMeson.sol ├── Swap │ └── IMesonSwapEvents.sol ├── Pools │ └── IMesonPoolsEvents.sol ├── TransferToMesonContract.sol └── Token │ └── UCTUpgradeable.sol ├── config.json ├── tsconfig.json ├── .github └── workflows │ ├── test_dev.yaml │ └── test.yaml ├── tsconfig.eslint.json ├── .eslintrc.js └── templates └── contract.hbs /packages/sdk/.gitignore: -------------------------------------------------------------------------------- 1 | /lib 2 | -------------------------------------------------------------------------------- /scripts/data/.gitignore: -------------------------------------------------------------------------------- 1 | *.json -------------------------------------------------------------------------------- /packages/presets/.gitignore: -------------------------------------------------------------------------------- 1 | /lib 2 | -------------------------------------------------------------------------------- /.env.local: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY= 2 | LP_PRIVATE_KEY= 3 | PREMIUM_MANAGER= 4 | -------------------------------------------------------------------------------- /packages/client/.gitignore: -------------------------------------------------------------------------------- 1 | /abis 2 | /lib 3 | /es 4 | tsconfig.tsbuildinfo 5 | -------------------------------------------------------------------------------- /packages/rpc/.gitignore: -------------------------------------------------------------------------------- 1 | /abis 2 | /lib 3 | /es 4 | tsconfig.tsbuildinfo 5 | -------------------------------------------------------------------------------- /packages/adaptors/.gitignore: -------------------------------------------------------------------------------- 1 | /abis 2 | /lib 3 | /es 4 | tsconfig.tsbuildinfo 5 | -------------------------------------------------------------------------------- /packages/clients/.gitignore: -------------------------------------------------------------------------------- 1 | /lib 2 | /es 3 | tsconfig.tsbuildinfo 4 | /lib-dist 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /packages/base/.gitignore: -------------------------------------------------------------------------------- 1 | /abis 2 | /lib 3 | /es 4 | tsconfig.tsbuildinfo 5 | /lib-dist 6 | /es-dist 7 | -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0xdc28e29764ca79368f426f106458f2c427392e32d088b04f4c372ab51b25d2cf" 4 | } 5 | } -------------------------------------------------------------------------------- /packages/client/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | export * from './types' 6 | 7 | export * from './MesonClient' 8 | export * from './MesonClientManager' 9 | export * from './MesonSigner' 10 | -------------------------------------------------------------------------------- /packages/clients/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | import { MesonClientManager } from './MesonClients' 6 | 7 | export * from './MesonClients' 8 | 9 | export const mesonClientManager = new MesonClientManager() 10 | -------------------------------------------------------------------------------- /packages/base/src/types/MesonBalance.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonBalance 3 | */ 4 | import type { BigNumber } from '@ethersproject/bignumber' 5 | 6 | export interface IMesonBalance { 7 | value: BigNumber 8 | display: string 9 | } 10 | -------------------------------------------------------------------------------- /packages/rpc/src/rpcs.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | export { MesonRpcs as Rpcs } from './MesonRpcs' 6 | 7 | export { MesonRpcStatusCache as RpcStatusCache } from './MesonRpcStatusCache' 8 | 9 | export { MesonRpcMonitor as Monitor } from './MesonRpcMonitor' 10 | -------------------------------------------------------------------------------- /packages/base/src/const/AddressFormat.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file AddressFormat 3 | */ 4 | 5 | export const AddressFormat = [ 6 | 'ethers', 7 | 'bitcoin', 8 | 'tron', 9 | 'aptos', 10 | 'sui', 11 | 'solana', 12 | 'starknet', 13 | 'ckb', 14 | 'ton', 15 | ] as const 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules 4 | /.openzeppelin 5 | 6 | /cache 7 | /cache-zk 8 | /artifacts 9 | /artifacts-zk 10 | /deploys 11 | /docs 12 | 13 | .env 14 | 15 | /contracts/utils/MesonConfig.sol 16 | .npmrc 17 | .idea 18 | tsconfig.tsbuildinfo 19 | /typechain-types 20 | -------------------------------------------------------------------------------- /packages/base/src/const/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | export * from './AddressFormat' 6 | export * from './CategoryTokenMap' 7 | 8 | export const ADDRESS_ONE = '0x0000000000000000000000000000000000000001' 9 | 10 | export const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000' 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.runtime": "node", 3 | "eslint.nodePath": "", 4 | "eslint.validate": [ 5 | "javascript", 6 | "javascriptreact", 7 | "typescript", 8 | "typescriptreact" 9 | ], 10 | "eslint.workingDirectories": [{ "mode": "auto" }], 11 | "eslint.useFlatConfig": false 12 | } 13 | -------------------------------------------------------------------------------- /packages/rpc/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | export * as rpcs from './rpcs' 6 | 7 | export * from './types' 8 | 9 | export type { MesonRpcMonitor } from './MesonRpcMonitor' 10 | export type { MesonRpcs } from './MesonRpcs' 11 | export type { MesonRpcStatusCache } from './MesonRpcStatusCache' 12 | -------------------------------------------------------------------------------- /test/shared/expect.ts: -------------------------------------------------------------------------------- 1 | import { expect, use } from 'chai' 2 | import chaiAsPromised from 'chai-as-promised' 3 | import { solidity } from 'ethereum-waffle' 4 | import { jestSnapshotPlugin } from 'mocha-chai-jest-snapshot' 5 | 6 | use(chaiAsPromised) 7 | use(solidity) 8 | use(jestSnapshotPlugin()) 9 | 10 | export { expect } -------------------------------------------------------------------------------- /packages/base/src/types/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | export * from './MesonToken' 6 | export * from './MesonNetwork' 7 | export * from './MesonPresets' 8 | export * from './MesonContract' 9 | export * from './MesonBalance' 10 | export * from './MesonSalt' 11 | 12 | export type Combine = A & Omit 13 | -------------------------------------------------------------------------------- /contracts/Meson.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | import "./MesonManager.sol"; 5 | 6 | /// @title Meson 7 | /// @notice A plain non-upgradeable Meson 8 | contract Meson is MesonManager { 9 | constructor(address premiumManager) { 10 | _transferOwnership(_msgSender()); 11 | _transferPremiumManager(premiumManager); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/presets/src/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import presets from './MesonPresets' 3 | 4 | export { MesonPresets } from './MesonPresets' 5 | export { CustomFeeHttpProvider, CustomFeeWsProvider } from './CustomFeeProvider' 6 | 7 | export type { IMesonNetworkDataWithPartner as PresetNetwork, IMesonTokenDataWithPartner as PresetToken} from '@mesonfi/base' 8 | 9 | export default presets 10 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/zksync/ZksyncAdaptor.ts: -------------------------------------------------------------------------------- 1 | import { Provider as ZkProvider } from 'zksync-web3' 2 | 3 | import { IAdaptor } from '../types' 4 | import extendProvider from '../ethers/extendProvider' 5 | 6 | export default class ZksyncAdaptor extends extendProvider(ZkProvider) implements IAdaptor { 7 | constructor(client: ZkProvider) { 8 | super(client as any) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/ethers/EthersAdaptor.ts: -------------------------------------------------------------------------------- 1 | import { providers } from 'ethers' 2 | 3 | import { IAdaptor } from '../types' 4 | import extendProvider from './extendProvider' 5 | 6 | export default class EthersAdaptor extends extendProvider(providers.StaticJsonRpcProvider) implements IAdaptor { 7 | constructor(client: providers.JsonRpcProvider) { 8 | super(client as any) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./contracts/Meson.sol", 3 | "deploy": "", 4 | "framework": "hardhat", 5 | "npmClient": "yarn", 6 | "compilers": { 7 | "solc": "0.8.28", 8 | "truffle": "", 9 | "evmVersion": "paris", 10 | "optimizer": { 11 | "enabled": true, 12 | "runs": 100 13 | } 14 | }, 15 | "linter": "solhint", 16 | "editor": { 17 | "fontFamily": "Hack", 18 | "fontSize": "13px", 19 | "ligatures": false 20 | } 21 | } -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/zksync/index.ts: -------------------------------------------------------------------------------- 1 | import { Wallet as ZkWallet, Contract as ZkContract } from 'zksync-web3' 2 | import ZksyncAdaptor from './ZksyncAdaptor' 3 | 4 | export function getWallet(privateKey: string, adaptor: ZksyncAdaptor, Wallet = ZkWallet): ZkWallet { 5 | return new Wallet(privateKey, adaptor) 6 | } 7 | 8 | export function getContract(address: string, abi, wallet: ZksyncAdaptor | ZkWallet) { 9 | return new ZkContract(address, abi, wallet) 10 | } 11 | -------------------------------------------------------------------------------- /packages/adaptors/src/tron/address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file formatAddress 3 | */ 4 | 5 | import TronWeb from 'tronweb' 6 | 7 | export function isAddress (addr: string): boolean { 8 | return TronWeb.isAddress(addr) 9 | } 10 | 11 | export function formatAddress (addr: string): string { 12 | return TronWeb.address.fromHex(addr) 13 | } 14 | 15 | export function clipRecipient (recipient: string): string { 16 | return `0x${TronWeb.address.toHex(recipient).substring(2)}` 17 | } 18 | -------------------------------------------------------------------------------- /packages/sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2021", 4 | "module": "commonjs", 5 | "strict": false, 6 | "esModuleInterop": true, 7 | "outDir": "lib", 8 | "declaration": true, 9 | "resolveJsonModule": true, 10 | "skipLibCheck": true, 11 | "typeRoots": ["./node_modules/@types"] 12 | }, 13 | "include": ["./src"], 14 | "ts-node": { 15 | "transpileOnly": true, 16 | "transpiler": "ts-node/transpilers/swc-experimental" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/presets/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2021", 4 | "module": "commonjs", 5 | "strict": false, 6 | "esModuleInterop": true, 7 | "outDir": "lib", 8 | "declaration": true, 9 | "resolveJsonModule": true, 10 | "skipLibCheck": true, 11 | "typeRoots": ["./node_modules/@types"] 12 | }, 13 | "include": ["./src"], 14 | "ts-node": { 15 | "transpileOnly": true, 16 | "transpiler": "ts-node/transpilers/swc-experimental" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/test/MesonPoolsTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | import "../Pools/MesonPools.sol"; 5 | 6 | contract MesonPoolsTest is MesonPools { 7 | address internal _premiumManager; 8 | 9 | constructor(address token, address premiumManager) { 10 | _addSupportToken(token, 1); 11 | _premiumManager = premiumManager; 12 | } 13 | 14 | function _isPremiumManager() internal view override returns (bool) { 15 | return _premiumManager == _msgSender(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/adaptors/src/starknet/address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file formatAddress 3 | */ 4 | 5 | import { utils } from 'ethers' 6 | 7 | export function isAddress (addr: string) { 8 | return !!addr 9 | } 10 | 11 | export function formatAddress (addr: string) { 12 | return utils.hexZeroPad(addr, 32) 13 | } 14 | 15 | export function clipRecipient (recipient: string) { 16 | 17 | if (utils.isAddress(recipient)) { 18 | return recipient 19 | } 20 | 21 | return utils.hexZeroPad(recipient, 32).substring(0, 42) 22 | } 23 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/bitcoin/BtcClient.ts: -------------------------------------------------------------------------------- 1 | import { networks } from 'bitcoinjs-lib' 2 | 3 | export default class BtcClient { 4 | readonly url: string 5 | readonly isTestnet: boolean 6 | readonly mesonAddress: string 7 | 8 | constructor(url: string, isTestnet?: boolean, mesonAddress?: string) { 9 | this.url = url 10 | this.isTestnet = isTestnet 11 | this.mesonAddress = mesonAddress 12 | } 13 | 14 | get network() { 15 | return this.isTestnet ? networks.testnet : networks.bitcoin 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/adaptors/src/ethers/address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file address 3 | */ 4 | import { utils } from 'ethers' 5 | 6 | export function formatAddress (addr: string) { 7 | if (utils.isAddress(addr)) { 8 | return utils.getAddress(addr).toLowerCase() 9 | } else { 10 | return addr 11 | } 12 | } 13 | 14 | export function isAddress (addr: string): boolean { 15 | return utils.isHexString(addr) && utils.isAddress(addr) 16 | } 17 | 18 | export function clipRecipient (recipient: string): string { 19 | return recipient 20 | } 21 | -------------------------------------------------------------------------------- /packages/base/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | export * from './meson/MesonNetwork' 6 | export * from './meson/MesonToken' 7 | export * from './meson/MesonPresets' 8 | 9 | export type * from '../abis/MesonContract' 10 | export type * from '../abis/ERC20Contract' 11 | export type * from '../abis/ContractTypes' 12 | 13 | export type * from './types' 14 | 15 | export * as meson from './meson' 16 | 17 | export type { IMesonSwapData } from './meson/MesonSwap' 18 | export type { IMesonBaseOptions } from './meson' 19 | -------------------------------------------------------------------------------- /contracts/UpgradableMeson.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; 5 | import "./MesonManager.sol"; 6 | 7 | contract UpgradableMeson is UUPSUpgradeable, MesonManager { 8 | function initialize(address owner, address premiumManager) external initializer { 9 | _transferOwnership(owner); 10 | _transferPremiumManager(premiumManager); 11 | } 12 | 13 | function _authorizeUpgrade(address) internal override onlyOwner {} 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "outDir": "dist", 8 | "resolveJsonModule": true, 9 | "typeRoots": ["./typechain", "./node_modules/@types"], 10 | "skipLibCheck": true 11 | }, 12 | "include": ["./scripts", "./test", "./typechain-types"], 13 | "files": ["./hardhat.config.ts"], 14 | "ts-node": { 15 | "transpileOnly": true, 16 | "transpiler": "ts-node/transpilers/swc-experimental" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/adaptors/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | export * from './types' 6 | 7 | export type { MesonAdaptorConfigManager } from './MesonAdaptorConfigManager' 8 | 9 | export type * from './aptos/type' 10 | export type * from './bitcoin/type' 11 | export type * from './ckb/type' 12 | export type * from './ethers/type' 13 | export type * from './solana/type' 14 | export type * from './starknet/type' 15 | export type * from './sui/type' 16 | export type * from './ton/type' 17 | export type * from './tron/type' 18 | 19 | export * as adaptors from './adaptors' 20 | -------------------------------------------------------------------------------- /contracts/test/MockToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract MockToken is ERC20 { 7 | uint8 private _decimals; 8 | 9 | constructor( 10 | string memory name, 11 | string memory symbol, 12 | uint256 initialSupply, 13 | uint8 decimals_ 14 | ) ERC20(name, symbol) { 15 | _decimals = decimals_; 16 | _mint(msg.sender, initialSupply); 17 | } 18 | 19 | function decimals() public view override returns (uint8) { 20 | return _decimals; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/deploy-forward.js: -------------------------------------------------------------------------------- 1 | const { adaptors } = require('@mesonfi/sdk') 2 | const { getAdaptor } = require('./lib/getAdaptor') 3 | const { deployContract } = require('./lib/deploy') 4 | 5 | require('dotenv').config() 6 | 7 | const { PRIVATE_KEY } = process.env 8 | 9 | module.exports = async function deployForwardContract(network) { 10 | const adaptor = getAdaptor(network) 11 | await hre.run('compile') 12 | 13 | const wallet = adaptors.getWallet(PRIVATE_KEY, adaptor) 14 | console.log('Deploying ForwardTokenContract...') 15 | await deployContract('ForwardTokenContract', wallet) 16 | } 17 | -------------------------------------------------------------------------------- /test/shared/wallet.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'hardhat' 2 | 3 | // default mnemonic for hardhat network 4 | const mnemonic = 'test test test test test test test test test test test junk' 5 | export const wallet = ethers.Wallet.fromMnemonic(mnemonic) 6 | 7 | const privateKey1 = '0xb0467aa26cc0b8f5de684b447287958fbeea2877adf194c284cf98d8d0fad2dd' 8 | export const initiator = new ethers.Wallet(privateKey1, ethers.provider) 9 | 10 | const privateKey2 = '0x3618b13685a4faf31003929844655e3c08c864128c45ce356f97de22612ede51' 11 | export const poolOwner = new ethers.Wallet(privateKey2, ethers.provider) 12 | -------------------------------------------------------------------------------- /.github/workflows/test_dev.yaml: -------------------------------------------------------------------------------- 1 | name: Develop branch CI 2 | 3 | on: 4 | push: 5 | branches: [ develop ] 6 | pull_request: 7 | branches: [ develop ] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Use Node.js 16.x 15 | uses: actions/setup-node@v2 16 | with: 17 | node-version: 16.x 18 | - name: Install dependencies 19 | run: yarn install --immutable --immutable-cache --check-cache 20 | - name: Build packages 21 | run: yarn run build:packages 22 | - run: yarn test 23 | -------------------------------------------------------------------------------- /packages/sdk/src/index.ts: -------------------------------------------------------------------------------- 1 | export { MesonClient, PartialSwapData, PostedSwapStatus, LockedSwapStatus } from './MesonClient' 2 | export { Block, Transaction, Receipt } from './Rpc' 3 | export { Swap, SwapData } from './Swap' 4 | export { SwapSigner, EthersWalletSwapSigner, RemoteSwapSigner, NonEcdsaRemoteSwapSigner } from './SwapSigner' 5 | export { SwapWithSigner } from './SwapWithSigner' 6 | export { SignedSwapRequest, SignedSwapRequestData, SignedSwapRelease, SignedSwapReleaseData } from './SignedSwap' 7 | export * as adaptors from './adaptors' 8 | export { IAdaptor } from './adaptors/types' 9 | 10 | export * as stark from 'starknet' -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/ethers/index.ts: -------------------------------------------------------------------------------- 1 | import { ethers, providers, Signer } from 'ethers' 2 | import EthersAdaptor from './EthersAdaptor' 3 | 4 | export function getWallet(privateKey: string, adaptor: EthersAdaptor | providers.JsonRpcProvider, Wallet = ethers.Wallet): ethers.Wallet { 5 | if (!privateKey) { 6 | const wallet = Wallet.createRandom() 7 | return wallet.connect(adaptor) 8 | } 9 | return new Wallet(privateKey, adaptor) 10 | } 11 | 12 | export function getContract(address: string, abi, adaptor: EthersAdaptor | providers.JsonRpcProvider | Signer) { 13 | return new ethers.Contract(address, abi, adaptor) 14 | } 15 | -------------------------------------------------------------------------------- /packages/base/src/types/MesonPresets.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonConfig 3 | */ 4 | 5 | import { IMesonNetwork } from './MesonNetwork' 6 | 7 | export interface IMesonPresets { 8 | 9 | readonly useTestnet: boolean 10 | 11 | getNetworks(): T[] 12 | 13 | hasNetwork(networkId: string): boolean 14 | 15 | hasNetworkByChain(chainId: string): boolean 16 | 17 | hasNetworkByShortCoinType(shortSlip44: string): boolean 18 | 19 | getNetworkByNetworkId(networkId: string): T 20 | 21 | getNetworkFromShortCoinType(shortCoinType: string): T 22 | 23 | getNetworkFromChainId(chainId: string): T 24 | } 25 | -------------------------------------------------------------------------------- /packages/rpc/src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file types 3 | */ 4 | import { MesonNetworkStatus } from '@mesonfi/base' 5 | 6 | export interface IMesonRpcs { 7 | 8 | readonly isReady: boolean 9 | 10 | isUrlHealthy(networkId: string, url: string): boolean 11 | 12 | waitForReady(): Promise 13 | 14 | hasHealthyRpc(networkId: string): boolean 15 | 16 | getHealthyRpcStatus(networkId: string): MesonNetworkStatus[] 17 | 18 | getAllHealthyRpcStatus(): Record 19 | 20 | refreshAllRpcStatus(): Promise 21 | 22 | fetchRpcs(): Promise> 23 | } 24 | 25 | export type { 26 | MesonNetworkStatus, 27 | } 28 | -------------------------------------------------------------------------------- /packages/adaptors/src/solana/address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file formatAddress 3 | */ 4 | 5 | import { PublicKey as SolPublicKey } from '@solana/web3.js' 6 | import { utils } from 'ethers' 7 | 8 | export function formatAddress (addr: string): string { 9 | try { 10 | return new SolPublicKey(addr).toString() 11 | } catch { 12 | return '' 13 | } 14 | } 15 | 16 | export function isAddress (addr: string): boolean { 17 | return !!formatAddress(addr) 18 | } 19 | 20 | export function clipRecipient (recipient: string) { 21 | 22 | if (utils.isAddress(recipient)) { 23 | return recipient 24 | } 25 | 26 | return utils.hexlify(utils.base58.decode(recipient)).substring(0, 42) 27 | } 28 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Main branch CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Use Node.js 16.x 15 | uses: actions/setup-node@v2 16 | with: 17 | node-version: 16.x 18 | - name: Install dependencies 19 | run: yarn install --immutable --immutable-cache --check-cache 20 | - name: Build packages 21 | run: yarn run build:packages 22 | - name: Check generated abis/types 23 | run: yarn build:types && git diff --exit-code 24 | - run: yarn test 25 | -------------------------------------------------------------------------------- /contracts/test/MesonSwapTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | import "../Swap/MesonSwap.sol"; 5 | 6 | contract MesonSwapTest is MesonSwap { 7 | constructor(address token) { 8 | _addSupportToken(token, 1); 9 | } 10 | 11 | function register(uint40 poolIndex) external { 12 | address poolOwner = _msgSender(); 13 | require(poolIndex != 0, "Cannot use index 0"); 14 | require(ownerOfPool[poolIndex] == address(0), "Pool index already registered"); 15 | require(poolOfAuthorizedAddr[poolOwner] == 0, "Signer address already registered"); 16 | ownerOfPool[poolIndex] = poolOwner; 17 | poolOfAuthorizedAddr[poolOwner] = poolIndex; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/adaptors/src/ton/address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file formatAddress 3 | */ 4 | 5 | import { utils } from 'ethers' 6 | import { Address as TonAddress } from '@ton/core' 7 | 8 | export function formatAddress (addr: string) { 9 | try { 10 | return TonAddress.parseFriendly(addr).address.toString({ bounceable: false }) 11 | } catch { 12 | return '' 13 | } 14 | } 15 | 16 | export function isAddress (addr: string) { 17 | return !!formatAddress(addr) 18 | } 19 | 20 | export function clipRecipient (recipient: string) { 21 | 22 | if (utils.isAddress(recipient)) { 23 | return recipient 24 | } 25 | 26 | return '0x' + TonAddress.parse(recipient).toRaw().toString('hex').substring(0, 40) 27 | } 28 | -------------------------------------------------------------------------------- /packages/adaptors/src/sui/address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file formatAddress 3 | */ 4 | 5 | import { utils } from 'ethers' 6 | 7 | export function isAddress (addr: string) { 8 | return utils.isHexString(addr) && addr.length <= 66 && addr.length > 50 9 | } 10 | 11 | export function formatAddress (addr: string) { 12 | const parts = addr.split('::') 13 | if (!parts[0].startsWith('0x')) { 14 | parts[0] = '0x' + parts[0] 15 | } 16 | parts[0] = utils.hexZeroPad(parts[0], 32) 17 | return parts.join('::') 18 | } 19 | 20 | export function clipRecipient (recipient: string) { 21 | 22 | if (utils.isAddress(recipient)) { 23 | return recipient 24 | } 25 | 26 | return utils.hexZeroPad(recipient, 32).substring(0, 42) 27 | } 28 | -------------------------------------------------------------------------------- /packages/adaptors/src/aptos/address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file formatAddress 3 | */ 4 | 5 | import { utils } from 'ethers' 6 | 7 | export function formatAddress (addr: string) { 8 | const parts = addr.split('::') 9 | if (!parts[0].startsWith('0x')) { 10 | parts[0] = '0x' + parts[0] 11 | } 12 | parts[0] = utils.hexZeroPad(parts[0], 32) 13 | return parts.join('::') 14 | } 15 | 16 | export function isAddress (addr: string): boolean { 17 | return utils.isHexString(addr) && addr.length <= 66 && addr.length > 50 18 | } 19 | 20 | export function clipRecipient (recipient: string) { 21 | 22 | if (utils.isAddress(recipient)) { 23 | return recipient 24 | } 25 | 26 | return utils.hexZeroPad(recipient, 32).substring(0, 42) 27 | } 28 | -------------------------------------------------------------------------------- /scripts/lib/getAdaptor.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat') 2 | const presets = require('@mesonfi/presets').default 3 | 4 | const CustomGasFeeProviderWrapper = require('./CustomGasFeeProviderWrapper') 5 | 6 | exports.getAdaptor = function getAdaptor (network) { 7 | if (!presets.getNetwork(network.id)) { 8 | presets.useTestnet(true) 9 | } 10 | 11 | if (network.addressFormat === 'ethers' && !network.id.startsWith('zksync') && !network.id.startsWith('zklink')) { 12 | const provider = new ethers.providers.JsonRpcProvider(network.url) 13 | ethers.provider = new CustomGasFeeProviderWrapper(provider) 14 | return ethers.provider 15 | } else { 16 | return presets.createAdaptor(network.id, network.url) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "module": "esnext", 5 | "declaration": false, 6 | "strict": true, 7 | "lib": [ 8 | "ES2019", 9 | "ES2020", 10 | "ES2021" 11 | ], 12 | "noEmit": true, 13 | "rootDir": ".", 14 | "allowSyntheticDefaultImports": true, 15 | "downlevelIteration": true, 16 | "jsx": "preserve", 17 | "moduleResolution": "node16", 18 | "esModuleInterop": true, 19 | "preserveSymlinks": true, 20 | "resolveJsonModule": true, 21 | "experimentalDecorators": true, 22 | "baseUrl": "./", 23 | "skipLibCheck": true, 24 | "incremental": true, 25 | "isolatedModules": true 26 | }, 27 | "include": ["**/*.ts", "**/*.tsx"] 28 | } 29 | -------------------------------------------------------------------------------- /contracts/Proxy2ToMeson.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; 5 | import "./UpgradableMeson.sol"; 6 | 7 | // Some blockchains do not support deploying another contract in constructor 8 | contract Proxy2ToMeson is ERC1967Proxy { 9 | bytes4 private constant INITIALIZE_SELECTOR = bytes4(keccak256("initialize(address,address)")); 10 | 11 | constructor(address implAddress, address premiumManager) ERC1967Proxy(implAddress, _encodeData(msg.sender, premiumManager)) {} 12 | 13 | function _encodeData(address owner, address premiumManager) private pure returns (bytes memory) { 14 | return abi.encodeWithSelector(INITIALIZE_SELECTOR, owner, premiumManager); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /contracts/interfaces/IDepositWithBeneficiary.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | /// @title Interface for depositWithBeneficiary 5 | interface IDepositWithBeneficiary { 6 | /// @notice Make a token transfer that the *signer* is paying tokens but benefits are given to the *beneficiary* 7 | /// @param token The contract address of the transferring token 8 | /// @param amount The amount of the transfer 9 | /// @param beneficiary The address that will receive benefits of this transfer 10 | /// @param data Extra data passed to the contract 11 | /// @return Returns true for a successful transfer. 12 | function depositWithBeneficiary(address token, uint256 amount, address beneficiary, uint64 data) 13 | payable external returns (bool); 14 | } 15 | -------------------------------------------------------------------------------- /scripts/copy-abis.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const pairs = [ 5 | [ 6 | 'artifacts/contracts/Meson.sol/Meson.json', 7 | 'packages/base/abis/MesonAbi.json', 8 | ], 9 | [ 10 | 'artifacts/contracts/test/MockToken.sol/MockToken.json', 11 | 'packages/base/abis/ERC20Abi.json', 12 | ], 13 | ] 14 | 15 | pairs.forEach(([from, to]) => { 16 | const content = fs.readFileSync(from, 'utf-8') 17 | const json = JSON.parse(content) 18 | 19 | const result = JSON.stringify({ contractName: json.contractName, abi: json.abi }, null, 2) 20 | 21 | const dirName = path.dirname(to) 22 | 23 | if (!fs.existsSync(dirName)) { 24 | fs.mkdirSync(dirName, { recursive: true }) 25 | } 26 | 27 | fs.writeFileSync(to, result, 'utf-8') 28 | }) 29 | -------------------------------------------------------------------------------- /scripts/upgrade.js: -------------------------------------------------------------------------------- 1 | const { adaptors } = require('@mesonfi/sdk') 2 | const { getAdaptor } = require('./lib/getAdaptor') 3 | const { deployContract } = require('./lib/deploy') 4 | 5 | require('dotenv').config() 6 | 7 | const { PRIVATE_KEY } = process.env 8 | 9 | module.exports = async function upgrade(network) { 10 | const adaptor = getAdaptor(network) 11 | await hre.run('compile') 12 | 13 | const wallet = adaptors.getWallet(PRIVATE_KEY, adaptor) 14 | console.log('Deploying UpgradableMeson...') 15 | const impl = await deployContract('UpgradableMeson', wallet) 16 | const abi = JSON.parse(impl.interface.format('json')) 17 | const proxy = adaptors.getContract(network.mesonAddress, abi, wallet) 18 | await proxy.upgradeTo(impl.address) 19 | console.log('Meson upgraded') 20 | } 21 | -------------------------------------------------------------------------------- /packages/adaptors/src/starknet/parse/v1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "members": [ 4 | { 5 | "name": "to", 6 | "offset": 0, 7 | "type": "felt" 8 | }, 9 | { 10 | "name": "selector", 11 | "offset": 1, 12 | "type": "felt" 13 | }, 14 | { 15 | "name": "data", 16 | "offset": 2, 17 | "type": "felt*" 18 | } 19 | ], 20 | "name": "CallArray", 21 | "size": 3, 22 | "type": "struct" 23 | }, 24 | { 25 | "outputs": [ 26 | { 27 | "name": "calls_len", 28 | "type": "felt" 29 | }, 30 | { 31 | "name": "calls", 32 | "type": "CallArray*" 33 | } 34 | ], 35 | "name": "__execute__", 36 | "inputs": [], 37 | "type": "function" 38 | } 39 | ] -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/starknet/parse/v1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "members": [ 4 | { 5 | "name": "to", 6 | "offset": 0, 7 | "type": "felt" 8 | }, 9 | { 10 | "name": "selector", 11 | "offset": 1, 12 | "type": "felt" 13 | }, 14 | { 15 | "name": "data", 16 | "offset": 2, 17 | "type": "felt*" 18 | } 19 | ], 20 | "name": "CallArray", 21 | "size": 3, 22 | "type": "struct" 23 | }, 24 | { 25 | "outputs": [ 26 | { 27 | "name": "calls_len", 28 | "type": "felt" 29 | }, 30 | { 31 | "name": "calls", 32 | "type": "CallArray*" 33 | } 34 | ], 35 | "name": "__execute__", 36 | "inputs": [], 37 | "type": "function" 38 | } 39 | ] -------------------------------------------------------------------------------- /packages/base/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "strict": true, 7 | "lib": [ 8 | "ES2019", 9 | "ES2020", 10 | "ES2021" 11 | ], 12 | "rootDir": ".", 13 | "allowSyntheticDefaultImports": true, 14 | "downlevelIteration": true, 15 | "jsx": "preserve", 16 | "moduleResolution": "node", 17 | "esModuleInterop": true, 18 | "preserveSymlinks": true, 19 | "resolveJsonModule": true, 20 | "experimentalDecorators": true, 21 | "baseUrl": "./", 22 | "skipLibCheck": true, 23 | "incremental": true, 24 | "isolatedModules": true 25 | }, 26 | "include": [ 27 | "./src" 28 | ], 29 | "ts-node": { 30 | "transpileOnly": true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/rpc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "strict": false, 7 | "lib": [ 8 | "ES2019", 9 | "ES2020", 10 | "ES2021" 11 | ], 12 | "allowSyntheticDefaultImports": true, 13 | "downlevelIteration": true, 14 | "jsx": "preserve", 15 | "moduleResolution": "node", 16 | "esModuleInterop": true, 17 | "preserveSymlinks": true, 18 | "resolveJsonModule": true, 19 | "experimentalDecorators": true, 20 | "skipLibCheck": true, 21 | "incremental": true, 22 | "isolatedModules": true 23 | }, 24 | "include": [ 25 | "./src" 26 | ], 27 | "ts-node": { 28 | "transpileOnly": true, 29 | "transpiler": "ts-node/transpilers/swc-experimental" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /contracts/ProxyToMeson.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; 5 | import "./UpgradableMeson.sol"; 6 | 7 | contract ProxyToMeson is ERC1967Proxy { 8 | bytes4 private constant INITIALIZE_SELECTOR = bytes4(keccak256("initialize(address,address)")); 9 | 10 | constructor(address premiumManager) ERC1967Proxy(_deployImpl(), _encodeData(msg.sender, premiumManager)) {} 11 | 12 | function _deployImpl() private returns (address) { 13 | UpgradableMeson _impl = new UpgradableMeson(); 14 | return address(_impl); 15 | } 16 | 17 | function _encodeData(address owner, address premiumManager) private pure returns (bytes memory) { 18 | return abi.encodeWithSelector(INITIALIZE_SELECTOR, owner, premiumManager); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/adaptors/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "strict": false, 7 | "lib": [ 8 | "ES2019", 9 | "ES2020", 10 | "ES2021" 11 | ], 12 | "allowSyntheticDefaultImports": true, 13 | "downlevelIteration": true, 14 | "jsx": "preserve", 15 | "moduleResolution": "node", 16 | "esModuleInterop": true, 17 | "preserveSymlinks": true, 18 | "resolveJsonModule": true, 19 | "experimentalDecorators": true, 20 | "skipLibCheck": true, 21 | "incremental": true, 22 | "isolatedModules": true 23 | }, 24 | "include": [ 25 | "./src" 26 | ], 27 | "ts-node": { 28 | "transpileOnly": true, 29 | "transpiler": "ts-node/transpilers/swc-experimental" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "strict": false, 7 | "lib": [ 8 | "ES2019", 9 | "ES2020", 10 | "ES2021" 11 | ], 12 | "allowSyntheticDefaultImports": true, 13 | "downlevelIteration": true, 14 | "jsx": "preserve", 15 | "moduleResolution": "node", 16 | "esModuleInterop": true, 17 | "preserveSymlinks": true, 18 | "resolveJsonModule": true, 19 | "experimentalDecorators": true, 20 | "skipLibCheck": true, 21 | "incremental": true, 22 | "isolatedModules": true 23 | }, 24 | "include": [ 25 | "./src" 26 | ], 27 | "ts-node": { 28 | "transpileOnly": true, 29 | "transpiler": "ts-node/transpilers/swc-experimental" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/adaptors/src/ckb/address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file formatAddress 3 | */ 4 | 5 | import { utils } from 'ethers' 6 | import { config, helpers } from '@ckb-lumos/lumos' 7 | 8 | export function isAddress (addr: string) { 9 | return !!addr 10 | } 11 | 12 | export function formatAddress (addr: string) { 13 | return addr 14 | } 15 | 16 | export function clipRecipient (recipient: string) { 17 | 18 | if (utils.isAddress(recipient)) { 19 | return recipient 20 | } 21 | 22 | const lockScript = helpers.parseAddress(recipient, { 23 | config: recipient.startsWith('ckb') ? config.MAINNET : config.TESTNET, 24 | }) 25 | 26 | if (!lockScript.args.startsWith('0x0001')) { 27 | throw new Error('Recipient not supported. Please enter a JoyID address.') 28 | } 29 | 30 | return lockScript.args.replace('0x0001', '0x') 31 | } 32 | -------------------------------------------------------------------------------- /packages/base/src/types/MesonToken.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonToken 3 | */ 4 | 5 | import type { AddressFormat } from '../const' 6 | 7 | export type MesonAddressFormat = (typeof AddressFormat)[number]; 8 | 9 | export interface IMesonTokenData { 10 | 11 | tokenIndex: number 12 | 13 | symbol: string 14 | 15 | name: string 16 | 17 | icon?: string 18 | 19 | addr: string 20 | 21 | decimals: number 22 | 23 | disabled: boolean 24 | 25 | link?: string 26 | } 27 | 28 | export interface IMesonToken extends IMesonTokenData { 29 | 30 | readonly type: string 31 | readonly category: string 32 | readonly isCoreToken: boolean 33 | 34 | getTokenLink(): string 35 | 36 | getAddressLink(): string 37 | } 38 | 39 | export interface IMesonTokenDataWithPartner extends Omit { 40 | 41 | disabled?: boolean 42 | 43 | partner?: string 44 | } 45 | -------------------------------------------------------------------------------- /packages/base/src/types/MesonContract.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonContract 3 | */ 4 | 5 | export interface JsonFragmentType { 6 | readonly name?: string 7 | readonly indexed?: boolean 8 | readonly type?: string 9 | // must use any to match ethers.js types 10 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 11 | readonly internalType?: any 12 | readonly components?: readonly JsonFragmentType[] 13 | } 14 | 15 | export interface JsonFragment { 16 | readonly name?: string 17 | readonly type?: string 18 | 19 | readonly anonymous?: boolean 20 | 21 | readonly payable?: boolean 22 | readonly constant?: boolean 23 | readonly stateMutability?: string 24 | 25 | readonly inputs?: readonly JsonFragmentType[] 26 | readonly outputs?: readonly JsonFragmentType[] 27 | 28 | readonly gas?: string 29 | } 30 | 31 | export type ContractInterface = JsonFragment[]; 32 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/types.ts: -------------------------------------------------------------------------------- 1 | import { type BigNumber } from 'ethers' 2 | 3 | export type WrappedTransaction = { 4 | blockHash: string 5 | status?: number | string 6 | } 7 | 8 | export interface IAdaptor { 9 | get client() 10 | set client(c: any) 11 | get nodeUrl(): string 12 | detectNetwork(): Promise 13 | getBlockNumber(): Promise 14 | getGasPrice(): Promise 15 | getBalance(addr: string): Promise 16 | getCode(addr: string): Promise 17 | // getTransactionCount(addr: string): Promise 18 | getLogs(filter: any): Promise 19 | // on(): any 20 | // removeAllListeners(): any 21 | send(method: string, params: any[]): Promise 22 | waitForTransaction(hash: string, confirmations?: number, timeout?: number): Promise 23 | } 24 | 25 | export type AdaptorConstructor = new (...args: any) => IAdaptor 26 | -------------------------------------------------------------------------------- /packages/clients/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "strict": true, 7 | "lib": [ 8 | "ES2019", 9 | "ES2020", 10 | "ES2021" 11 | ], 12 | "rootDir": ".", 13 | "allowSyntheticDefaultImports": true, 14 | "downlevelIteration": true, 15 | "jsx": "preserve", 16 | "moduleResolution": "node", 17 | "esModuleInterop": true, 18 | "preserveSymlinks": true, 19 | "resolveJsonModule": true, 20 | "experimentalDecorators": true, 21 | "baseUrl": "./", 22 | "typeRoots": [ 23 | "../node_modules/@types", 24 | "../types" 25 | ], 26 | "skipLibCheck": true, 27 | "incremental": true, 28 | "isolatedModules": false 29 | }, 30 | "include": [ 31 | "./src" 32 | ], 33 | "ts-node": { 34 | "transpileOnly": true 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/adaptors/src/adaptors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | import { type MesonAddressFormat } from '@mesonfi/base' 5 | import { adaptorConfigs } from './MesonAdaptorConfigManager' 6 | import { IMesonAdaptorConfig, WebSocketConstructor } from './types' 7 | 8 | export const registerWebSocketConstructor: (WebSocketConstructor: WebSocketConstructor) => void = adaptorConfigs.registerWebSocketConstructor.bind(adaptorConfigs) 9 | 10 | export const registerAdaptorConfig: (addressFormat: T, adaptor: IMesonAdaptorConfig) => void = adaptorConfigs.registerAdaptorConfig.bind(adaptorConfigs) 11 | 12 | export const getAdaptorConfig: (addressFormat: MesonAddressFormat) => IMesonAdaptorConfig = adaptorConfigs.getAdaptorConfig.bind(adaptorConfigs) 13 | 14 | export const getWebSocketConstructor: () => WebSocketConstructor | null = adaptorConfigs.getWebSocketConstructor.bind(adaptorConfigs) 15 | -------------------------------------------------------------------------------- /packages/rpc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mesonfi/rpc", 3 | "version": "1.33.0-alpha.1", 4 | "description": "", 5 | "license": "MIT", 6 | "repository": "https://github.com/MesonFi/meson-contracts-solidity", 7 | "main": "lib/index.js", 8 | "module": "es/index.js", 9 | "typings": "lib/index.d.ts", 10 | "scripts": { 11 | "build": "npm run build:clean-dest && npm run build:run", 12 | "build:run": "npm run build:lib && npm run build:es", 13 | "build:clean-dest": "rm -rf lib && rm -rf es", 14 | "build:lib": "tsc --outDir lib", 15 | "build:es": "tsc -m esnext --outDir es", 16 | "prepare": "npm run build", 17 | "test": "tsx test/demo.ts" 18 | }, 19 | "peerDependencies": { 20 | "@mesonfi/base": "*", 21 | "@mesonfi/adaptors": "*" 22 | }, 23 | "files": [ 24 | "lib", 25 | "es", 26 | "Readme.md" 27 | ], 28 | "publishConfig": { 29 | "registry": "https://npm.pkg.github.com/" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mesonfi/client", 3 | "version": "1.33.0-alpha.1", 4 | "description": "", 5 | "license": "MIT", 6 | "repository": "https://github.com/MesonFi/meson-contracts-solidity", 7 | "main": "lib/index.js", 8 | "module": "es/index.js", 9 | "typings": "lib/index.d.ts", 10 | "scripts": { 11 | "build": "npm run build:clean-dest && npm run build:run", 12 | "build:run": "npm run build:lib && npm run build:es", 13 | "build:clean-dest": "rm -rf lib && rm -rf es", 14 | "build:lib": "tsc --outDir lib", 15 | "build:es": "tsc -m esnext --outDir es", 16 | "prepare": "npm run build", 17 | "test": "tsx test/demo.ts" 18 | }, 19 | "peerDependencies": { 20 | "@mesonfi/base": "*", 21 | "@mesonfi/adaptors": "*" 22 | }, 23 | "files": [ 24 | "lib", 25 | "es", 26 | "Readme.md" 27 | ], 28 | "publishConfig": { 29 | "registry": "https://npm.pkg.github.com/" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /scripts/lib/updatePresets.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs') 3 | 4 | const mainnetsPath = path.join(__dirname, '../../packages/base/networks/mainnets.json') 5 | const testnetsPath = path.join(__dirname, '../../packages/base/networks/testnets.json') 6 | 7 | module.exports = function updatePresets (network) { 8 | const mainnets = require(mainnetsPath) 9 | let index = mainnets.findIndex(item => item.id === network.id) 10 | if (index > -1) { 11 | // mainnet 12 | mainnets.splice(index, 1, network) 13 | fs.writeFileSync(mainnetsPath, JSON.stringify(mainnets, null, 2)) 14 | return 15 | } 16 | 17 | // testnet 18 | const testnets = require(testnetsPath) 19 | index = testnets.findIndex(item => item.id === network.id) 20 | if (index === -1) { 21 | throw new Error(`Invalid network: ${networkId}`) 22 | } 23 | testnets.splice(index, 1, network) 24 | fs.writeFileSync(testnetsPath, JSON.stringify(testnets, null, 2)) 25 | } 26 | -------------------------------------------------------------------------------- /packages/adaptors/src/ethers/wallet.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers' 2 | import { MesonData } from '../types' 3 | import { 4 | IMesonEthersFailoverNetworkClient, 5 | IMesonEthersWallet, 6 | IMesonEthersWalletWithExtension, 7 | } from './type' 8 | 9 | export function fromPrivateKey (privateKey: string, networkClient: IMesonEthersFailoverNetworkClient): IMesonEthersWallet { 10 | 11 | const addressFormat = 'ethers' as const 12 | 13 | if (!privateKey) { 14 | const wallet = ethers.Wallet.createRandom() 15 | return Object.assign(wallet.connect(networkClient), { networkClient, addressFormat }) 16 | } 17 | 18 | return Object.assign(new ethers.Wallet(privateKey, networkClient), { networkClient, addressFormat }) 19 | } 20 | 21 | export function fromExtension (ext: MesonData, networkClient: IMesonEthersFailoverNetworkClient): IMesonEthersWalletWithExtension { 22 | 23 | const addressFormat = 'ethers' as const 24 | 25 | return Object.assign(ext.signer, { networkClient, addressFormat }) 26 | } 27 | -------------------------------------------------------------------------------- /packages/base/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mesonfi/base", 3 | "version": "1.33.0-rc.8", 4 | "description": "", 5 | "license": "MIT", 6 | "repository": "https://github.com/MesonFi/meson-contracts-solidity", 7 | "main": "lib/index.js", 8 | "module": "es/index.js", 9 | "typings": "lib/index.d.ts", 10 | "scripts": { 11 | "build": "npm run build:clean-dest && npm run build:clean && npm run build:run && npm run build:clean", 12 | "build:run": "npm run build:lib && npm run build:es", 13 | "build:clean-dest": "rm -rf lib && rm -rf es", 14 | "build:clean": "rm -rf lib-dist && rm -rf es-dist", 15 | "build:lib": "tsc --outDir lib-dist && mv lib-dist/src lib", 16 | "build:es": "tsc -m esnext --outDir es-dist && mv es-dist/src es", 17 | "prepare": "npm run build" 18 | }, 19 | "files": [ 20 | "config", 21 | "networks", 22 | "types", 23 | "lib", 24 | "es", 25 | "abis", 26 | "Readme.md" 27 | ], 28 | "publishConfig": { 29 | "registry": "https://npm.pkg.github.com/" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /scripts/copy-types.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const pairs = [ 5 | [ 6 | 'typechain-types/@openzeppelin/contracts/token/ERC20/ERC20.ts', 7 | 'packages/base/abis/ERC20Contract.d.ts', 8 | ], 9 | [ 10 | 'typechain-types/contracts/Meson.ts', 11 | 'packages/base/abis/MesonContract.d.ts', 12 | ], 13 | [ 14 | 'typechain-types/common.ts', 15 | 'packages/base/abis/ContractTypes.d.ts', 16 | ], 17 | ] 18 | 19 | pairs.forEach(([from, to]) => { 20 | const content = fs.readFileSync(from, 'utf-8') 21 | const result = content 22 | .replace(/"(?:..\/)+common"/, '"./ContractTypes"') 23 | .replace('export interface ERC20 extends ', 'export interface ERC20Contract extends ') 24 | .replace('export interface Meson extends ', 'export interface MesonContract extends ') 25 | 26 | const dirName = path.dirname(to) 27 | 28 | if (!fs.existsSync(dirName)) { 29 | fs.mkdirSync(dirName, { recursive: true }) 30 | } 31 | 32 | fs.writeFileSync(to, result, 'utf-8') 33 | }) 34 | -------------------------------------------------------------------------------- /packages/presets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mesonfi/presets", 3 | "version": "1.32.0-rc.4", 4 | "description": "", 5 | "license": "MIT", 6 | "repository": "https://github.com/MesonFi/meson-contracts-solidity", 7 | "main": "lib/index.js", 8 | "types": "lib/index.d.ts", 9 | "publishConfig": { 10 | "registry": "https://npm.pkg.github.com/" 11 | }, 12 | "files": [ 13 | "lib", 14 | "tsconfig.json" 15 | ], 16 | "scripts": { 17 | "build": "tsc", 18 | "prepare": "yarn build" 19 | }, 20 | "peerDependencies": { 21 | "@mesonfi/base": "^1.33.0-rc.2", 22 | "@mesonfi/sdk": "^1.32.0-rc.4" 23 | }, 24 | "dependencies": { 25 | "@aptos-labs/ts-sdk": "1.35.0", 26 | "@ckb-lumos/lumos": "^0.22.2", 27 | "@mysten/sui": "1.21.0", 28 | "@solana/web3.js": "1.87.5", 29 | "ethers": "5.7.2", 30 | "lodash": "^4.17.21", 31 | "starknet": "7.6.4", 32 | "tronweb": "5.2.0" 33 | }, 34 | "devDependencies": { 35 | "@types/node": "^22.13.11", 36 | "typescript": "^5.4.5" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/adaptors/src/ethers/type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file type. 3 | */ 4 | import { ethers, providers } from 'ethers' 5 | import { Failover, IMesonNetworkClientCommon, IMesonWalletCommon } from '../types' 6 | 7 | export type IMesonEthersNetworkClient = providers.StaticJsonRpcProvider & IMesonNetworkClientCommon<'ethers'> 8 | 9 | export type IMesonEthersFailoverNetworkClient = Failover<'ethers', IMesonEthersNetworkClient> 10 | 11 | export type IMesonEthersWallet = ethers.Wallet & IMesonWalletCommon<'ethers'> 12 | 13 | export type IMesonEthersWalletWithExtension = ethers.VoidSigner & IMesonWalletCommon<'ethers'> 14 | 15 | declare module '../types' { 16 | 17 | interface MesonNetworkClientMap { 18 | ethers: IMesonEthersNetworkClient 19 | } 20 | 21 | interface MesonFailoverNetworkClientMap { 22 | ethers: IMesonEthersFailoverNetworkClient 23 | } 24 | 25 | interface MesonWalletMap { 26 | ethers: IMesonEthersWallet 27 | } 28 | 29 | interface MesonWalletMapWithExtension { 30 | ethers: IMesonEthersWalletWithExtension 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/adaptors/src/starknet/parse/v0.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "members": [ 4 | { 5 | "name": "to", 6 | "offset": 0, 7 | "type": "felt" 8 | }, 9 | { 10 | "name": "selector", 11 | "offset": 1, 12 | "type": "felt" 13 | }, 14 | { 15 | "name": "offset", 16 | "offset": 2, 17 | "type": "felt" 18 | }, 19 | { 20 | "name": "len", 21 | "offset": 3, 22 | "type": "felt" 23 | } 24 | ], 25 | "name": "CallArray", 26 | "size": 4, 27 | "type": "struct" 28 | }, 29 | { 30 | "outputs": [ 31 | { 32 | "name": "calls_len", 33 | "type": "felt" 34 | }, 35 | { 36 | "name": "calls", 37 | "type": "CallArray*" 38 | }, 39 | { 40 | "name": "data_len", 41 | "type": "felt" 42 | }, 43 | { 44 | "name": "data", 45 | "type": "felt*" 46 | } 47 | ], 48 | "name": "__execute__", 49 | "inputs": [], 50 | "type": "function" 51 | } 52 | ] -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/starknet/parse/v0.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "members": [ 4 | { 5 | "name": "to", 6 | "offset": 0, 7 | "type": "felt" 8 | }, 9 | { 10 | "name": "selector", 11 | "offset": 1, 12 | "type": "felt" 13 | }, 14 | { 15 | "name": "offset", 16 | "offset": 2, 17 | "type": "felt" 18 | }, 19 | { 20 | "name": "len", 21 | "offset": 3, 22 | "type": "felt" 23 | } 24 | ], 25 | "name": "CallArray", 26 | "size": 4, 27 | "type": "struct" 28 | }, 29 | { 30 | "outputs": [ 31 | { 32 | "name": "calls_len", 33 | "type": "felt" 34 | }, 35 | { 36 | "name": "calls", 37 | "type": "CallArray*" 38 | }, 39 | { 40 | "name": "data_len", 41 | "type": "felt" 42 | }, 43 | { 44 | "name": "data", 45 | "type": "felt*" 46 | } 47 | ], 48 | "name": "__execute__", 49 | "inputs": [], 50 | "type": "function" 51 | } 52 | ] -------------------------------------------------------------------------------- /contracts/Swap/IMesonSwapEvents.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | /// @title MesonSwapEvents Interface 5 | interface IMesonSwapEvents { 6 | /// @notice Event when a swap request was posted. 7 | /// Emit at the end of `postSwap()` and `postSwapWithSignature()` calls. 8 | /// @param encodedSwap Encoded swap 9 | event SwapPosted(uint256 indexed encodedSwap); 10 | 11 | /// @notice Event when a swap request was bonded. 12 | /// Emit at the end of `bondSwap()` calls. 13 | /// @param encodedSwap Encoded swap 14 | event SwapBonded(uint256 indexed encodedSwap); 15 | 16 | /// @notice Event when a swap request was cancelled. 17 | /// Emit at the end of `cancelSwap()` and `cancelSwapTo()` calls. 18 | /// @param encodedSwap Encoded swap 19 | event SwapCancelled(uint256 indexed encodedSwap); 20 | 21 | /// @notice Event when a swap request was executed. 22 | /// Emit at the end of `executeSwap()`, `directExecuteSwap()` and `simpleExecuteSwap()` calls. 23 | /// @param encodedSwap Encoded swap 24 | event SwapExecuted(uint256 indexed encodedSwap); 25 | } 26 | -------------------------------------------------------------------------------- /packages/adaptors/src/bitcoin/address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file formatAddress 3 | */ 4 | 5 | import { utils } from 'ethers' 6 | import * as btclib from 'bitcoinjs-lib' 7 | 8 | export function parseAddress (addr: string) { 9 | try { 10 | const result = btclib.address.fromBech32(addr) 11 | return { addr, format: 'bech32', hex: '0x' + result.data.toString('hex') } 12 | } catch { 13 | } 14 | 15 | try { 16 | const result = btclib.address.fromBase58Check(addr) 17 | return { addr, format: 'base58', hex: '0x' + result.hash.toString('hex') } 18 | } catch { 19 | } 20 | } 21 | 22 | export function formatAddress (addr: string): string { 23 | return parseAddress(addr)?.addr 24 | } 25 | 26 | export function isAddress (addr: string) { 27 | return !!formatAddress(addr) 28 | } 29 | 30 | export function clipRecipient (recipient: string) { 31 | 32 | if (utils.isAddress(recipient)) { 33 | return recipient 34 | } 35 | 36 | const parsed = parseAddress(recipient) 37 | 38 | if (!parsed) { 39 | throw new Error('Invalid bitcoin address') 40 | } 41 | 42 | return parsed.hex.substring(0, 42) 43 | } 44 | -------------------------------------------------------------------------------- /packages/presets/scripts/make-mainnets.js: -------------------------------------------------------------------------------- 1 | const chains = require('./chains.json') 2 | 3 | const SELECTED_CHAIN_IDS = [1, 56, 100, 137, 250, 43114, 1666600000] 4 | // conflux 1030 5 | 6 | const SLIP44 = { 7 | 250: 1007, 8 | 1666600000: 1023 9 | } 10 | 11 | const selected = chains.filter(item => SELECTED_CHAIN_IDS.indexOf(item.chainId) > -1) 12 | 13 | 14 | const presets = selected.map(chain => { 15 | const standard = chain.explorers && chain.explorers[0].standard 16 | const slip44 = chain.slip44 || SLIP44[chain.chainId] 17 | return { 18 | id: chain.chain.toLowerCase(), 19 | name: chain.name, 20 | alias: chain.shortName, 21 | chainId: '0x' + Number(chain.chainId).toString(16), 22 | slip44: '0x' + Number(0x80000000 + slip44).toString(16), 23 | extensions: standard === 'EIP3091' ? ['metamask'] : [], 24 | addressFormat: standard === 'EIP3091' ? 'ethers' : 'unknown', 25 | url: chain.rpc[0], 26 | explorer: chain.explorers[0].url, 27 | nativeCurrency: chain.nativeCurrency, 28 | mesonAddress: '', 29 | tokens: [], 30 | } 31 | }) 32 | 33 | console.log(JSON.stringify(presets, null, 2)) -------------------------------------------------------------------------------- /packages/adaptors/src/tron/type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file type. 3 | */ 4 | 5 | import { Failover, IMesonNetworkClientCommon, IMesonWalletCommon, MesonData } from '../types' 6 | 7 | export type IMesonTronNetworkClient = { 8 | fullNode: { 9 | host: string 10 | isConnected(): Promise 11 | } 12 | trx: MesonData 13 | contract(abi: MesonData, address: string): MesonData 14 | } & IMesonNetworkClientCommon<'tron'> 15 | 16 | export type IMesonTronFailoverNetworkClient = Failover<'tron', IMesonTronNetworkClient> 17 | 18 | export interface IMesonTronWallet extends IMesonWalletCommon<'tron'> { 19 | } 20 | 21 | export interface IMesonTronWalletWithExtension extends IMesonWalletCommon<'tron'> { 22 | } 23 | 24 | declare module '../types' { 25 | 26 | interface MesonNetworkClientMap { 27 | tron: IMesonTronNetworkClient 28 | } 29 | 30 | interface MesonFailoverNetworkClientMap { 31 | tron: IMesonTronFailoverNetworkClient 32 | } 33 | 34 | interface MesonWalletMap { 35 | tron: IMesonTronWallet 36 | } 37 | 38 | interface MesonWalletMapWithExtension { 39 | tron: IMesonTronWalletWithExtension 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/adaptors/src/ton/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | import { ERC20Contract, MesonContract, meson } from '@mesonfi/base' 6 | import { WithProvider } from '../types' 7 | 8 | import { TonNetworkClient } from './client' 9 | import { getContract } from './contract' 10 | import { IMesonTonFailoverNetworkClient } from './type' 11 | import { TonExtWallet, TonWallet } from './wallet' 12 | 13 | export * from './type' 14 | 15 | export { formatAddress, isAddress, clipRecipient } from './address' 16 | 17 | export { 18 | TonNetworkClient as NetworkClient, 19 | } 20 | 21 | export const Wallet = { 22 | Constructor: TonWallet, 23 | fromPrivateKey: TonWallet.fromPrivateKey, 24 | fromExtension: TonExtWallet.fromExtension, 25 | } 26 | 27 | export function getMesonInstance (address: string, networkClient: IMesonTonFailoverNetworkClient): WithProvider { 28 | return getContract(address, meson.ABI.Meson, networkClient) 29 | } 30 | 31 | export function getERC20Instance (address: string, networkClient: IMesonTonFailoverNetworkClient): WithProvider { 32 | return getContract(address, meson.ABI.ERC20, networkClient) 33 | } 34 | -------------------------------------------------------------------------------- /packages/clients/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mesonfi/clients", 3 | "version": "1.32.0-alpha.2", 4 | "description": "", 5 | "license": "MIT", 6 | "repository": "https://github.com/MesonFi/meson-contracts-solidity", 7 | "main": "lib/index.js", 8 | "module": "es/index.js", 9 | "typings": "lib/index.d.ts", 10 | "scripts": { 11 | "build": "npm run build:clean-dest && npm run build:clean && npm run build:run && npm run build:clean", 12 | "build:run": "npm run build:lib && npm run build:es", 13 | "build:clean-dest": "rm -rf lib && rm -rf es", 14 | "build:clean": "rm -rf lib-dist && rm -rf es-dist", 15 | "build:lib": "tsc --outDir lib-dist && mv lib-dist/src lib", 16 | "build:es": "tsc -m esnext --outDir es-dist && mv es-dist/src es", 17 | "prepare": "npm run build" 18 | }, 19 | "peerDependencies": { 20 | "@mesonfi/base": "*", 21 | "@mesonfi/rpc": "*" 22 | }, 23 | "dependencies": { 24 | "@mesonfi/sdk": "^1.32.0-alpha.1", 25 | "@mesonfi/presets": "^1.32.0-alpha.1" 26 | }, 27 | "files": [ 28 | "lib", 29 | "es" 30 | ], 31 | "publishConfig": { 32 | "registry": "https://npm.pkg.github.com/" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/adaptors/src/ckb/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | import { ERC20Contract, MesonContract, meson } from '@mesonfi/base' 6 | import { WithProvider } from '../types' 7 | 8 | import { CkbNetworkClient } from './client' 9 | import { getContract } from './contract' 10 | import { IMesonCkbFailoverNetworkClient } from './type' 11 | import { CkbWallet, CkbWalletFromJoyId } from './wallet' 12 | 13 | export * from './type' 14 | 15 | export { formatAddress, isAddress, clipRecipient } from './address' 16 | 17 | export { 18 | CkbNetworkClient as NetworkClient, 19 | } 20 | 21 | export const Wallet = { 22 | Constructor: CkbWallet, 23 | fromPrivateKey: CkbWallet.fromPrivateKey, 24 | fromExtension: CkbWalletFromJoyId.fromExtension, 25 | } 26 | 27 | export function getMesonInstance (address: string, networkClient: IMesonCkbFailoverNetworkClient): WithProvider { 28 | return getContract(address, meson.ABI.Meson, networkClient) 29 | } 30 | 31 | export function getERC20Instance (address: string, networkClient: IMesonCkbFailoverNetworkClient): WithProvider { 32 | return getContract(address, meson.ABI.ERC20, networkClient) 33 | } 34 | -------------------------------------------------------------------------------- /packages/presets/scripts/make-testnets.js: -------------------------------------------------------------------------------- 1 | const chains = require('./chains.json') 2 | 3 | const SELECTED_CHAIN_IDS = [3, 97, 80001, 4002, 43113, 1666700000] 4 | 5 | const SLIP44 = { 6 | 3: 60, 7 | 97: 714, 8 | 80001: 966, 9 | 4002: 1007, 10 | 43113: 9000, 11 | 1666700000: 1023 12 | } 13 | 14 | const selected = chains.filter(item => SELECTED_CHAIN_IDS.indexOf(item.chainId) > -1) 15 | 16 | 17 | const presets = selected.map(chain => { 18 | const explorer = chain.explorers && chain.explorers[0] || {} 19 | const slip44 = chain.slip44 || SLIP44[chain.chainId] 20 | return { 21 | id: chain.chain.toLowerCase() + '-testnet', 22 | name: chain.name, 23 | alias: chain.shortName, 24 | chainId: '0x' + Number(chain.chainId).toString(16), 25 | slip44: '0x' + Number(0x80000000 + slip44).toString(16), 26 | extensions: explorer.standard === 'EIP3091' ? ['metamask'] : [], 27 | addressFormat: explorer.standard === 'EIP3091' ? 'ethers' : 'unknown', 28 | url: chain.rpc[0], 29 | explorer: explorer.url, 30 | nativeCurrency: chain.nativeCurrency, 31 | mesonAddress: '', 32 | tokens: [], 33 | } 34 | }) 35 | 36 | console.log(JSON.stringify(presets, null, 2)) -------------------------------------------------------------------------------- /packages/adaptors/src/aptos/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | import { ERC20Contract, MesonContract, meson } from '@mesonfi/base' 6 | import { WithProvider } from '../types' 7 | 8 | import { AptosNetworkClient } from './client' 9 | import { getContract } from './contract' 10 | import { IMesonAptosFailoverNetworkClient } from './type' 11 | import { AptosExtWallet, AptosWallet } from './wallet' 12 | 13 | export * from './type' 14 | 15 | export { formatAddress, isAddress, clipRecipient } from './address' 16 | 17 | export { 18 | AptosNetworkClient as NetworkClient, 19 | } 20 | 21 | export const Wallet = { 22 | Constructor: AptosWallet, 23 | fromPrivateKey: AptosWallet.fromPrivateKey, 24 | fromExtension: AptosExtWallet.fromExtension, 25 | } 26 | 27 | export function getMesonInstance (address: string, networkClient: IMesonAptosFailoverNetworkClient): WithProvider { 28 | return getContract(address, meson.ABI.Meson, networkClient) 29 | } 30 | 31 | export function getERC20Instance (address: string, networkClient: IMesonAptosFailoverNetworkClient): WithProvider { 32 | return getContract(address, meson.ABI.ERC20, networkClient) 33 | } 34 | -------------------------------------------------------------------------------- /packages/adaptors/src/ethers/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | import { ethers } from 'ethers' 6 | 7 | import { ERC20Contract, MesonContract, meson } from '@mesonfi/base' 8 | import { MesonData, WithProvider } from '../types' 9 | 10 | import { EthersNetworkClient } from './client' 11 | import { IMesonEthersFailoverNetworkClient } from './type' 12 | import { fromExtension, fromPrivateKey } from './wallet' 13 | 14 | export * from './type' 15 | 16 | export { formatAddress, isAddress, clipRecipient } from './address' 17 | 18 | export { 19 | EthersNetworkClient as NetworkClient, 20 | } 21 | 22 | export const Wallet = { 23 | Constructor: ethers.Wallet, 24 | fromPrivateKey, 25 | fromExtension, 26 | } 27 | 28 | export function getMesonInstance (address: string, networkClient: IMesonEthersFailoverNetworkClient): WithProvider { 29 | return new ethers.Contract(address, meson.ABI.Meson, networkClient) as MesonData 30 | } 31 | 32 | export function getERC20Instance (address: string, networkClient: IMesonEthersFailoverNetworkClient): WithProvider { 33 | return new ethers.Contract(address, meson.ABI.ERC20, networkClient) as MesonData 34 | } 35 | -------------------------------------------------------------------------------- /packages/adaptors/src/ton/type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file type. 3 | */ 4 | import { Combine, IMesonToken } from '@mesonfi/base' 5 | import { TonClient } from '@ton/ton' 6 | 7 | import { Failover, IMesonNetworkClientCommon, IMesonWalletCommon, MesonData } from '../types' 8 | 9 | export interface IMesonTonNetworkClient extends Combine, TonClient> { 10 | 11 | readonly tokens: IMesonToken[] 12 | 13 | _detectNetwork(): Promise 14 | } 15 | 16 | export type IMesonTonFailoverNetworkClient = Failover<'ton', IMesonTonNetworkClient> 17 | 18 | export interface IMesonTonWallet extends IMesonWalletCommon<'ton'> { 19 | } 20 | 21 | export interface IMesonTonWalletWithExtension extends IMesonWalletCommon { 22 | readonly ext: MesonData 23 | } 24 | 25 | declare module '../types' { 26 | 27 | interface MesonNetworkClientMap { 28 | ton: IMesonTonNetworkClient 29 | } 30 | 31 | interface MesonFailoverNetworkClientMap { 32 | ton: IMesonTonFailoverNetworkClient 33 | } 34 | 35 | interface MesonWalletMap { 36 | ton: IMesonTonWallet 37 | } 38 | 39 | interface MesonWalletMapWithExtension { 40 | ton: IMesonTonWalletWithExtension 41 | } 42 | } 43 | 44 | export {} 45 | -------------------------------------------------------------------------------- /packages/adaptors/src/tron/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | import { ERC20Contract, MesonContract, meson } from '@mesonfi/base' 6 | import { MesonData, WithProvider } from '../types' 7 | 8 | import { TronNetworkClient } from './client' 9 | import { TronContract } from './contract' 10 | import { IMesonTronFailoverNetworkClient } from './type' 11 | import { TronWallet } from './wallet' 12 | 13 | export * from './type' 14 | 15 | export { formatAddress, isAddress, clipRecipient } from './address' 16 | 17 | export { 18 | TronNetworkClient as NetworkClient, 19 | } 20 | 21 | export const Wallet = { 22 | Constructor: TronWallet, 23 | fromPrivateKey: TronWallet.fromPrivateKey, 24 | fromExtension: TronWallet.fromExtension, 25 | } 26 | 27 | export function getMesonInstance (address: string, networkClient: IMesonTronFailoverNetworkClient): WithProvider { 28 | return new TronContract(address, meson.ABI.Meson, networkClient) as MesonData 29 | } 30 | 31 | export function getERC20Instance (address: string, networkClient: IMesonTronFailoverNetworkClient): WithProvider { 32 | return new TronContract(address, meson.ABI.ERC20, networkClient) as MesonData 33 | } 34 | -------------------------------------------------------------------------------- /packages/adaptors/src/bitcoin/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | import { ERC20Contract, MesonContract, meson } from '@mesonfi/base' 6 | import { WithProvider } from '../types' 7 | 8 | import { BitcoinNetworkClient } from './client' 9 | import { getContract } from './contract' 10 | import { IMesonBitcoinFailoverNetworkClient } from './type' 11 | import { BtcWalletFromExtension, BtcWallet } from './wallet' 12 | 13 | export * from './type' 14 | 15 | export { formatAddress, isAddress, clipRecipient } from './address' 16 | 17 | export { 18 | BitcoinNetworkClient as NetworkClient, 19 | } 20 | 21 | export const Wallet = { 22 | Constructor: BtcWallet, 23 | fromPrivateKey: BtcWallet.fromPrivateKey, 24 | fromExtension: BtcWalletFromExtension.fromExtension, 25 | } 26 | 27 | export function getMesonInstance (address: string, networkClient: IMesonBitcoinFailoverNetworkClient): WithProvider { 28 | return getContract(address, meson.ABI.Meson, networkClient) 29 | } 30 | 31 | export function getERC20Instance (address: string, networkClient: IMesonBitcoinFailoverNetworkClient): WithProvider { 32 | return getContract(address, meson.ABI.ERC20, networkClient) 33 | } 34 | -------------------------------------------------------------------------------- /packages/adaptors/src/sui/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | import { ERC20Contract, MesonContract, meson } from '@mesonfi/base' 6 | import { WithProvider } from '../types' 7 | 8 | import { SuiNetworkClient } from './client' 9 | import { getContract } from './contract' 10 | import { IMesonSuiFailoverNetworkClient } from './type' 11 | import { SuiExtWallet, SuiWallet } from './wallet' 12 | 13 | export * from './type' 14 | 15 | export { formatAddress, isAddress, clipRecipient } from './address' 16 | 17 | export { 18 | SuiNetworkClient as NetworkClient, 19 | } 20 | 21 | export const Wallet = { 22 | Constructor: SuiWallet, 23 | fromPrivateKey: SuiWallet.fromPrivateKey, 24 | fromExtension: SuiExtWallet.fromExtension, 25 | } 26 | 27 | export function getMesonInstance (address: string, networkClient: IMesonSuiFailoverNetworkClient): WithProvider { 28 | return getContract(address, meson.ABI.Meson, networkClient) as WithProvider 29 | } 30 | 31 | export function getERC20Instance (address: string, networkClient: IMesonSuiFailoverNetworkClient): WithProvider { 32 | return getContract(address, meson.ABI.ERC20, networkClient) as WithProvider 33 | } 34 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/tron/index.ts: -------------------------------------------------------------------------------- 1 | import TronWeb from 'tronweb' 2 | 3 | import TronAdaptor from './TronAdaptor' 4 | import TronWallet from './TronWallet' 5 | import TronContract from './TronContract' 6 | import { FailoverTronAdaptor } from '../FailoverAdaptors' 7 | 8 | export function getWallet(privateKey: string, adaptor: TronAdaptor, Wallet = TronWallet): TronWallet { 9 | if (privateKey.startsWith('0x')) { 10 | privateKey = privateKey.substring(2) 11 | } 12 | let injectedAdaptor 13 | if (adaptor['adaptors']) { 14 | injectedAdaptor = new FailoverTronAdaptor(adaptor['adaptors'].map(adp => _injectPrivateKey(privateKey, adp))) 15 | } else { 16 | injectedAdaptor = _injectPrivateKey(privateKey, adaptor) 17 | } 18 | return new Wallet(injectedAdaptor) 19 | } 20 | 21 | function _injectPrivateKey(privateKey: string, adaptor: TronAdaptor): TronAdaptor { 22 | return new TronAdaptor(new TronWeb({ fullHost: adaptor.client.fullNode.host, privateKey })) 23 | } 24 | 25 | export function getWalletFromExtension(adaptor: TronAdaptor): TronWallet { 26 | return new TronWallet(adaptor) 27 | } 28 | 29 | export function getContract(address: string, abi, adaptor: TronAdaptor) { 30 | return new TronContract(address, abi, adaptor) 31 | } 32 | -------------------------------------------------------------------------------- /packages/presets/src/providers.ts: -------------------------------------------------------------------------------- 1 | import { RPC as CkbRPC } from '@ckb-lumos/lumos' 2 | import { TonClient, type TonClientParameters } from '@ton/ton' 3 | import { Aptos as AptosClient, Network, AptosConfig } from '@aptos-labs/ts-sdk' 4 | 5 | export class ExtendedAptosClient extends AptosClient { 6 | constructor(url: string) { 7 | super(new AptosConfig({ 8 | fullnode: url, 9 | indexer: process.env.APTOS_GRAPHQL_URL || `https://api.mainnet.aptoslabs.com/v1/graphql`, 10 | network: Network.CUSTOM, 11 | fullnodeConfig: { 12 | HEADERS: { Authorization: `Bearer ${process.env.APTOS_API_KEY}` }, 13 | }, 14 | indexerConfig: { 15 | HEADERS: { Authorization: `Bearer ${process.env.APTOS_GRAPHQL_API_KEY}` }, 16 | }, 17 | })) 18 | } 19 | } 20 | 21 | export class ExtendedCkbClient extends CkbRPC { 22 | readonly metadata: any 23 | 24 | constructor(url: string, config: any, metadata: any) { 25 | super(url, config || {}) 26 | this.metadata = metadata 27 | } 28 | } 29 | 30 | export class ExtendedTonClient extends TonClient { 31 | readonly metadata: any 32 | 33 | constructor(parameters: TonClientParameters, metadata: any) { 34 | super(parameters) 35 | this.metadata = metadata 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/rpc/src/MesonRpcs.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'cross-fetch' 2 | 3 | import { IMesonRpcs, MesonNetworkStatus } from './types' 4 | import { MesonRpcStatusCache } from './MesonRpcStatusCache' 5 | 6 | export class MesonRpcs extends MesonRpcStatusCache implements IMesonRpcs { 7 | 8 | private readonly rpcManagerURL: string 9 | 10 | constructor (rpcManagerURL: string) { 11 | super() 12 | this.rpcManagerURL = rpcManagerURL 13 | } 14 | 15 | public async refreshAllRpcStatus () { 16 | try { 17 | 18 | const rpcStatusObject = await this.fetchRpcs() 19 | 20 | for (const [networkId, data] of Object.entries(rpcStatusObject)) { 21 | this.update(networkId, data) 22 | } 23 | 24 | this.setReady() 25 | } catch (err) { 26 | console.error(err) 27 | } 28 | } 29 | 30 | public async fetchRpcs (): Promise> { 31 | 32 | const response = await fetch(this.rpcManagerURL) 33 | 34 | const body: { 35 | success: boolean 36 | data: Record 37 | error: string 38 | } = await response.json() 39 | 40 | if (!body.success) { 41 | throw new Error('failed to fetch rpcs ' + body.error) 42 | } 43 | 44 | return body.data 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/adaptors/src/solana/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | import { ERC20Contract, MesonContract, meson } from '@mesonfi/base' 6 | import { WithProvider } from '../types' 7 | 8 | import { SolanaNetworkClient } from './client' 9 | import { getContract } from './contract' 10 | import { IMesonSolanaFailoverNetworkClient } from './type' 11 | import { SolanaExtWallet, SolanaWallet } from './wallet' 12 | 13 | export * from './type' 14 | 15 | export { formatAddress, isAddress, clipRecipient } from './address' 16 | 17 | export { 18 | SolanaNetworkClient as NetworkClient, 19 | } 20 | 21 | export const Wallet = { 22 | Constructor: SolanaWallet, 23 | fromPrivateKey: SolanaWallet.fromPrivateKey, 24 | fromExtension: SolanaExtWallet.fromExtension, 25 | } 26 | 27 | export function getMesonInstance (address: string, networkClient: IMesonSolanaFailoverNetworkClient): WithProvider { 28 | return getContract(address, meson.ABI.Meson, networkClient) as WithProvider 29 | } 30 | 31 | export function getERC20Instance (address: string, networkClient: IMesonSolanaFailoverNetworkClient): WithProvider { 32 | return getContract(address, meson.ABI.ERC20, networkClient) as WithProvider 33 | } 34 | -------------------------------------------------------------------------------- /packages/adaptors/src/solana/type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file type. 3 | */ 4 | import { Combine } from '@mesonfi/base' 5 | import { Connection as SolConnection } from '@solana/web3.js' 6 | import { Failover, IMesonNetworkClientCommon, IMesonWalletCommon, MesonData } from '../types' 7 | 8 | export interface IMesonSolanaNetworkClient extends Combine, SolConnection> { 9 | _detectNetwork(): Promise 10 | _getTransactionCount (addr: string): Promise 11 | } 12 | 13 | export type IMesonSolanaFailoverNetworkClient = Failover<'solana', IMesonSolanaNetworkClient> 14 | 15 | export interface IMesonSolanaWallet extends IMesonWalletCommon<'solana'> { 16 | signMessage(message: string): MesonData 17 | } 18 | 19 | export interface IMesonSolanaWalletWithExtension extends IMesonWalletCommon<'solana'> { 20 | readonly ext: MesonData 21 | } 22 | 23 | declare module '../types' { 24 | 25 | interface MesonNetworkClientMap { 26 | solana: IMesonSolanaNetworkClient 27 | } 28 | 29 | interface MesonFailoverNetworkClientMap { 30 | solana: IMesonSolanaFailoverNetworkClient 31 | } 32 | 33 | interface MesonWalletMap { 34 | solana: IMesonSolanaWallet 35 | } 36 | 37 | interface MesonWalletMapWithExtension { 38 | solana: IMesonSolanaWalletWithExtension 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/adaptors/src/starknet/type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file type. 3 | */ 4 | import { Combine } from '@mesonfi/base' 5 | import { Contract as StarkContract, RpcProvider as StarkProvider } from 'starknet' 6 | import { Failover, IMesonNetworkClientCommon, IMesonWalletCommon, MesonData } from '../types' 7 | 8 | export interface IMesonStarknetNetworkClient extends Combine, StarkProvider> { 9 | readonly _coreToken: StarkContract 10 | } 11 | 12 | export type IMesonStarknetFailoverNetworkClient = Failover<'starknet', IMesonStarknetNetworkClient> 13 | 14 | export interface IMesonStarknetWallet extends IMesonWalletCommon<'starknet'> { 15 | signMessage(message: string): MesonData 16 | } 17 | 18 | export interface IMesonStarknetWalletWithExtension extends IMesonWalletCommon<'starknet'> { 19 | readonly ext: MesonData 20 | } 21 | 22 | declare module '../types' { 23 | 24 | interface MesonNetworkClientMap { 25 | starknet: IMesonStarknetNetworkClient 26 | } 27 | 28 | interface MesonFailoverNetworkClientMap { 29 | starknet: IMesonStarknetFailoverNetworkClient 30 | } 31 | 32 | interface MesonWalletMap { 33 | starknet: IMesonStarknetWallet 34 | } 35 | 36 | interface MesonWalletMapWithExtension { 37 | starknet: IMesonStarknetWalletWithExtension 38 | } 39 | } 40 | 41 | export {} 42 | -------------------------------------------------------------------------------- /packages/adaptors/src/aptos/type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file type. 3 | */ 4 | import type { Aptos as AptosClient, LedgerInfo } from '@aptos-labs/ts-sdk' 5 | import { Combine } from '@mesonfi/base' 6 | 7 | import { Failover, IMesonNetworkClientCommon, IMesonWalletCommon, MesonData } from '../types' 8 | 9 | export interface IMesonAptosNetworkClient extends Combine, AptosClient> { 10 | _detectNetwork(): Promise 11 | } 12 | 13 | export type IMesonAptosFailoverNetworkClient = Failover<'aptos', IMesonAptosNetworkClient> 14 | 15 | export interface IMesonAptosWallet extends IMesonWalletCommon<'aptos'> { 16 | 17 | signMessage(message: string): MesonData 18 | 19 | deploy(module: string, metadata: string): Promise 20 | } 21 | 22 | export interface IMesonAptosWalletWithExtension extends IMesonWalletCommon<'aptos'> { 23 | readonly ext: MesonData 24 | } 25 | 26 | declare module '../types' { 27 | 28 | interface MesonNetworkClientMap { 29 | aptos: IMesonAptosNetworkClient 30 | } 31 | 32 | interface MesonFailoverNetworkClientMap { 33 | aptos: IMesonAptosFailoverNetworkClient 34 | } 35 | 36 | interface MesonWalletMap { 37 | aptos: IMesonAptosWallet 38 | } 39 | 40 | interface MesonWalletMapWithExtension { 41 | aptos: IMesonAptosWalletWithExtension 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/shared/meson.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'hardhat' 2 | import { BigNumberish } from 'ethers' 3 | import { PartialSwapData, SwapData } from '@mesonfi/sdk' 4 | 5 | export const TestAddress = '0x7F342A0D04B951e8600dA1eAdD46afe614DaC20B' 6 | export const TestAddress2 = '0x2eF8a51F8fF129DBb874A0efB021702F59C1b211' 7 | export const AddressOne = '0x0000000000000000000000000000000000000001' 8 | 9 | export function getPartialSwap({ 10 | amount = ethers.utils.parseUnits('1000', 6) as BigNumberish, 11 | fee = ethers.utils.parseUnits('1', 6) as BigNumberish, 12 | inToken = 1, 13 | outToken = 1, 14 | } = {}): PartialSwapData { 15 | return { 16 | amount, 17 | fee, 18 | inToken, 19 | outToken, 20 | recipient: '0x2ef8a51f8ff129dbb874a0efb021702f59c1b211', 21 | salt: '0x80' 22 | } 23 | } 24 | 25 | export function getSwap({ 26 | amount = ethers.utils.parseUnits('1000', 6) as BigNumberish, 27 | fee = ethers.utils.parseUnits('1', 6) as BigNumberish, 28 | expireTs = Math.floor(Date.now() / 1000) + 5400, 29 | inChain = '0x0001', 30 | inToken = 2, 31 | outChain = '0x0002', 32 | outToken = 3, 33 | } = {}): SwapData { 34 | return { 35 | amount, 36 | fee, 37 | expireTs, 38 | inChain, 39 | inToken, 40 | outChain, 41 | outToken, 42 | recipient: '0x2ef8a51f8ff129dbb874a0efb021702f59c1b211', 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/base/src/const/CategoryTokenMap.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file CategoryTokenMap 3 | */ 4 | export const CategoryTokenMap: Record = { 5 | 1: 'usdc', 6 | 2: 'usdt', 7 | 3: 'busd', 8 | 4: 'usdc', 9 | 7: 'pusd', 10 | 9: 'usdc', 11 | 10: 'usdt', 12 | 16: 'usd1', 13 | 17: 'usdc', 14 | 18: 'usdt', 15 | 19: 'busd', 16 | 32: 'pod', 17 | 33: 'usdc', 18 | 34: 'usdt', 19 | 35: 'busd', 20 | 36: 'dai', 21 | 37: 'cusd', 22 | 39: 'usdb', 23 | 40: 'fdusd', 24 | 41: 'bbusd', 25 | 48: 'usd1', 26 | 49: 'usdc', 27 | 52: 'dai', 28 | 65: 'iusd', 29 | 67: 'mbtc', 30 | 69: 'merl', 31 | 71: 'stone', 32 | 73: 'solvbtc-m', 33 | 75: 'solvbtc', 34 | 77: 'solvbtc-a', 35 | 79: 'ubtc', 36 | 81: 'xsolvbtc', 37 | 83: 'solvbtc-ena', 38 | 85: 'solvbtc-jup', 39 | 87: 'pump', 40 | 89: 'b2', 41 | 91: 'solvbtc-bera', 42 | 113: 'pumpbtc', 43 | 114: 'unibtc', 44 | 115: 'cbbtc', 45 | 116: 'fbtc', 46 | 124: 'duck', 47 | 191: 'gas-token', 48 | 194: 'm', 49 | 195: 'm', 50 | 198: 'taker', 51 | 199: 'taker', 52 | 236: 'pol', 53 | 238: 'pol', 54 | 239: 'pol', 55 | 240: 'btc', 56 | 241: 'btc', 57 | 242: 'btc', 58 | 243: 'btc', 59 | 244: 'sol', 60 | 246: 'sol', 61 | 247: 'sol', 62 | 248: 'bnb', 63 | 250: 'bnb', 64 | 251: 'bnb', 65 | 252: 'eth', 66 | 254: 'eth', 67 | 255: 'eth', 68 | } 69 | -------------------------------------------------------------------------------- /packages/sdk/src/SwapWithSigner.ts: -------------------------------------------------------------------------------- 1 | import { Swap, SwapData } from './Swap' 2 | import { SwapSigner } from './SwapSigner' 3 | import { SignedSwapRequestData, SignedSwapReleaseData } from './SignedSwap' 4 | 5 | export class SwapWithSigner extends Swap { 6 | readonly swapSigner: SwapSigner 7 | 8 | constructor(req: SwapData, swapSigner: SwapSigner) { 9 | super(req) 10 | this.swapSigner = swapSigner 11 | } 12 | 13 | async signForRequest(testnet: boolean): Promise { 14 | const signature = await this.swapSigner.signSwapRequest(this.encoded, testnet) 15 | const initiator = this.swapSigner.getAddress(this.encoded) 16 | const data: SignedSwapRequestData = { 17 | encoded: this.encoded, 18 | initiator, 19 | signature, 20 | } 21 | if (testnet) { 22 | data.testnet = true 23 | } 24 | return data 25 | } 26 | 27 | async signForRelease(recipient: string, testnet: boolean): Promise { 28 | const signature = await this.swapSigner.signSwapRelease(this.encoded, recipient, testnet) 29 | const initiator = this.swapSigner.getAddress(this.encoded) 30 | const data: SignedSwapReleaseData = { 31 | encoded: this.encoded, 32 | initiator, 33 | recipient, 34 | signature, 35 | } 36 | if (testnet) { 37 | data.testnet = true 38 | } 39 | return data 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/adaptors/src/starknet/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | 5 | import { ERC20Contract, meson, MesonContract } from '@mesonfi/base' 6 | import { WithProvider } from '../types' 7 | 8 | import { StarknetNetworkClient } from './client' 9 | import { getContract } from './contract' 10 | import { IMesonStarknetFailoverNetworkClient } from './type' 11 | import { StarkExtWallet, StarkWallet } from './wallet' 12 | 13 | import AbiMeson from './abi/Meson.json' 14 | import AbiERC20 from './abi/ERC20.json' 15 | 16 | export * from './type' 17 | 18 | export { formatAddress, isAddress, clipRecipient } from './address' 19 | 20 | export { 21 | StarknetNetworkClient as NetworkClient, 22 | } 23 | 24 | export const Wallet = { 25 | Constructor: StarkWallet, 26 | fromPrivateKey: StarkWallet.fromPrivateKey, 27 | fromExtension: StarkExtWallet.fromExtension, 28 | } 29 | 30 | export function getMesonInstance (address: string, networkClient: IMesonStarknetFailoverNetworkClient): WithProvider { 31 | return getContract(address, meson.ABI.Meson, AbiMeson, networkClient) as WithProvider 32 | } 33 | 34 | export function getERC20Instance (address: string, networkClient: IMesonStarknetFailoverNetworkClient): WithProvider { 35 | return getContract(address, meson.ABI.ERC20, AbiERC20, networkClient) as WithProvider 36 | } 37 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import('eslint').Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: ['standard'], 5 | rules: { 6 | 'comma-dangle': ['error', 'always-multiline'], 7 | curly: ['error', 'all'], 8 | 'brace-style': ['error', '1tbs'], 9 | 'padded-blocks': ['off'], 10 | }, 11 | overrides: [ 12 | { 13 | files: ['**/*.ts', '**/*.tsx'], 14 | parser: '@typescript-eslint/parser', 15 | parserOptions: { 16 | tsconfigRootDir: __dirname, 17 | project: ['./tsconfig.eslint.json'], 18 | sourceType: 'module', 19 | }, 20 | plugins: ['@typescript-eslint', '@stylistic'], 21 | extends: [ 22 | 'plugin:@typescript-eslint/strict', 23 | 'plugin:@typescript-eslint/stylistic', 24 | ], 25 | rules: { 26 | 'no-use-before-define': 'off', 27 | '@typescript-eslint/no-use-before-define': ['off'], 28 | '@stylistic/member-delimiter-style': ['error', { 29 | multiline: { delimiter: 'none', requireLast: false }, 30 | }], 31 | }, 32 | }, 33 | ], 34 | ignorePatterns: [ 35 | // 'packages/adaptors/src/*/contract.ts', 36 | // 'packages/adaptors/src/*/client.ts', 37 | // 'packages/adaptors/src/*/wallet.ts', 38 | 'packages/sdk/', 39 | 'packages/presets/', 40 | 'lib/', 41 | 'es/', 42 | 'test/', 43 | 'node_modules/', 44 | '*.d.ts', 45 | ], 46 | } 47 | -------------------------------------------------------------------------------- /packages/adaptors/src/bitcoin/type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file type. 3 | */ 4 | import type { Network } from 'bitcoinjs-lib' 5 | import { Failover, IMesonNetworkClientCommon, IMesonWalletCommon, MesonData } from '../types' 6 | 7 | export interface IMesonBitcoinNetworkClient extends IMesonNetworkClientCommon<'bitcoin'> { 8 | readonly isTestnet: boolean 9 | readonly mesonAddress: string 10 | readonly network: Network 11 | 12 | _detectNetwork(): Promise 13 | 14 | _fetch(path: string): Promise 15 | 16 | _tx(data: string): Promise 17 | 18 | _getFeeRate(): Promise 19 | } 20 | 21 | export type IMesonBitcoinFailoverNetworkClient = Failover<'bitcoin', IMesonBitcoinNetworkClient>; 22 | 23 | export interface IMesonBitcoinWallet extends IMesonWalletCommon<'bitcoin'> { 24 | } 25 | 26 | export interface IMesonBitcoinWalletWithExtension extends IMesonWalletCommon<'bitcoin'> { 27 | readonly ext: MesonData 28 | 29 | deploy(): Promise 30 | } 31 | 32 | declare module '../types' { 33 | 34 | interface MesonNetworkClientMap { 35 | bitcoin: IMesonBitcoinNetworkClient 36 | } 37 | 38 | interface MesonFailoverNetworkClientMap { 39 | bitcoin: IMesonBitcoinFailoverNetworkClient 40 | } 41 | 42 | interface MesonWalletMap { 43 | bitcoin: IMesonBitcoinWallet 44 | } 45 | 46 | interface MesonWalletMapWithExtension { 47 | bitcoin: IMesonBitcoinWalletWithExtension 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/shared/fixtures.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'hardhat' 2 | import { MockToken, MesonPoolsTest, MesonSwapTest } from '../../typechain-types' 3 | 4 | export const TOKEN_BALANCE = ethers.utils.parseUnits('3000', 6) 5 | export const TOKEN_TOTAL_SUPPLY = ethers.utils.parseUnits('10000', 6) 6 | 7 | export async function fixtures (accounts: string[] | undefined) { 8 | const signer = (await ethers.getSigners())[0] 9 | 10 | const tokenFactory = await ethers.getContractFactory('MockToken') 11 | const token1 = await tokenFactory.deploy('Mock Token 1', 'MT1', TOKEN_TOTAL_SUPPLY, 6) as MockToken 12 | const token2 = await tokenFactory.deploy('Mock Token 2', 'MT2', TOKEN_TOTAL_SUPPLY, 18) as MockToken 13 | 14 | if (accounts) { 15 | for (const account of accounts) { 16 | await signer.sendTransaction({ 17 | to: account, 18 | value: ethers.utils.parseEther('10') 19 | }) 20 | await token1.transfer(account, TOKEN_BALANCE) 21 | await token2.transfer(account, TOKEN_BALANCE) 22 | } 23 | } 24 | 25 | const poolsFactory = await ethers.getContractFactory('MesonPoolsTest') 26 | const pools = await poolsFactory.deploy(token1.address, accounts && accounts[1] || ethers.constants.AddressZero) as MesonPoolsTest 27 | 28 | const swapFactory = await ethers.getContractFactory('MesonSwapTest') 29 | const swap = await swapFactory.deploy(token1.address) as MesonSwapTest 30 | 31 | return { pools, swap, token1, token2 } 32 | } 33 | -------------------------------------------------------------------------------- /packages/adaptors/src/all.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file all 3 | */ 4 | 5 | import * as adaptors from './adaptors' 6 | 7 | import * as aptos from './aptos' 8 | import * as bitcoin from './bitcoin' 9 | import * as ckb from './ckb' 10 | import * as ethers from './ethers' 11 | import * as solana from './solana' 12 | import * as starknet from './starknet' 13 | import * as sui from './sui' 14 | import * as tron from './tron' 15 | import * as ton from './ton' 16 | 17 | export function initAdaptors () { 18 | adaptors.registerAdaptorConfig('aptos', aptos) 19 | adaptors.registerAdaptorConfig('bitcoin', bitcoin) 20 | adaptors.registerAdaptorConfig('ckb', ckb) 21 | adaptors.registerAdaptorConfig('ethers', ethers) 22 | adaptors.registerAdaptorConfig('solana', solana) 23 | adaptors.registerAdaptorConfig('starknet', starknet) 24 | adaptors.registerAdaptorConfig('sui', sui) 25 | adaptors.registerAdaptorConfig('tron', tron) 26 | adaptors.registerAdaptorConfig('ton', ton) 27 | } 28 | 29 | export { 30 | adaptors, 31 | } 32 | 33 | export * from './types' 34 | 35 | export type { MesonAdaptorConfigManager } from './MesonAdaptorConfigManager' 36 | 37 | export type * from './aptos/type' 38 | export type * from './bitcoin/type' 39 | export type * from './ckb/type' 40 | export type * from './ethers/type' 41 | export type * from './solana/type' 42 | export type * from './starknet/type' 43 | export type * from './sui/type' 44 | export type * from './ton/type' 45 | export type * from './tron/type' 46 | -------------------------------------------------------------------------------- /packages/client/test/demo.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file demo 3 | */ 4 | 5 | import {initAdaptors} from '@mesonfi/adaptors/src/all'; 6 | import {useMesonNode} from '../src/node'; 7 | 8 | initAdaptors(); 9 | 10 | const {clients, rpcs, waitForRpcStatusReady, init} = useMesonNode({ 11 | rpcManagerURL: 'https://rpcs.meson.fi' 12 | }); 13 | 14 | async function main() { 15 | 16 | await init(); 17 | await waitForRpcStatusReady(); 18 | 19 | const mesonClient = clients.getMesonClient('bnb'); 20 | const networkClient = clients.getNetworkClient('bnb'); 21 | 22 | console.log(await networkClient.getBalance('0x666d6b8a44d226150ca9058beebafe0e3ac065a2')); 23 | console.log(await mesonClient.getTokenBalance('0x666d6b8a44d226150ca9058beebafe0e3ac065a2', 251)); 24 | 25 | await networkClient.getBlockInfo(); 26 | 27 | await mesonClient.ready(); 28 | 29 | console.log(await networkClient.getBlockInfo()); 30 | console.log(await networkClient.getGasPrice()); 31 | 32 | const contract = mesonClient.mesonInstance; 33 | 34 | console.log(await contract.getSupportedTokens()); 35 | 36 | const wallet = clients.getWalletByPrivateKey('', 'aptos'); 37 | 38 | await wallet.sendTransaction('foo', 'bar'); 39 | 40 | if (wallet.addressFormat === 'aptos') { 41 | const message = wallet.signMessage('xxx'); 42 | console.log(message); 43 | } 44 | 45 | setInterval(() => { 46 | console.log(JSON.stringify(rpcs.getAllHealthyRpcStatus())); 47 | }, 3000); 48 | } 49 | 50 | void main(); 51 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/tron/TronWallet.ts: -------------------------------------------------------------------------------- 1 | import TronAdaptor from './TronAdaptor' 2 | 3 | export default class TronWallet extends TronAdaptor { 4 | constructor(adaptor: TronAdaptor) { 5 | super(adaptor.client) 6 | } 7 | 8 | get tronWeb () { 9 | return this.client 10 | } 11 | 12 | get address() { 13 | return this.tronWeb.defaultAddress.base58 14 | } 15 | 16 | async transfer({ to, value }) { 17 | const tx = await this.tronWeb.transactionBuilder.sendTrx(to, value.toString()) 18 | const signed = await this.tronWeb.trx.sign(tx) 19 | const receipt = await this.tronWeb.trx.sendRawTransaction(signed) 20 | return { 21 | hash: receipt.txID, 22 | wait: (confirmations: number) => this.waitForTransaction(receipt.txID, confirmations) 23 | } 24 | } 25 | 26 | async sendTransaction(payload, overrides) { 27 | if (!payload.contract) { 28 | return await this.transfer(payload) 29 | } 30 | const { contract, method, args } = payload 31 | const hash = await contract[method](...args).send(overrides) 32 | return { 33 | hash, 34 | wait: (confirmations: number) => this.waitForTransaction(hash, confirmations) 35 | } 36 | } 37 | 38 | async deploy() {} 39 | 40 | async getTransaction(hash: string): Promise { 41 | while (true) { 42 | try { 43 | return await this.send('eth_getTransactionByHash', [hash]) 44 | } catch { 45 | await new Promise(resolve => setTimeout(resolve, 1000)) 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /scripts/pool.js: -------------------------------------------------------------------------------- 1 | const { adaptors } = require('@mesonfi/sdk') 2 | const { meson } = require('@mesonfi/base') 3 | const { getAdaptor } = require('./lib/getAdaptor') 4 | const { addSupportedTokens, deposit, withdraw, send, authorize, transferOwner, withdrawServiceFee } = require('./lib/pool') 5 | 6 | require('dotenv').config() 7 | 8 | const { LP_PRIVATE_KEY } = process.env 9 | 10 | const amount = '10' 11 | const category = 'USDC' 12 | const addr = '' 13 | 14 | module.exports = async function pool (network) { 15 | const adaptor = getAdaptor(network) 16 | 17 | const wallet = adaptors.getWallet(LP_PRIVATE_KEY, adaptor) 18 | console.log(`⬜️ LP address: ${wallet.address}`) 19 | 20 | const mesonInstance = adaptors.getContract(network.mesonAddress, meson.ABI.Meson, wallet) 21 | console.log(`🟩 Status: ${JSON.stringify(await mesonInstance.provider.detectNetwork())}`) 22 | console.log(`🟩 Block height: ${await mesonInstance.provider.getBlockNumber()}`) 23 | console.log(`🟩 LP balance: ${await mesonInstance.provider.getBalance(wallet.address)}`) 24 | 25 | // const tx = await deposit(category, amount, { network, wallet }) 26 | // const tx = await withdraw(category, amount, { network, wallet }) 27 | // const tx = await send(category, amount, addr, { network, wallet }) 28 | // const tx = await addSupportedTokens(tokens, { network, wallet }) 29 | // const tx = await authorize(addr, { network, wallet }) 30 | // const tx = await transferOwner(addr, { network, wallet }) 31 | // const tx = await withdrawServiceFee(category, amount, { network, wallet }) 32 | // console.log(tx) 33 | } 34 | -------------------------------------------------------------------------------- /packages/adaptors/src/ckb/type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file type. 3 | */ 4 | import { config, Indexer, RPC as CkbRPC } from '@ckb-lumos/lumos' 5 | import type { CKBComponents } from '@ckb-lumos/rpc/lib/types/api' 6 | import { Combine, IMesonNetworkMetadata, IMesonToken } from '@mesonfi/base' 7 | 8 | import { Failover, IMesonNetworkClientCommon, IMesonWalletCommon, MesonData } from '../types' 9 | 10 | export interface IMesonCkbNetworkClient extends Combine, CkbRPC> { 11 | 12 | readonly metadata: IMesonNetworkMetadata 13 | readonly tokens: IMesonToken[] 14 | readonly network: typeof config.TESTNET 15 | readonly joyidCodeHash: string 16 | readonly indexer: Indexer 17 | 18 | _detectNetwork(): Promise 19 | 20 | _addressFromPkh(pkh?: string): string 21 | 22 | _prefixFromCodeHash(codeHash: string): string 23 | } 24 | 25 | export type IMesonCkbFailoverNetworkClient = Failover<'ckb', IMesonCkbNetworkClient> 26 | 27 | export interface IMesonCkbWallet extends IMesonWalletCommon<'ckb'> { 28 | } 29 | 30 | export interface IMesonCkbWalletWithExtension extends IMesonWalletCommon<'ckb'> { 31 | readonly ext: MesonData 32 | } 33 | 34 | declare module '../types' { 35 | 36 | interface MesonNetworkClientMap { 37 | ckb: IMesonCkbNetworkClient 38 | } 39 | 40 | interface MesonFailoverNetworkClientMap { 41 | ckb: IMesonCkbFailoverNetworkClient 42 | } 43 | 44 | interface MesonWalletMap { 45 | ckb: IMesonCkbWallet 46 | } 47 | 48 | interface MesonWalletMapWithExtension { 49 | ckb: IMesonCkbWalletWithExtension 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/adaptors/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mesonfi/adaptors", 3 | "version": "1.33.0-rc.8", 4 | "description": "", 5 | "license": "MIT", 6 | "repository": "https://github.com/MesonFi/meson-contracts-solidity", 7 | "main": "lib/index.js", 8 | "module": "es/index.js", 9 | "typings": "lib/index.d.ts", 10 | "scripts": { 11 | "build": "npm run build:clean-dest && npm run build:run", 12 | "build:run": "npm run build:lib && npm run build:es", 13 | "build:clean-dest": "rm -rf lib && rm -rf es", 14 | "build:lib": "tsc --outDir lib", 15 | "build:es": "tsc -m esnext --outDir es", 16 | "prepare": "npm run build", 17 | "test": "tsx test/demo.ts" 18 | }, 19 | "dependencies": { 20 | "@aptos-labs/ts-sdk": "1.35.0", 21 | "@bitcoinerlab/secp256k1": "^1.1.1", 22 | "@ckb-lumos/lumos": "^0.22.2", 23 | "@mysten/sui": "1.21.0", 24 | "@solana/spl-token": "0.3.8", 25 | "@solana/web3.js": "1.87.5", 26 | "@ton/core": "0.56.3", 27 | "@ton/crypto": "3.3.0", 28 | "@ton/ton": "14.0.0", 29 | "bitcoinjs-lib": "^6.1.6", 30 | "bs58": "^4.0.1", 31 | "cross-fetch": "^3.1.5", 32 | "ecpair": "^2.1.0", 33 | "ethers": "5.7.2", 34 | "lodash": "^4.17.21", 35 | "starknet": "7.6.4", 36 | "tonapi-sdk-js": "2.0.3", 37 | "tronweb": "5.2.0", 38 | "tweetnacl": "1.0.3", 39 | "zksync-web3": "0.13.4" 40 | }, 41 | "peerDependencies": { 42 | "@mesonfi/base": "*" 43 | }, 44 | "files": [ 45 | "lib", 46 | "es", 47 | "Readme.md" 48 | ], 49 | "publishConfig": { 50 | "registry": "https://npm.pkg.github.com/" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/base/src/types/MesonSalt.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonSalt 3 | */ 4 | 5 | export interface IMesonSaltHeader { 6 | 7 | // salt & 0x80000000000000000000 == true => will release to an EOA address, otherwise a smart contract; 8 | notToContract: boolean 9 | 10 | // salt & 0x40000000000000000000 == true => will waive *service fee*; 11 | waiveServiceFee: boolean 12 | 13 | // salt & 0x20000000000000000000 == true => meson.to; 14 | isMesonTo: boolean 15 | 16 | // salt & 0x10000000000000000000 == true => API; 17 | isApi: boolean 18 | 19 | // salt & 0x08000000000000000000 == true => use *non-typed signing 20 | // some wallets such as hardware wallets don't support EIP-712v1; 21 | useNonTypedSigning: boolean 22 | 23 | // salt & 0x04000000000000000000 == true => swap for core token (n/a for releasing to contract); 24 | amountForCoreToken: boolean 25 | 26 | // salt & 0x02000000000000000000 == true => share some release amount to partner; 27 | amountToShare: boolean 28 | 29 | // salt & 0x01000000000000000000 == true => use points to waive service fee; 30 | // in reality, the salt header would be 0x4100 31 | usePointsToWaiveServiceFee: boolean 32 | 33 | // salt & 0x00800000000000000000 == true => swap from other platform with reward. 34 | withReward: boolean 35 | 36 | // salt & 0x0010000000000000000 == true => the target chain use new format. 37 | // This is a temporary solution for the current version. Solana and Skale use the old format. 38 | newFormatCoreToken: boolean 39 | 40 | // salt & 0x000f0000000000000000 => the track id from referrer. 41 | trackId: number 42 | } 43 | -------------------------------------------------------------------------------- /packages/adaptors/src/starknet/parse/index.ts: -------------------------------------------------------------------------------- 1 | import { utils } from 'ethers' 2 | import { CallData } from 'starknet' 3 | import v0 from './v0.json' 4 | import v1 from './v1.json' 5 | import execute from './execute.json' 6 | 7 | export default function parse (calldata) { 8 | try { 9 | return parse_v0(calldata) 10 | } catch { 11 | return parse_v1(calldata) 12 | } 13 | } 14 | 15 | const parser_v0 = new CallData(v0) 16 | function parse_v0 (calldata) { 17 | const result = parser_v0.parse('__execute__', calldata) 18 | const { calls, data } = result as { calls: any[]; data: bigint[] } 19 | return calls.map(({ offset, len, ...calldata }) => formatCalldata({ 20 | ...calldata, 21 | data: data.slice(Number(offset), Number(offset) + Number(len)), 22 | })) 23 | } 24 | 25 | const parser_v1 = new CallData(v1) 26 | const parser_execute = new CallData(execute) 27 | function parse_v1 (calldata) { 28 | const result = parser_v1.parse('__execute__', calldata) 29 | return (result as any).calls.map((calldata) => { 30 | try { 31 | const executeData = parser_execute.parse('execute', calldata.data) 32 | const result2 = parser_execute.parse('execute_from_outside_v2', (executeData as any).calldata) 33 | return (result2 as any).outside_execution.calls.map(formatCalldata) 34 | } catch {} 35 | 36 | return formatCalldata(calldata) 37 | }).flat() 38 | } 39 | 40 | function formatCalldata (calldata) { 41 | return { 42 | to: utils.hexZeroPad(calldata.to, 32), 43 | selector: utils.hexZeroPad(calldata.selector, 32), 44 | data: calldata.data.map(d => utils.hexlify(d)), 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/starknet/parse/index.ts: -------------------------------------------------------------------------------- 1 | import { utils } from 'ethers' 2 | import { CallData } from 'starknet' 3 | import v0 from './v0.json' 4 | import v1 from './v1.json' 5 | import execute from './execute.json' 6 | 7 | export default function parse(calldata) { 8 | try { 9 | return parse_v0(calldata) 10 | } catch { 11 | return parse_v1(calldata) 12 | } 13 | } 14 | 15 | const parser_v0 = new CallData(v0) 16 | function parse_v0(calldata) { 17 | const result = parser_v0.parse('__execute__', calldata) 18 | const { calls, data } = result as { calls: any[], data: bigint[] } 19 | return calls.map(({ offset, len, ...calldata }) => formatCalldata({ 20 | ...calldata, 21 | data: data.slice(Number(offset), Number(offset) + Number(len)) 22 | })) 23 | } 24 | 25 | const parser_v1 = new CallData(v1) 26 | const parser_execute = new CallData(execute) 27 | function parse_v1(calldata) { 28 | const result = parser_v1.parse('__execute__', calldata) 29 | return (result as any).calls.map((calldata) => { 30 | try { 31 | const executeData = parser_execute.parse('execute', calldata.data) 32 | const result2 = parser_execute.parse('execute_from_outside_v2', (executeData as any).calldata) 33 | return (result2 as any).outside_execution.calls.map(formatCalldata) 34 | } catch {} 35 | 36 | return formatCalldata(calldata) 37 | }).flat() 38 | } 39 | 40 | function formatCalldata (calldata) { 41 | return { 42 | to: utils.hexZeroPad(calldata.to, 32), 43 | selector: utils.hexZeroPad(calldata.selector, 32), 44 | data: calldata.data.map(d => utils.hexlify(d)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/adaptors/src/sui/type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file type. 3 | */ 4 | import { Combine } from '@mesonfi/base' 5 | import { SuiClient, SuiTransactionBlockResponse } from '@mysten/sui/client' 6 | import { BigNumber } from 'ethers' 7 | import { Failover, IMesonNetworkClientCommon, IMesonWalletCommon, MesonData } from '../types' 8 | 9 | export interface IMesonSuiNetworkClient extends Combine, SuiClient> { 10 | _detectNetwork(): Promise 11 | 12 | _getTokenBalance (addr: string, coinType: string): Promise 13 | 14 | _wrapSuiTx(txRes: SuiTransactionBlockResponse): { 15 | blockHash: string 16 | blockNumber: string 17 | hash: string 18 | from: string 19 | to?: string 20 | value: string 21 | input: string 22 | timestamp: string 23 | status: string 24 | } 25 | } 26 | 27 | export type IMesonSuiFailoverNetworkClient = Failover<'sui', IMesonSuiNetworkClient> 28 | 29 | export interface IMesonSuiWallet extends IMesonWalletCommon<'sui'> { 30 | signMessage(message: string): MesonData 31 | } 32 | 33 | export interface IMesonSuiWalletWithExtension extends IMesonWalletCommon<'sui'> { 34 | readonly ext: MesonData 35 | } 36 | 37 | declare module '../types' { 38 | 39 | interface MesonNetworkClientMap { 40 | sui: IMesonSuiNetworkClient 41 | } 42 | 43 | interface MesonFailoverNetworkClientMap { 44 | sui: IMesonSuiFailoverNetworkClient 45 | } 46 | 47 | interface MesonWalletMap { 48 | sui: IMesonSuiWallet 49 | } 50 | 51 | interface MesonWalletMapWithExtension { 52 | sui: IMesonSuiWalletWithExtension 53 | } 54 | } 55 | 56 | export {} 57 | -------------------------------------------------------------------------------- /packages/sdk/src/Rpc.ts: -------------------------------------------------------------------------------- 1 | import { IAdaptor } from './adaptors/types' 2 | 3 | export type Block = { 4 | hash: string 5 | parentHash: string 6 | number: string 7 | timestamp: string 8 | transactions: Transaction[] 9 | uncles?: string[] 10 | } 11 | 12 | export type Transaction = { 13 | hash: string 14 | from: string 15 | to: string 16 | value: string 17 | input: string 18 | blockHash?: string 19 | blockNumber: string 20 | timestamp: string 21 | } 22 | 23 | export type Receipt = { 24 | status: string 25 | blockNumber: string 26 | [key: string]: any 27 | } 28 | 29 | export class Rpc { 30 | #provider: IAdaptor 31 | 32 | constructor(provider: IAdaptor) { 33 | this.#provider = provider 34 | } 35 | 36 | async getLatestBlock(): Promise { 37 | return await this.#provider.send('eth_getBlockByNumber', ['latest', true]) 38 | } 39 | 40 | async getBlockByNumber(blockNumber: number, withTransactions: boolean = false): Promise { 41 | const hexBlockNumber = `0x${blockNumber.toString(16)}` 42 | return await this.#provider.send('eth_getBlockByNumber', [hexBlockNumber, withTransactions]) 43 | } 44 | 45 | async getBlockByHash(blockHash: string, withTransactions: boolean = false): Promise { 46 | return await this.#provider.send('eth_getBlockByHash', [blockHash, withTransactions]) 47 | } 48 | 49 | async getTransaction(hash: string): Promise { 50 | return await this.#provider.send('eth_getTransactionByHash', [hash]) 51 | } 52 | 53 | async getReceipt(hash: string): Promise { 54 | return await this.#provider.send('eth_getTransactionReceipt', [hash]) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/adaptors/src/MesonAdaptorConfigManager.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonAdaptorManager 3 | */ 4 | 5 | import type { MesonAddressFormat } from '@mesonfi/base' 6 | 7 | import { IMesonAdaptorConfig, WebSocketConstructor } from './types' 8 | 9 | export class MesonAdaptorConfigManager { 10 | 11 | private readonly adaptorConfigs: Partial> = {} 12 | 13 | private WebSocketConstructor: WebSocketConstructor | null = null 14 | 15 | public registerWebSocketConstructor (WebSocketConstructor: WebSocketConstructor): void { 16 | 17 | if (this.WebSocketConstructor) { 18 | throw new Error('WebSocketConstructor already registered') 19 | } 20 | 21 | this.WebSocketConstructor = WebSocketConstructor 22 | } 23 | 24 | public registerAdaptorConfig (addressFormat: T, adaptor: IMesonAdaptorConfig): void { 25 | 26 | if (this.adaptorConfigs[addressFormat]) { 27 | throw new Error(`Adaptor for address format ${addressFormat} already registered`) 28 | } 29 | 30 | this.adaptorConfigs[addressFormat] = adaptor 31 | } 32 | 33 | public getAdaptorConfig (addressFormat: MesonAddressFormat): IMesonAdaptorConfig { 34 | 35 | if (!this.adaptorConfigs[addressFormat]) { 36 | throw new Error(`Adaptor for address format ${addressFormat} not registered`) 37 | } 38 | 39 | return this.adaptorConfigs[addressFormat] as IMesonAdaptorConfig 40 | } 41 | 42 | public getWebSocketConstructor (): WebSocketConstructor | null { 43 | return this.WebSocketConstructor 44 | } 45 | } 46 | 47 | export const adaptorConfigs = new MesonAdaptorConfigManager() 48 | -------------------------------------------------------------------------------- /contracts/test/ForwardTokenContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | import "../interfaces/IERC20Minimal.sol"; 5 | import "../interfaces/IDepositWithBeneficiary.sol"; 6 | 7 | /// @notice A sample of 3rd-party dapp that interacts with meson 8 | /// With `depositWithBeneficiary`, the meson contract will be able 9 | /// to deposit cross-chain'ed stablecoins to the 3rd-party dapp contract 10 | /// on behalf of the user. The user will receive the benefits corresponding 11 | /// to this deposit. 12 | contract ForwardTokenContract is IDepositWithBeneficiary { 13 | function depositWithBeneficiary( 14 | address token, 15 | uint256 amount, 16 | address beneficiary, 17 | uint64 18 | ) payable external override returns (bool) { 19 | if (token == address(0)) { 20 | // ETH 21 | // No need to take ETH since it is transferred in msg.value 22 | } else { 23 | // Stablecoins 24 | // Required. Take cross-chain'ed token to dapp's contract 25 | IERC20Minimal(token).transferFrom(msg.sender, address(this), amount); 26 | } 27 | 28 | // The dapp can do it's own logic with depositing tokens 29 | // e.g. exchange for other tokens, mint NFTs, etc. 30 | // Could use data to determine specific operations. 31 | 32 | 33 | // Send benefits to the user. Here as an example we just transfer 34 | // deposited tokens to the user. 35 | if (token == address(0)) { 36 | // ETH 37 | (bool success, ) = beneficiary.call{value: amount}(""); 38 | require(success, "Transfer failed"); 39 | } else { 40 | // Stablecoins 41 | IERC20Minimal(token).transfer(beneficiary, amount); 42 | } 43 | 44 | return true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /scripts/lib/CustomGasFeeProviderWrapper.js: -------------------------------------------------------------------------------- 1 | const { EthersProviderWrapper } = require('@nomiclabs/hardhat-ethers/internal/ethers-provider-wrapper') 2 | 3 | module.exports = class CustomGasFeeProviderWrapper extends EthersProviderWrapper { 4 | async getFeeData() { 5 | const feeData = await this._checkEip1559() || { gasPrice: await this.getGasPrice() } 6 | return feeData 7 | } 8 | 9 | _eip1559FeeData = undefined 10 | async _checkEip1559 () { 11 | if (typeof this._eip1559FeeData !== 'undefined') { 12 | return this._eip1559FeeData 13 | } 14 | 15 | const block = await this.getBlockWithTransactions('latest') 16 | const transactions = [...block.transactions] 17 | let offset = 0 18 | while (transactions.length < 20) { 19 | offset++ 20 | transactions.push(...(await this.getBlockWithTransactions(block.number - offset)).transactions) 21 | if (offset > 5) { 22 | break 23 | } 24 | } 25 | const eip1559Transactions = transactions.filter(tx => tx.maxFeePerGas && tx.maxPriorityFeePerGas) 26 | 27 | setTimeout(() => this._eip1559FeeData = undefined, 60_000) 28 | 29 | if (!transactions.length || eip1559Transactions.length / transactions.length < 0.5) { 30 | this._eip1559FeeData = null 31 | return 32 | } 33 | 34 | const sorted = eip1559Transactions.sort((tx1, tx2) => tx1.maxFeePerGas.lt(tx2.maxFeePerGas) ? -1 : 1) 35 | const index = Math.floor(sorted.length * 0.5) 36 | const { gasPrice, maxFeePerGas, maxPriorityFeePerGas } = sorted[index] 37 | this._eip1559FeeData = { gasPrice, maxFeePerGas, maxPriorityFeePerGas } 38 | 39 | return this._eip1559FeeData 40 | } 41 | 42 | async estimateGas(transaction) { 43 | return await super.estimateGas(transaction) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mesonfi/sdk", 3 | "version": "1.32.0-rc.7", 4 | "description": "", 5 | "license": "MIT", 6 | "repository": "https://github.com/MesonFi/meson-contracts-solidity", 7 | "main": "lib/index.js", 8 | "types": "lib/index.d.ts", 9 | "publishConfig": { 10 | "registry": "https://npm.pkg.github.com/" 11 | }, 12 | "files": [ 13 | "lib", 14 | "tsconfig.json" 15 | ], 16 | "scripts": { 17 | "test": "mocha -r ts-node/register 'tests/**/*.spec.ts'", 18 | "build": "tsc", 19 | "prepare": "yarn build" 20 | }, 21 | "peerDependencies": { 22 | "@mesonfi/base": "*" 23 | }, 24 | "dependencies": { 25 | "@aptos-labs/ts-sdk": "1.35.0", 26 | "@bitcoinerlab/secp256k1": "^1.1.1", 27 | "@ckb-lumos/lumos": "^0.22.2", 28 | "@mysten/sui": "1.21.0", 29 | "@solana/spl-token": "0.3.8", 30 | "@solana/web3.js": "1.87.5", 31 | "@ton/core": "0.56.3", 32 | "@ton/crypto": "3.3.0", 33 | "@ton/ton": "14.0.0", 34 | "bitcoinjs-lib": "^6.1.6", 35 | "bs58": "^4.0.1", 36 | "cross-fetch": "^3.1.5", 37 | "ecpair": "^2.1.0", 38 | "ethers": "5.7.2", 39 | "lodash": "^4.17.21", 40 | "starknet": "7.6.4", 41 | "tonapi-sdk-js": "2.0.3", 42 | "tronweb": "5.2.0", 43 | "tweetnacl": "1.0.3", 44 | "zksync-web3": "0.13.4" 45 | }, 46 | "devDependencies": { 47 | "@types/chai": "^4.3.3", 48 | "@types/chai-as-promised": "^7.1.5", 49 | "@types/lodash": "^4.14.186", 50 | "@types/mocha": "^9.1.1", 51 | "@types/node": "^20.9.0", 52 | "abi-wan-kanabi": "^2.1.0", 53 | "chai": "^4.3.6", 54 | "chai-as-promised": "^7.1.1", 55 | "ethereum-waffle": "^4.0.4", 56 | "mocha": "^10.0.0", 57 | "ts-node": "^10.9.1", 58 | "typescript": "^5.4.5" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /scripts/config/set-chain-config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs') 3 | 4 | const mainnetsPath = path.join(__dirname, '../../packages/base/networks/mainnets.json') 5 | const testnetsPath = path.join(__dirname, '../../packages/base/networks/testnets.json') 6 | 7 | const testnets = require(testnetsPath); 8 | const presets = require(mainnetsPath); 9 | 10 | module.exports = async function setChainConfig(networkId, testnetMode) { 11 | if (!networkId) { 12 | throw new Error(`No networkId specified`) 13 | } 14 | 15 | const template = await fs.promises.readFile( 16 | path.join(__dirname, 'MesonConfig.sol'), 17 | 'utf8' 18 | ) 19 | 20 | let network 21 | if (networkId === 'local') { 22 | network = { name: 'Local', shortSlip44: '0x0001' } 23 | } else if (testnetMode) { 24 | network = testnets.find(item => item.id.startsWith(networkId)) 25 | } else { 26 | network = presets.find(item => item.id.startsWith(networkId)) 27 | } 28 | if (!network) { 29 | throw new Error(`Invalid network: ${networkId}`) 30 | } 31 | 32 | console.log(`Switch chain config to: ${networkId} ${testnetMode ? 'testnet' : 'mainnet'}`) 33 | 34 | let config = template 35 | .replace('CONFIG_PROTOCOL_VERSION', 1) 36 | .replace('CONFIG_BLOCKCHAIN_NAME', `${network.name}`) 37 | .replace('CONFIG_COIN_TYPE', network.shortSlip44) 38 | 39 | if (network.shortSlip44 === '0x003c') { 40 | config = config.replace('CONFIG_LOCK_TIME', '40 minutes') 41 | } else { 42 | config = config.replace('CONFIG_LOCK_TIME', '20 minutes') 43 | } 44 | 45 | config = config.replace(/CONFIG_TESTNET_MODE/g, testnetMode ? ' (Testnet)' : '') 46 | 47 | await fs.promises.writeFile( 48 | path.join(__dirname, '../../contracts/utils/MesonConfig.sol'), 49 | config 50 | ) 51 | 52 | return network 53 | } 54 | -------------------------------------------------------------------------------- /scripts/config/MesonConfig.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | /// @notice Parameters of the Meson contract 5 | /// for CONFIG_BLOCKCHAIN_NAME 6 | contract MesonConfig { 7 | uint8 constant MESON_PROTOCOL_VERSION = CONFIG_PROTOCOL_VERSION; 8 | 9 | // Ref https://github.com/satoshilabs/slips/blob/master/slip-0044.md 10 | uint16 constant SHORT_COIN_TYPE = CONFIG_COIN_TYPE; 11 | 12 | uint256 constant MAX_SWAP_AMOUNT = 1e11; // 100,000.000000 = 100k 13 | uint256 constant SERVICE_FEE_RATE = 5; // service fee = 5 / 10000 = 0.05% 14 | uint256 constant SERVICE_FEE_MINIMUM = 500_000; // min $0.5 15 | uint256 constant SERVICE_FEE_MINIMUM_ETH = 500; // min 0.0005 ETH (or SOL) 16 | uint256 constant SERVICE_FEE_MINIMUM_BNB = 5000; // min 0.005 BNB 17 | uint256 constant SERVICE_FEE_MINIMUM_BTC = 10; // min 0.00001 BTC 18 | 19 | uint256 constant MIN_BOND_TIME_PERIOD = 1 hours; 20 | uint256 constant MAX_BOND_TIME_PERIOD = 2 hours; 21 | uint256 constant LOCK_TIME_PERIOD = CONFIG_LOCK_TIME; 22 | 23 | bytes28 constant ETH_SIGN_HEADER = bytes28("\x19Ethereum Signed Message:\n32"); 24 | bytes28 constant ETH_SIGN_HEADER_52 = bytes28("\x19Ethereum Signed Message:\n52"); 25 | bytes25 constant TRON_SIGN_HEADER = bytes25("\x19TRON Signed Message:\n32\n"); 26 | bytes25 constant TRON_SIGN_HEADER_33 = bytes25("\x19TRON Signed Message:\n33\n"); 27 | bytes25 constant TRON_SIGN_HEADER_53 = bytes25("\x19TRON Signed Message:\n53\n"); 28 | 29 | bytes32 constant REQUEST_TYPE_HASH = keccak256("bytes32 Sign to request a swap on MesonCONFIG_TESTNET_MODE"); 30 | bytes32 constant RELEASE_TYPE_HASH = keccak256("bytes32 Sign to release a swap on MesonCONFIG_TESTNET_MODEaddress Recipient"); 31 | 32 | bytes32 constant RELEASE_TO_TRON_TYPE_HASH = keccak256("bytes32 Sign to release a swap on MesonCONFIG_TESTNET_MODEaddress Recipient (tron address in hex format)"); 33 | } 34 | -------------------------------------------------------------------------------- /packages/rpc/src/MesonRpcStatusCache.ts: -------------------------------------------------------------------------------- 1 | import { MesonNetworkStatus } from './types' 2 | 3 | export class MesonRpcStatusCache { 4 | 5 | protected ready = false 6 | 7 | protected readonly cache = new Map() 8 | 9 | protected readonly pending: VoidFunction[] = [] 10 | 11 | public get isReady (): boolean { 12 | return this.ready 13 | } 14 | 15 | public waitForReady (): Promise { 16 | return new Promise((resolve) => { 17 | if (this.isReady) { 18 | resolve() 19 | } else { 20 | this.pending.push(resolve) 21 | } 22 | }) 23 | } 24 | 25 | public isUrlHealthy (networkId: string, url: string): boolean { 26 | const rpcStatusList = this.cache.get(networkId) || [] 27 | return Boolean(rpcStatusList.find(status => status.url === url)?.healthy) 28 | } 29 | 30 | public hasHealthyRpc (networkId: string): boolean { 31 | return this.getHealthyRpcStatus(networkId).length > 0 32 | } 33 | 34 | public getHealthyRpcStatus (networkId: string): MesonNetworkStatus[] { 35 | return (this.cache.get(networkId) || []) 36 | .filter(rpc => rpc.healthy) 37 | .filter(rpc => rpc.url) 38 | } 39 | 40 | public getAllHealthyRpcStatus (): Record { 41 | const result = new Map() 42 | 43 | for (const networkId of this.cache.keys()) { 44 | result.set(networkId, this.getHealthyRpcStatus(networkId)) 45 | } 46 | 47 | return Object.fromEntries(result) 48 | } 49 | 50 | protected update (networkId: string, rpcStatusList: MesonNetworkStatus[]) { 51 | this.cache.set(networkId, rpcStatusList) 52 | } 53 | 54 | protected setReady () { 55 | if (this.ready) { 56 | return 57 | } 58 | this.ready = true 59 | for (const resolve of this.pending) { 60 | resolve() 61 | } 62 | this.pending.length = 0 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /scripts/deploy.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat') 2 | const { adaptors } = require('@mesonfi/sdk') 3 | const { getAdaptor } = require('./lib/getAdaptor') 4 | const { deployMeson, deployContract } = require('./lib/deploy') 5 | const { deposit } = require('./lib/pool') 6 | const updatePresets = require('./lib/updatePresets') 7 | 8 | require('dotenv').config() 9 | 10 | const { 11 | PRIVATE_KEY, 12 | PREMIUM_MANAGER, 13 | DEPOSIT_ON_DEPLOY, 14 | } = process.env 15 | 16 | module.exports = async function deploy(network, upgradable, testnetMode) { 17 | const adaptor = getAdaptor(network) 18 | await hre.run('compile') 19 | 20 | if (upgradable && network.id.startsWith('skale')) { 21 | upgradable = 2 // deploy Proxy2ToMeson 22 | } 23 | 24 | const wallet = adaptors.getWallet(PRIVATE_KEY, adaptor) 25 | const tokens = network.tokens 26 | 27 | if (testnetMode) { // only for testnets 28 | for (const token of tokens) { 29 | if (token.addr) { 30 | continue 31 | } 32 | 33 | console.log(`Deploying ${token.name}...`) 34 | const totalSupply = ethers.utils.parseUnits('100000000', token.decimals) 35 | const args = [token.name, token.symbol, totalSupply.toString(), token.decimals] 36 | const tokenContract = await deployContract('MockToken', wallet, args) 37 | token.addr = tokenContract.address 38 | } 39 | } 40 | 41 | const meson = await deployMeson(wallet, upgradable, PREMIUM_MANAGER, tokens) 42 | network.mesonAddress = meson.address 43 | 44 | const shortCoinType = await meson.getShortCoinType() 45 | if (shortCoinType !== network.shortSlip44) { 46 | throw new Error('Coin type does not match') 47 | } 48 | 49 | if (testnetMode && DEPOSIT_ON_DEPLOY) { // only for testnets 50 | for (const token of tokens) { 51 | await deposit(token.tokenIndex, DEPOSIT_ON_DEPLOY, { network, wallet }) 52 | } 53 | } 54 | 55 | network.tokens = tokens 56 | updatePresets(network) 57 | } 58 | -------------------------------------------------------------------------------- /packages/base/src/utils/salt.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file formatSaltHeader 3 | */ 4 | 5 | import { IMesonSaltHeader } from '../types' 6 | 7 | const getKeys = Object.keys as (obj: T) => (keyof T)[] 8 | 9 | const MESONFI_SALT_HEADER_DATA: Record, number> = { 10 | notToContract: 0x8000, 11 | waiveServiceFee: 0x4000, 12 | isMesonTo: 0x2000, 13 | isApi: 0x1000, 14 | useNonTypedSigning: 0x0800, 15 | amountForCoreToken: 0x0400, 16 | amountToShare: 0x0200, 17 | usePointsToWaiveServiceFee: 0x0100, 18 | withReward: 0x0080, 19 | newFormatCoreToken: 0x0010, 20 | } 21 | 22 | export function formatSaltHeader (data: IMesonSaltHeader): string { 23 | const { trackId } = data 24 | 25 | let salt = 0 26 | 27 | getKeys(MESONFI_SALT_HEADER_DATA).forEach(key => { 28 | if (data[key]) { 29 | salt |= MESONFI_SALT_HEADER_DATA[key] 30 | } 31 | }) 32 | 33 | salt |= trackId 34 | 35 | return '0x' + salt.toString(16).padStart(4, '0') 36 | } 37 | 38 | export function parseSaltHeader (saltHeader: string): IMesonSaltHeader { 39 | const saltNumber = parseInt(saltHeader.slice(2, 6), 16) 40 | 41 | return { 42 | notToContract: !!(saltNumber & MESONFI_SALT_HEADER_DATA.notToContract), 43 | waiveServiceFee: !!(saltNumber & MESONFI_SALT_HEADER_DATA.waiveServiceFee), 44 | isMesonTo: !!(saltNumber & MESONFI_SALT_HEADER_DATA.isMesonTo), 45 | isApi: !!(saltNumber & MESONFI_SALT_HEADER_DATA.isApi), 46 | useNonTypedSigning: !!(saltNumber & MESONFI_SALT_HEADER_DATA.useNonTypedSigning), 47 | amountForCoreToken: !!(saltNumber & MESONFI_SALT_HEADER_DATA.amountForCoreToken), 48 | amountToShare: !!(saltNumber & MESONFI_SALT_HEADER_DATA.amountToShare), 49 | usePointsToWaiveServiceFee: !!(saltNumber & MESONFI_SALT_HEADER_DATA.usePointsToWaiveServiceFee), 50 | withReward: !!(saltNumber & MESONFI_SALT_HEADER_DATA.withReward), 51 | newFormatCoreToken: !!(saltNumber & MESONFI_SALT_HEADER_DATA.newFormatCoreToken), 52 | trackId: saltNumber & 0x000f, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/ethers/extendProvider.ts: -------------------------------------------------------------------------------- 1 | import { providers, errors } from 'ethers' 2 | 3 | import type { IAdaptor, WrappedTransaction } from '../types' 4 | 5 | export type ProviderConstructor = new (...args: any) => providers.StaticJsonRpcProvider 6 | 7 | export default function extendProvider(Provider: ClassProvider) { 8 | return class ProviderAdaptor extends Provider implements IAdaptor { 9 | #client: providers.StaticJsonRpcProvider | any 10 | 11 | readonly #url: string 12 | 13 | constructor(...args: any[]) { 14 | const client: providers.StaticJsonRpcProvider = args[0] 15 | const url = client.connection.url 16 | super({ 17 | url, 18 | timeout: 10_000, 19 | throttleLimit: 3, 20 | throttleCallback: async (attempt: number, url: string) => { 21 | console.log(`[429]`, url, attempt) 22 | return true 23 | } 24 | }, client.network) 25 | 26 | this.#client = client 27 | this.#url = url 28 | } 29 | 30 | get client() { 31 | return this.#client 32 | } 33 | 34 | protected set client(c) { 35 | this.#client = c 36 | } 37 | 38 | get nodeUrl() { 39 | return this.#url 40 | } 41 | 42 | async sendTransaction(signedTransaction: string | Promise): Promise { 43 | return new Promise((resolve, reject) => { 44 | const h = setTimeout(() => { 45 | console.log('tx_timeout') 46 | reject(new Error('Time out')) 47 | }, 10_000) 48 | 49 | super.sendTransaction(signedTransaction).then(res => { 50 | clearTimeout(h) 51 | resolve(res) 52 | }).catch(reject) 53 | }) 54 | } 55 | 56 | async perform(method, params) { 57 | try { 58 | return await super.perform(method, params) 59 | } catch (e) { 60 | if (e.code === errors.CALL_EXCEPTION) { 61 | e.code = errors.SERVER_ERROR 62 | } 63 | throw e 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /templates/contract.hbs: -------------------------------------------------------------------------------- 1 | # {{{natspec.title}}} 2 | {{{natspec.userdoc}}} 3 | {{{natspec.devdoc}}} 4 | 5 | {{#if ownFunctions}} 6 | ## Functions 7 | {{/if}} 8 | {{#ownFunctions}} 9 | ### {{name}} 10 | ```solidity 11 | function {{name}}( 12 | {{#natspec.params}} 13 | {{#lookup ../args.types @index}}{{/lookup}} {{param}}{{#if @last}}{{else}},{{/if}} 14 | {{/natspec.params}} 15 | ) {{visibility}}{{#if outputs}} returns ({{outputs}}){{/if}} 16 | ``` 17 | {{#if natspec.userdoc}}{{natspec.userdoc}}{{/if}} 18 | {{#if natspec.devdoc}}{{natspec.devdoc}}{{/if}} 19 | {{#if natspec.params}} 20 | #### Parameters: 21 | | Name | Type | Description | 22 | | :--- | :--- | :------------------------------------------------------------------- | 23 | {{#natspec.params}} 24 | |`{{param}}` | {{#lookup ../args.types @index}}{{/lookup}} | {{ description }}{{/natspec.params}}{{/if}} 25 | {{#if natspec.returns}} 26 | #### Return Values: 27 | | Name | Type | Description | 28 | | :----------------------------- | :------------ | :--------------------------------------------------------------------------- | 29 | {{#natspec.returns}} 30 | |`{{param}}`| {{#lookup ../args.types @index}}{{/lookup}} | {{{description}}}{{/natspec.returns}}{{/if}} 31 | 32 | {{/ownFunctions}} 33 | {{#if ownEvents}} 34 | ## Events 35 | {{/if}} 36 | {{#ownEvents}} 37 | ### {{name}} 38 | ```solidity 39 | event {{name}}( 40 | {{#natspec.params}} 41 | {{#lookup ../args.types @index}}{{/lookup}} {{param}}{{#if @last}}{{else}},{{/if}} 42 | {{/natspec.params}} 43 | ) 44 | ``` 45 | {{#if natspec.userdoc}}{{natspec.userdoc}}{{/if}} 46 | {{#if natspec.devdoc}}{{natspec.devdoc}}{{/if}} 47 | {{#if natspec.params}} 48 | #### Parameters: 49 | | Name | Type | Description | 50 | | :----------------------------- | :------------ | :--------------------------------------------- | 51 | {{#natspec.params}} 52 | |`{{param}}`| {{#lookup ../args.types @index}}{{/lookup}} | {{{description}}}{{/natspec.params}}{{/if}} 53 | {{/ownEvents}} -------------------------------------------------------------------------------- /packages/sdk/tests/SwapWithSigner.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { MockProvider } from 'ethereum-waffle' 3 | import { Wallet } from 'ethers' 4 | 5 | import { SwapWithSigner, EthersWalletSwapSigner } from '../src' 6 | import { signedSwapRequestData, signedSwapReleaseData } from './shared' 7 | 8 | describe('SwapWithSigner', () => { 9 | let swapWithSigner: SwapWithSigner 10 | let initiator: Wallet 11 | 12 | beforeEach('create SwapWithSigner', () => { 13 | const wallets = new MockProvider().getWallets() 14 | initiator = wallets[1] 15 | const swapSigner = new EthersWalletSwapSigner(initiator) 16 | const swap = SwapWithSigner.decode(signedSwapRequestData.encoded) 17 | swapWithSigner = new SwapWithSigner(swap, swapSigner) 18 | }) 19 | 20 | describe('#signForRequest', () => { 21 | it('signs a swap request for testnet', async () => { 22 | const signedSwapRequest = await swapWithSigner.signForRequest(true) 23 | expect(signedSwapRequest.initiator).to.equal(initiator.address) 24 | expect(signedSwapRequest.signature).to.deep.equal(signedSwapRequestData.signature) 25 | }) 26 | it('signs a swap request for mainnet', async () => { 27 | const signedSwapRequest = await swapWithSigner.signForRequest(false) 28 | expect(signedSwapRequest.initiator).to.equal(initiator.address) 29 | expect(signedSwapRequest.signature).to.deep.equal(signedSwapRequestData.mainnetSignature) 30 | }) 31 | }) 32 | 33 | describe('#signForRelease', () => { 34 | it('signs a swap release for testnet', async () => { 35 | const signedSwapRelease = await swapWithSigner.signForRelease(signedSwapReleaseData.recipient, true) 36 | expect(signedSwapRelease.initiator).to.equal(initiator.address) 37 | expect(signedSwapRelease.recipient).to.equal(signedSwapReleaseData.recipient) 38 | expect(signedSwapRelease.signature).to.deep.equal(signedSwapReleaseData.signature) 39 | }) 40 | it('signs a swap release for mainnet', async () => { 41 | const signedSwapRelease = await swapWithSigner.signForRelease(signedSwapReleaseData.recipient, false) 42 | expect(signedSwapRelease.initiator).to.equal(initiator.address) 43 | expect(signedSwapRelease.recipient).to.equal(signedSwapReleaseData.recipient) 44 | expect(signedSwapRelease.signature).to.deep.equal(signedSwapReleaseData.mainnetSignature) 45 | }) 46 | }) 47 | }) 48 | -------------------------------------------------------------------------------- /packages/adaptors/src/tron/wallet.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file wallet 3 | */ 4 | import TronWeb from 'tronweb' 5 | import { MesonData } from '../types' 6 | import { IMesonTronFailoverNetworkClient, IMesonTronWallet } from './type' 7 | 8 | export class TronWallet implements IMesonTronWallet { 9 | 10 | public static fromExtension (ext: MesonData, client: IMesonTronFailoverNetworkClient): TronWallet { 11 | return new TronWallet(client, ext.signer) 12 | } 13 | 14 | public static fromPrivateKey (privateKey: string, client: IMesonTronFailoverNetworkClient): TronWallet { 15 | if (privateKey.startsWith('0x')) { 16 | privateKey = privateKey.substring(2) 17 | } 18 | const injectedAdaptor = new TronWeb({ fullHost: client.fullNode.host, privateKey }) 19 | 20 | return new TronWallet(client, injectedAdaptor) 21 | } 22 | 23 | public readonly networkClient: IMesonTronFailoverNetworkClient 24 | 25 | public readonly tronWeb: MesonData 26 | 27 | public readonly addressFormat = 'tron' 28 | 29 | constructor (client: IMesonTronFailoverNetworkClient, tronWeb: MesonData) { 30 | this.networkClient = client 31 | this.tronWeb = tronWeb 32 | } 33 | 34 | get address () { 35 | return this.tronWeb.defaultAddress.base58 36 | } 37 | 38 | async transfer ({ to, value }) { 39 | const tx = await this.tronWeb.transactionBuilder.sendTrx(to, value.toString()) 40 | const signed = await this.tronWeb.trx.sign(tx) 41 | const receipt = await this.tronWeb.trx.sendRawTransaction(signed) 42 | return { 43 | hash: receipt.txID, 44 | wait: (confirmations: number) => this.networkClient.waitForTransaction(receipt.txID, confirmations), 45 | } 46 | } 47 | 48 | async sendTransaction (payload, overrides) { 49 | if (!payload.contract) { 50 | return await this.transfer(payload) 51 | } 52 | const { contract, method, args } = payload 53 | const hash = await contract[method](...args).send(overrides) 54 | return { 55 | hash, 56 | wait: (confirmations: number) => this.networkClient.waitForTransaction(hash, confirmations), 57 | } 58 | } 59 | 60 | async getTransaction (hash: string): Promise { 61 | while (true) { 62 | try { 63 | return await this.networkClient.send('eth_getTransactionByHash', [hash]) 64 | } catch { 65 | await new Promise(resolve => setTimeout(resolve, 1000)) 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /packages/base/src/meson/MesonToken.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonToken 3 | */ 4 | 5 | import { ADDRESS_ONE } from '../const' 6 | import { IMesonToken, IMesonTokenData } from '../types' 7 | import { getTokenCategory, getTokenType } from '../utils' 8 | import type { MesonNetwork } from './MesonNetwork' 9 | 10 | export class MesonToken implements IMesonToken { 11 | 12 | public static create (network: MesonNetwork, data: IMesonTokenData): MesonToken { 13 | return new MesonToken(network, data) 14 | } 15 | 16 | protected readonly network: MesonNetwork 17 | 18 | protected readonly data: IMesonTokenData 19 | 20 | protected constructor (network: MesonNetwork, data: IMesonTokenData) { 21 | this.data = data 22 | this.network = network 23 | } 24 | 25 | public get tokenIndex (): number { 26 | return this.data.tokenIndex 27 | } 28 | 29 | public get symbol (): string { 30 | return this.data.symbol 31 | } 32 | 33 | public get name (): string { 34 | return this.data.name 35 | } 36 | 37 | public get icon (): string { 38 | if (this.data.icon) { 39 | return this.data.icon 40 | } 41 | 42 | if (this.tokenIndex === 191) { 43 | return this.network.networkId 44 | } 45 | 46 | return this.category 47 | } 48 | 49 | public get addr (): string { 50 | return this.data.addr 51 | } 52 | 53 | public get decimals (): number { 54 | return this.data.decimals 55 | } 56 | 57 | public get link (): string | undefined { 58 | return this.data.link 59 | } 60 | 61 | public get type (): string { 62 | return getTokenType(this.tokenIndex) 63 | } 64 | 65 | public get category (): string { 66 | if (this.tokenIndex === 191) { 67 | return `core-token-${this.network.networkId}` 68 | } 69 | 70 | return getTokenCategory(this.tokenIndex) 71 | } 72 | 73 | public get disabled (): boolean { 74 | return this.data.disabled ?? false 75 | } 76 | 77 | public get isCoreToken (): boolean { 78 | return this.addr === ADDRESS_ONE 79 | } 80 | 81 | public getTokenLink () { 82 | if (this.isCoreToken) { 83 | return `${this.network.explorer}` 84 | } 85 | 86 | if (this.link) { 87 | return `${this.network.explorer}/${this.link}` 88 | } 89 | 90 | return `${this.network.explorer}/token/${this.addr}` 91 | } 92 | 93 | public getAddressLink () { 94 | return `${this.network.explorer}/address/${this.addr}` 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /packages/adaptors/src/starknet/parse/execute.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "execute", 5 | "outputs": [ 6 | { 7 | "name": "account_address", 8 | "type": "core::starknet::contract_address::ContractAddress" 9 | }, 10 | { 11 | "name": "entrypoint", 12 | "type": "core::felt252" 13 | }, 14 | { 15 | "name": "calldata", 16 | "type": "core::array::Array::" 17 | }, 18 | { 19 | "name": "gas_token_address", 20 | "type": "core::starknet::contract_address::ContractAddress" 21 | }, 22 | { 23 | "name": "gas_amount", 24 | "type": "core::integer::u256" 25 | } 26 | ], 27 | "inputs": [ 28 | { 29 | "type": "core::bool" 30 | } 31 | ], 32 | "state_mutability": "external" 33 | }, 34 | { 35 | "type": "function", 36 | "name": "execute_from_outside_v2", 37 | "outputs": [ 38 | { 39 | "name": "outside_execution", 40 | "type": "argent::outside_execution::interface::OutsideExecution" 41 | }, 42 | { 43 | "name": "signature", 44 | "type": "core::array::Span::" 45 | } 46 | ], 47 | "state_mutability": "external" 48 | }, 49 | { 50 | "type": "struct", 51 | "name": "argent::outside_execution::interface::OutsideExecution", 52 | "members": [ 53 | { 54 | "name": "caller", 55 | "type": "core::starknet::contract_address::ContractAddress" 56 | }, 57 | { 58 | "name": "nonce", 59 | "type": "core::felt252" 60 | }, 61 | { 62 | "name": "execute_after", 63 | "type": "core::integer::u64" 64 | }, 65 | { 66 | "name": "execute_before", 67 | "type": "core::integer::u64" 68 | }, 69 | { 70 | "name": "calls", 71 | "type": "core::array::Span::" 72 | } 73 | ] 74 | }, 75 | { 76 | "type": "struct", 77 | "name": "core::starknet::account::Call", 78 | "members": [ 79 | { 80 | "name": "to", 81 | "type": "core::starknet::contract_address::ContractAddress" 82 | }, 83 | { 84 | "name": "selector", 85 | "type": "core::felt252" 86 | }, 87 | { 88 | "name": "data", 89 | "type": "core::array::Span::" 90 | } 91 | ] 92 | } 93 | ] -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/starknet/parse/execute.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "execute", 5 | "outputs": [ 6 | { 7 | "name": "account_address", 8 | "type": "core::starknet::contract_address::ContractAddress" 9 | }, 10 | { 11 | "name": "entrypoint", 12 | "type": "core::felt252" 13 | }, 14 | { 15 | "name": "calldata", 16 | "type": "core::array::Array::" 17 | }, 18 | { 19 | "name": "gas_token_address", 20 | "type": "core::starknet::contract_address::ContractAddress" 21 | }, 22 | { 23 | "name": "gas_amount", 24 | "type": "core::integer::u256" 25 | } 26 | ], 27 | "inputs": [ 28 | { 29 | "type": "core::bool" 30 | } 31 | ], 32 | "state_mutability": "external" 33 | }, 34 | { 35 | "type": "function", 36 | "name": "execute_from_outside_v2", 37 | "outputs": [ 38 | { 39 | "name": "outside_execution", 40 | "type": "argent::outside_execution::interface::OutsideExecution" 41 | }, 42 | { 43 | "name": "signature", 44 | "type": "core::array::Span::" 45 | } 46 | ], 47 | "state_mutability": "external" 48 | }, 49 | { 50 | "type": "struct", 51 | "name": "argent::outside_execution::interface::OutsideExecution", 52 | "members": [ 53 | { 54 | "name": "caller", 55 | "type": "core::starknet::contract_address::ContractAddress" 56 | }, 57 | { 58 | "name": "nonce", 59 | "type": "core::felt252" 60 | }, 61 | { 62 | "name": "execute_after", 63 | "type": "core::integer::u64" 64 | }, 65 | { 66 | "name": "execute_before", 67 | "type": "core::integer::u64" 68 | }, 69 | { 70 | "name": "calls", 71 | "type": "core::array::Span::" 72 | } 73 | ] 74 | }, 75 | { 76 | "type": "struct", 77 | "name": "core::starknet::account::Call", 78 | "members": [ 79 | { 80 | "name": "to", 81 | "type": "core::starknet::contract_address::ContractAddress" 82 | }, 83 | { 84 | "name": "selector", 85 | "type": "core::felt252" 86 | }, 87 | { 88 | "name": "data", 89 | "type": "core::array::Span::" 90 | } 91 | ] 92 | } 93 | ] -------------------------------------------------------------------------------- /packages/presets/src/CustomFeeProvider.ts: -------------------------------------------------------------------------------- 1 | import { providers, BigNumber, utils } from 'ethers' 2 | 3 | export const CustomFeeHttpProvider = extendProvider(providers.StaticJsonRpcProvider) as typeof providers.StaticJsonRpcProvider 4 | export const CustomFeeWsProvider = extendProvider(providers.WebSocketProvider) as typeof providers.WebSocketProvider 5 | 6 | type Class = new (...args: any[]) => T 7 | function extendProvider(Provider: Class) { 8 | class CustomFeeProvider extends Provider { 9 | override async estimateGas(transaction: utils.Deferrable): Promise { 10 | const gasLimit = await super.estimateGas(transaction) 11 | // TODO: logger.debug('Transaction', `estimate gas success`, { estimateGas: gasLimit.toString() }) 12 | // TODO: log errors 13 | return gasLimit.mul(1.2 * 100).div(100) 14 | } 15 | 16 | override async getFeeData(): Promise { 17 | const feeData = await this._checkEip1559() || { gasPrice: await this.getGasPrice() } 18 | return feeData 19 | } 20 | 21 | #eip1559FeeData = undefined 22 | async _checkEip1559 () { 23 | if (typeof this.#eip1559FeeData !== 'undefined') { 24 | return this.#eip1559FeeData 25 | } 26 | 27 | const block = await this.getBlockWithTransactions('latest') 28 | const transactions = [...block.transactions] 29 | let offset = 0 30 | while (transactions.length < 20) { 31 | offset++ 32 | transactions.push(...(await this.getBlockWithTransactions(block.number - offset)).transactions) 33 | if (offset > 5) { 34 | break 35 | } 36 | } 37 | const eip1559Transactions = transactions.filter(tx => tx.maxFeePerGas && tx.maxPriorityFeePerGas) 38 | 39 | setTimeout(() => this.#eip1559FeeData = undefined, 60_000) 40 | 41 | if (!transactions.length || eip1559Transactions.length / transactions.length < 0.5) { 42 | this.#eip1559FeeData = null 43 | return 44 | } 45 | 46 | const sorted = eip1559Transactions.sort((tx1, tx2) => tx1.maxFeePerGas.lt(tx2.maxFeePerGas) ? -1 : 1) 47 | const index = Math.floor(sorted.length * 0.5) 48 | const { gasPrice, maxFeePerGas, maxPriorityFeePerGas } = sorted[index] 49 | this.#eip1559FeeData = { gasPrice, maxFeePerGas, maxPriorityFeePerGas } 50 | 51 | return this.#eip1559FeeData 52 | } 53 | } 54 | return CustomFeeProvider as unknown 55 | } 56 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/aptos/AptosWallet.ts: -------------------------------------------------------------------------------- 1 | import { utils } from 'ethers' 2 | import { Account as AptosAccount } from '@aptos-labs/ts-sdk' 3 | import AptosAdaptor from './AptosAdaptor' 4 | 5 | export default class AptosWallet extends AptosAdaptor { 6 | readonly account: AptosAccount 7 | 8 | constructor(adaptor: AptosAdaptor, account: AptosAccount) { 9 | super(adaptor.client) 10 | this.account = account 11 | } 12 | 13 | get address(): string { 14 | return this.account.accountAddress.toString() 15 | } 16 | 17 | signMessage (msg: string) { 18 | return this.account.sign(utils.toUtf8Bytes(msg)).toString() 19 | } 20 | 21 | async sendTransaction(payload, options) { 22 | const transaction = await this.client.transaction.build.simple({ 23 | sender: this.address, 24 | data: { 25 | function: payload.function, 26 | functionArguments: payload.arguments, 27 | typeArguments: payload.type_arguments, 28 | } 29 | }) 30 | const tx = await this.client.signAndSubmitTransaction({ signer: this.account, transaction }) 31 | 32 | return { 33 | hash: utils.hexZeroPad(tx.hash, 32), 34 | wait: () => this.waitForTransaction(tx.hash) 35 | } 36 | } 37 | 38 | async deploy(module: string, metadata: string) { 39 | // let hash = await this.client.publishPackage( 40 | // this.account, 41 | // new HexString(metadata).toUint8Array(), 42 | // [new TxnBuilderTypes.Module(new HexString(module).toUint8Array())] 43 | // ) 44 | // hash = utils.hexZeroPad(hash, 32) 45 | 46 | // return { 47 | // hash, 48 | // wait: () => this.waitForTransaction(hash) 49 | // } 50 | } 51 | } 52 | 53 | export class AptosExtWallet extends AptosWallet { 54 | readonly ext: any 55 | 56 | constructor(adaptor: AptosAdaptor, ext) { 57 | super(adaptor, null) 58 | this.ext = ext 59 | } 60 | 61 | get address() { 62 | // TODO: might be different for different exts 63 | return this.ext.signer.account() as string 64 | } 65 | 66 | async sendTransaction(payload, options) { 67 | // This method is provided by `@manahippo/aptos-wallet-adapter` 68 | const tx = await this.ext.signer.signAndSubmitTransaction(payload, options) 69 | // TODO: error handling 70 | return { 71 | hash: utils.hexZeroPad(tx.hash, 32), 72 | wait: () => this.waitForTransaction(tx.hash) 73 | } 74 | } 75 | 76 | async deploy(): Promise { 77 | throw new Error('Cannot deploy with extention wallet') 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /packages/sdk/src/SignedSwap.ts: -------------------------------------------------------------------------------- 1 | import { utils } from 'ethers' 2 | 3 | import type { CompactSignature } from './SwapSigner' 4 | import { Swap } from './Swap' 5 | import { SwapSigner } from './SwapSigner' 6 | 7 | export interface SignedSwapRequestData { 8 | testnet?: boolean, 9 | encoded: string, 10 | initiator: string, 11 | signature: CompactSignature, 12 | } 13 | 14 | export interface SignedSwapReleaseData extends SignedSwapRequestData { 15 | recipient: string, 16 | } 17 | 18 | export class SignedSwapRequest implements SignedSwapRequestData { 19 | readonly testnet: boolean 20 | readonly swap: Swap 21 | readonly encoded: string 22 | readonly initiator: string 23 | readonly signature: CompactSignature 24 | 25 | constructor (data: SignedSwapRequestData) { 26 | if (!data.encoded) { 27 | throw new Error('Missing encoded') 28 | } else if (!data.initiator) { 29 | throw new Error('Missing initiator') 30 | } else if (!data.signature) { 31 | throw new Error('Missing signature') 32 | } 33 | 34 | this.testnet = Boolean(data.testnet) 35 | this.swap = Swap.decode(data.encoded) 36 | 37 | this.encoded = data.encoded 38 | this.initiator = data.initiator.toLowerCase() 39 | this.signature = data.signature 40 | } 41 | 42 | getDigest () { 43 | return SwapSigner.hashRequest(this.encoded, this.testnet) 44 | } 45 | 46 | checkSignature () { 47 | const recovered = utils.recoverAddress(this.getDigest(), this.signature).toLowerCase() 48 | if (recovered !== this.initiator) { 49 | throw new Error('Invalid signature') 50 | } 51 | } 52 | 53 | toObject (): SignedSwapRequestData { 54 | const data: SignedSwapRequestData = { 55 | encoded: this.encoded, 56 | initiator: this.initiator, 57 | signature: this.signature, 58 | } 59 | if (this.testnet) { 60 | data.testnet = true 61 | } 62 | return data 63 | } 64 | } 65 | 66 | export class SignedSwapRelease extends SignedSwapRequest implements SignedSwapReleaseData { 67 | readonly recipient: string; 68 | 69 | constructor (data: SignedSwapReleaseData) { 70 | super(data) 71 | 72 | if (!data.recipient) { 73 | throw new Error('Missing recipient') 74 | } 75 | this.recipient = data.recipient 76 | } 77 | 78 | getDigest () { 79 | return SwapSigner.hashRelease(this.encoded, this.recipient, this.testnet) 80 | } 81 | 82 | toObject (): SignedSwapReleaseData { 83 | return { 84 | ...super.toObject(), 85 | recipient: this.recipient, 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/tron/TronContract.ts: -------------------------------------------------------------------------------- 1 | import TronWeb from 'tronweb' 2 | import { utils } from 'ethers' 3 | 4 | import TronAdaptor from './TronAdaptor' 5 | import TronWallet from './TronWallet' 6 | 7 | export default class TronContract { 8 | readonly #adaptor: TronAdaptor 9 | readonly #contract 10 | 11 | constructor(address: string, abi, adaptor: TronAdaptor) { 12 | this.#adaptor = adaptor 13 | this.#contract = this.#adaptor.client.contract(abi, address) 14 | 15 | Object.entries(this.#contract.methodInstances) 16 | .forEach(([name, { abi }]: [string, { abi: any }]) => { 17 | if (abi?.type === 'function') { 18 | if (['view', 'pure'].includes(abi.stateMutability)) { 19 | Object.defineProperty(this, name, { 20 | enumerable: true, 21 | value: (...args) => this._read(name, abi, args), 22 | writable: false, 23 | }) 24 | } else { 25 | Object.defineProperty(this, name, { 26 | enumerable: true, 27 | value: (...args) => this._write(name, abi, args), 28 | writable: false, 29 | }) 30 | } 31 | } 32 | }) 33 | } 34 | 35 | get address() { 36 | return TronWeb.address.fromHex(this.#contract.address) 37 | } 38 | 39 | get provider() { 40 | return this.#adaptor 41 | } 42 | 43 | get signer() { 44 | if (this.#adaptor instanceof TronWallet) { 45 | return this.#adaptor 46 | } 47 | throw new Error(`TronWeb instance doesn't have a signer.`) 48 | } 49 | 50 | get interface() { 51 | return new utils.Interface(this.#contract.abi) 52 | } 53 | 54 | get filters() { 55 | throw new Error('TronContract.filters not implemented') 56 | } 57 | 58 | connect(providerOrTronWeb: TronAdaptor | TronWeb) { 59 | return new TronContract(this.address, this.#contract.abi, providerOrTronWeb) 60 | } 61 | 62 | queryFilter() {} 63 | on() {} 64 | removeAllListeners() {} 65 | 66 | async _read(name: string, abi, args: any[]) { 67 | let overrides 68 | if (args.length > abi.inputs.length) { 69 | overrides = args.pop() 70 | } 71 | return await this.#contract[name](...args).call(overrides) 72 | } 73 | 74 | async _write(name: string, abi, args: any[]) { 75 | let overrides 76 | if (args.length > abi.inputs.length) { 77 | overrides = args.pop() 78 | } 79 | return await (this.#adaptor as TronWallet).sendTransaction({ 80 | contract: this.#contract, 81 | method: name, 82 | args, 83 | }, overrides) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/solana/SolanaWallet.ts: -------------------------------------------------------------------------------- 1 | import { utils } from 'ethers' 2 | import { 3 | Keypair as SolKeypair, 4 | PublicKey as SolPublicKey, 5 | Transaction as SolTransaction, 6 | SystemProgram, 7 | ComputeBudgetProgram, 8 | } from '@solana/web3.js' 9 | import nacl from 'tweetnacl' 10 | import SolanaAdaptor from './SolanaAdaptor' 11 | 12 | export default class SolanaWallet extends SolanaAdaptor { 13 | readonly keypair: SolKeypair 14 | 15 | constructor(adaptor: SolanaAdaptor, keypair: SolKeypair) { 16 | super(adaptor.client) 17 | this.keypair = keypair 18 | } 19 | 20 | get publicKey() { 21 | return this.keypair.publicKey 22 | } 23 | 24 | get address() { 25 | return this.publicKey.toString() 26 | } 27 | 28 | signMessage(msg: string) { 29 | let signData: Uint8Array 30 | if (utils.isHexString(msg)) { 31 | signData = utils.arrayify(msg) 32 | } else { 33 | signData = utils.toUtf8Bytes(msg) 34 | } 35 | const signature = nacl.sign.detached(signData, this.keypair.secretKey) 36 | return utils.hexlify(signature) 37 | } 38 | 39 | async sendTransaction(tx, options: { gasPrice?: number } = { gasPrice: 500_000 }) { 40 | if (!(tx instanceof SolTransaction)) { 41 | tx = new SolTransaction().add( 42 | SystemProgram.transfer({ 43 | fromPubkey: this.publicKey, 44 | toPubkey: new SolPublicKey(tx.to), 45 | lamports: tx.value.toString(), 46 | }) 47 | ) 48 | } 49 | if (options.gasPrice) { 50 | tx.add(ComputeBudgetProgram.setComputeUnitPrice({ microLamports: options.gasPrice })) 51 | } 52 | const hash = await this.client.sendTransaction(tx, [this.keypair]) 53 | return { 54 | hash, 55 | wait: () => this.waitForTransaction(hash, 1) 56 | } 57 | } 58 | 59 | async deploy(module: string, metadata: string) { 60 | } 61 | } 62 | 63 | export class SolanaExtWallet extends SolanaWallet { 64 | readonly ext: any 65 | 66 | constructor(adaptor: SolanaAdaptor, ext) { 67 | super(adaptor, null) 68 | this.ext = ext 69 | } 70 | 71 | get publicKey() { 72 | return new SolPublicKey(this.address) 73 | } 74 | 75 | get address() { 76 | return this.ext?.currentAccount?.address 77 | } 78 | 79 | async sendTransaction(tx: SolTransaction, options?) { 80 | tx.recentBlockhash = await this.detectNetwork() 81 | tx.feePayer = this.publicKey 82 | const hash = await this.ext.sendTransaction(tx) 83 | return { 84 | hash, 85 | wait: () => this.waitForTransaction(hash, 1) 86 | } 87 | } 88 | 89 | async deploy(): Promise { 90 | throw new Error('Cannot deploy with extention wallet') 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /contracts/Pools/IMesonPoolsEvents.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | /// @title MesonPools Interface 5 | interface IMesonPoolsEvents { 6 | /// @notice Event when an LP pool is registered. 7 | /// Emit at the end of `depositAndRegister()` calls. 8 | /// @param poolIndex Pool index 9 | /// @param owner Pool owner 10 | event PoolRegistered(uint40 indexed poolIndex, address owner); 11 | 12 | /// @notice Event when fund was deposited to an LP pool. 13 | /// Emit at the end of `depositAndRegister()` and `deposit()` calls. 14 | /// @param poolTokenIndex Concatenation of pool index & token index 15 | /// @param amount The amount of tokens to be added to the pool 16 | event PoolDeposited(uint48 indexed poolTokenIndex, uint256 amount); 17 | 18 | /// @notice Event when fund was withdrawn from an LP pool. 19 | /// Emit at the end of `withdraw()` calls. 20 | /// @param poolTokenIndex Concatenation of pool index & token index 21 | /// @param amount The amount of tokens to be removed from the pool 22 | event PoolWithdrawn(uint48 indexed poolTokenIndex, uint256 amount); 23 | 24 | /// @notice Event when an authorized address was added for an LP pool. 25 | /// Emit at the end of `depositAndRegister()` calls. 26 | /// @param poolIndex Pool index 27 | /// @param addr Authorized address to be added 28 | event PoolAuthorizedAddrAdded(uint40 indexed poolIndex, address addr); 29 | 30 | /// @notice Event when an authorized address was removed for an LP pool. 31 | /// Emit at the end of `depositAndRegister()` calls. 32 | /// @param poolIndex Pool index 33 | /// @param addr Authorized address to be removed 34 | event PoolAuthorizedAddrRemoved(uint40 indexed poolIndex, address addr); 35 | 36 | /// @notice Event when the ownership of a pool was transferred. 37 | /// Emit at the end of `transferPoolOwner()` calls. 38 | /// @param poolIndex Pool index 39 | /// @param prevOwner Previous owner of the pool 40 | /// @param newOwner New owner of the pool 41 | event PoolOwnerTransferred(uint40 indexed poolIndex, address prevOwner, address newOwner); 42 | 43 | /// @notice Event when a swap was locked. 44 | /// Emit at the end of `lock()` and `lockSwap()` calls. 45 | /// @param encodedSwap Encoded swap 46 | event SwapLocked(uint256 indexed encodedSwap); 47 | 48 | /// @notice Event when a swap was unlocked. 49 | /// Emit at the end of `unlock()` calls. 50 | /// @param encodedSwap Encoded swap 51 | event SwapUnlocked(uint256 indexed encodedSwap); 52 | 53 | /// @notice Event when a swap was released. 54 | /// Emit at the end of `release()`, `directRelease()` calls. 55 | /// @param encodedSwap Encoded swap 56 | event SwapReleased(uint256 indexed encodedSwap); 57 | } 58 | -------------------------------------------------------------------------------- /packages/adaptors/src/MesonNetworkClientBase.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonNetworkClientBase 3 | */ 4 | import { IMesonNetwork, MesonAddressFormat } from '@mesonfi/base' 5 | import { IMesonAdaptorBlockInfo, MesonData } from './types' 6 | import { BigNumber } from 'ethers' 7 | 8 | const __SUPER__ = Symbol('__SUPER__') 9 | 10 | export abstract class MesonNetworkClientBase { 11 | 12 | public readonly addressFormat: T 13 | 14 | public readonly networkId: string 15 | 16 | public readonly configUrl: string 17 | 18 | protected constructor (url: string, network: IMesonNetwork) { 19 | this.addressFormat = network.addressFormat as T 20 | this.networkId = network.id 21 | this.configUrl = url 22 | } 23 | 24 | public abstract get nodeUrl (): string 25 | 26 | public abstract getBlockInfo(): Promise 27 | 28 | public abstract getBlockNumber(): Promise 29 | 30 | // public abstract getGasPrice(): Promise 31 | 32 | public abstract getBalance(addr: string): Promise 33 | 34 | // public abstract getCode(addr: string): Promise 35 | // 36 | // public abstract getLogs(filter: MesonData): Promise 37 | // 38 | // public abstract send(method: string, params: MesonData[]): Promise 39 | 40 | // public abstract waitForTransaction(hash: string, confirmations?: number, timeout?: number): Promise 41 | 42 | protected inherit MesonData>(Constructor: T, args: ConstructorParameters): MesonData { 43 | 44 | const origin = Object.getPrototypeOf(this) 45 | const instance = new Constructor(...args) 46 | const base = Object.getPrototypeOf(instance) 47 | const target = {} 48 | 49 | Object.defineProperty(target, 'callSuper', { 50 | configurable: false, 51 | enumerable: false, 52 | writable: false, 53 | value: this.callSuper.bind(instance), 54 | }) 55 | 56 | Object.defineProperties(target, Object.getOwnPropertyDescriptors(origin)) 57 | Object.defineProperty(target, 'constructor', { 58 | configurable: true, 59 | enumerable: false, 60 | writable: false, 61 | value: Constructor, 62 | }) 63 | Object.setPrototypeOf(target, base) 64 | Object.setPrototypeOf(instance, target) 65 | 66 | Object.assign(instance, this) 67 | Object.defineProperty(instance, __SUPER__, { 68 | enumerable: false, 69 | configurable: false, 70 | writable: false, 71 | value: base, 72 | }) 73 | 74 | return instance 75 | } 76 | 77 | protected callSuper (method: string, ...args: MesonData[]): MesonData { 78 | return this[__SUPER__][method].apply(this, args) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /packages/adaptors/src/ton/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Address, Builder, Cell } from '@ton/core' 2 | 3 | export interface TokenTransfer { 4 | $$type: 'TokenTransfer' 5 | query_id: bigint 6 | amount: bigint 7 | destination: Address 8 | response_destination: Address | null 9 | custom_payload: Cell | null 10 | forward_ton_amount: bigint 11 | forward_payload: Cell 12 | } 13 | 14 | export function storeTokenTransfer (src: TokenTransfer) { 15 | return (builder: Builder) => { 16 | const b_0 = builder 17 | b_0.storeUint(260734629, 32) 18 | b_0.storeUint(src.query_id, 64) 19 | b_0.storeCoins(src.amount) 20 | b_0.storeAddress(src.destination) 21 | b_0.storeAddress(src.response_destination) 22 | if (src.custom_payload !== null && src.custom_payload !== undefined) { 23 | b_0.storeBit(true).storeRef(src.custom_payload) 24 | } else { 25 | b_0.storeBit(false) 26 | } 27 | b_0.storeCoins(src.forward_ton_amount) 28 | b_0.storeBuilder(src.forward_payload.asBuilder()) 29 | } 30 | } 31 | 32 | export interface ProxyTokenTransfer { 33 | $$type: 'ProxyTokenTransfer' 34 | wallet_address: Address 35 | token_transfer: TokenTransfer 36 | } 37 | 38 | export function storeProxyTokenTransfer (src: ProxyTokenTransfer) { 39 | return (builder: Builder) => { 40 | const b_0 = builder 41 | b_0.storeUint(3761706239, 32) 42 | b_0.storeAddress(src.wallet_address) 43 | const b_1 = new Builder() 44 | b_1.store(storeTokenTransfer(src.token_transfer)) 45 | b_0.storeRef(b_1.endCell()) 46 | } 47 | } 48 | 49 | export interface ProxyTokenTransferWithSwapid { 50 | $$type: 'ProxyTokenTransferWithSwapid' 51 | swapid: bigint 52 | wallet_address: Address 53 | token_transfer: TokenTransfer 54 | } 55 | 56 | export function storeProxyTokenTransferWithSwapid (src: ProxyTokenTransferWithSwapid) { 57 | return (builder: Builder) => { 58 | const b_0 = builder 59 | b_0.storeUint(2737718375, 32) 60 | b_0.storeUint(src.swapid, 256) 61 | b_0.storeAddress(src.wallet_address) 62 | const b_1 = new Builder() 63 | b_1.store(storeTokenTransfer(src.token_transfer)) 64 | b_0.storeRef(b_1.endCell()) 65 | } 66 | } 67 | 68 | export interface ModifySupportToken { 69 | $$type: 'ModifySupportToken' 70 | available: boolean 71 | token_index: bigint 72 | token_master_address: Address 73 | meson_wallet_address: Address 74 | } 75 | 76 | export function storeModifySupportToken (src: ModifySupportToken) { 77 | return (builder: Builder) => { 78 | const b_0 = builder 79 | b_0.storeUint(613687068, 32) 80 | b_0.storeBit(src.available) 81 | b_0.storeUint(src.token_index, 8) 82 | b_0.storeAddress(src.token_master_address) 83 | b_0.storeAddress(src.meson_wallet_address) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/ton/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Address, Builder, Cell } from "@ton/core"; 2 | 3 | export type TokenTransfer = { 4 | $$type: 'TokenTransfer'; 5 | query_id: bigint; 6 | amount: bigint; 7 | destination: Address; 8 | response_destination: Address | null; 9 | custom_payload: Cell | null; 10 | forward_ton_amount: bigint; 11 | forward_payload: Cell; 12 | } 13 | 14 | export function storeTokenTransfer(src: TokenTransfer) { 15 | return (builder: Builder) => { 16 | let b_0 = builder; 17 | b_0.storeUint(260734629, 32); 18 | b_0.storeUint(src.query_id, 64); 19 | b_0.storeCoins(src.amount); 20 | b_0.storeAddress(src.destination); 21 | b_0.storeAddress(src.response_destination); 22 | if (src.custom_payload !== null && src.custom_payload !== undefined) { b_0.storeBit(true).storeRef(src.custom_payload); } else { b_0.storeBit(false); } 23 | b_0.storeCoins(src.forward_ton_amount); 24 | b_0.storeBuilder(src.forward_payload.asBuilder()); 25 | }; 26 | } 27 | 28 | export type ProxyTokenTransfer = { 29 | $$type: 'ProxyTokenTransfer'; 30 | wallet_address: Address; 31 | token_transfer: TokenTransfer; 32 | } 33 | 34 | export function storeProxyTokenTransfer(src: ProxyTokenTransfer) { 35 | return (builder: Builder) => { 36 | let b_0 = builder; 37 | b_0.storeUint(3761706239, 32); 38 | b_0.storeAddress(src.wallet_address); 39 | let b_1 = new Builder(); 40 | b_1.store(storeTokenTransfer(src.token_transfer)); 41 | b_0.storeRef(b_1.endCell()); 42 | }; 43 | } 44 | 45 | export type ProxyTokenTransferWithSwapid = { 46 | $$type: 'ProxyTokenTransferWithSwapid'; 47 | swapid: bigint; 48 | wallet_address: Address; 49 | token_transfer: TokenTransfer; 50 | } 51 | 52 | export function storeProxyTokenTransferWithSwapid(src: ProxyTokenTransferWithSwapid) { 53 | return (builder: Builder) => { 54 | let b_0 = builder; 55 | b_0.storeUint(2737718375, 32); 56 | b_0.storeUint(src.swapid, 256); 57 | b_0.storeAddress(src.wallet_address); 58 | let b_1 = new Builder(); 59 | b_1.store(storeTokenTransfer(src.token_transfer)); 60 | b_0.storeRef(b_1.endCell()); 61 | }; 62 | } 63 | 64 | export type ModifySupportToken = { 65 | $$type: 'ModifySupportToken'; 66 | available: boolean; 67 | token_index: bigint; 68 | token_master_address: Address; 69 | meson_wallet_address: Address; 70 | } 71 | 72 | export function storeModifySupportToken(src: ModifySupportToken) { 73 | return (builder: Builder) => { 74 | let b_0 = builder; 75 | b_0.storeUint(613687068, 32); 76 | b_0.storeBit(src.available); 77 | b_0.storeUint(src.token_index, 8); 78 | b_0.storeAddress(src.token_master_address); 79 | b_0.storeAddress(src.meson_wallet_address); 80 | }; 81 | } -------------------------------------------------------------------------------- /packages/base/src/types/MesonNetwork.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonNetwork 3 | */ 4 | 5 | import { IMesonToken, IMesonTokenData, IMesonTokenDataWithPartner, MesonAddressFormat } from './MesonToken' 6 | 7 | export interface IMesonNetworkNativeCurrency { 8 | 9 | symbol: string 10 | 11 | decimals: number 12 | 13 | name?: string 14 | 15 | icon?: string 16 | } 17 | 18 | export interface IMesonNetworkMetadata { 19 | tx_hash_siglock?: string 20 | tx_hash_refcell?: string 21 | tx_hash_joyid?: string 22 | tx_hash_xudt?: string 23 | code_hash_refcell?: string 24 | code_hash_xudt?: string 25 | url_tonconsole?: string 26 | pools?: (number | string)[][] 27 | } 28 | 29 | export interface IMesonNetworkData { 30 | 31 | id: string 32 | 33 | name: string 34 | 35 | alias: string 36 | 37 | chainId: string 38 | 39 | explorer?: string 40 | 41 | slip44: string 42 | 43 | shortSlip44: string 44 | 45 | addressFormat: MesonAddressFormat 46 | 47 | url: string 48 | 49 | mesonAddress: string 50 | 51 | nativeCurrency?: IMesonNetworkNativeCurrency 52 | 53 | extensions: string[] 54 | 55 | metadata?: IMesonNetworkMetadata 56 | 57 | tokens: IMesonTokenData[] 58 | 59 | disabled: boolean 60 | } 61 | 62 | export interface IMesonNetwork extends Omit { 63 | 64 | readonly networkId: string 65 | 66 | readonly coreDecimals: number 67 | 68 | readonly tokens: T[] 69 | 70 | getData(): IMesonNetworkData 71 | 72 | supportExtension(extensionType: string): boolean 73 | 74 | getMesonAddressLink(): string 75 | 76 | hasToken(tokenIndex: number): boolean 77 | 78 | getTokenByTokenIndex(tokenIndex: number): T 79 | 80 | getTokensByCategory(category: string): T[] 81 | 82 | getTokenByCategory(category: string): T | undefined 83 | 84 | getCoreToken(): T | undefined 85 | 86 | getCoreSymbol(): string | undefined 87 | } 88 | 89 | export interface IMesonNetworkDataWithPartner extends Omit { 90 | 91 | disabled?: boolean 92 | 93 | addressFormat: string 94 | 95 | uctAddress?: string 96 | 97 | tokens: IMesonTokenDataWithPartner[] 98 | } 99 | 100 | export interface MesonNetworkStatusCommon { 101 | networkId: string 102 | addressFormat: MesonAddressFormat 103 | url: string 104 | } 105 | 106 | export interface MesonNetworkStatusHealthy extends MesonNetworkStatusCommon { 107 | latency: number 108 | lastBlockNumber: string 109 | lastBlockTimestamp: string 110 | gasPrice?: string 111 | healthy: true 112 | } 113 | 114 | export interface MesonNetworkStatusError extends MesonNetworkStatusCommon { 115 | error: string 116 | healthy: false 117 | } 118 | 119 | export type MesonNetworkStatus = MesonNetworkStatusHealthy | MesonNetworkStatusError 120 | -------------------------------------------------------------------------------- /packages/sdk/tests/shared/index.ts: -------------------------------------------------------------------------------- 1 | import { BigNumberish, utils } from 'ethers' 2 | import { PartialSwapData, SwapData, SignedSwapRequestData, SignedSwapReleaseData } from '../..' 3 | 4 | export function getPartialSwap({ 5 | amount = utils.parseUnits('1000', 6) as BigNumberish, 6 | fee = utils.parseUnits('1', 6) as BigNumberish, 7 | inToken = 1, 8 | outToken = 1, 9 | } = {}): PartialSwapData { 10 | return { 11 | amount, 12 | fee, 13 | inToken, 14 | outToken, 15 | recipient: '0x2ef8a51f8ff129dbb874a0efb021702f59c1b211', 16 | salt: '0x80' 17 | } 18 | } 19 | 20 | export function getSwap({ 21 | amount = utils.parseUnits('1000', 6) as BigNumberish, 22 | fee = utils.parseUnits('1', 6) as BigNumberish, 23 | expireTs = Math.floor(Date.now() / 1000) + 5400, 24 | inChain = '0x0001', 25 | inToken = 2, 26 | outChain = '0x0002', 27 | outToken = 3, 28 | } = {}): SwapData { 29 | return { 30 | amount, 31 | fee, 32 | expireTs, 33 | inChain, 34 | inToken, 35 | outChain, 36 | outToken, 37 | } 38 | } 39 | 40 | interface ExtendedSignedSwapRequestData extends SignedSwapRequestData { 41 | digest: string 42 | mainnetDigest: string 43 | mainnetSignature: string 44 | } 45 | 46 | export const signedSwapRequestData = { 47 | testnet: true, 48 | encoded: '0x01003b9aca000000000000008140328700000f424000621d7ef8003c01003c01', 49 | initiator: '0x63FC2aD3d021a4D7e64323529a55a9442C444dA0', 50 | digest: '0xae2ef152547628db8ec4d935ea85828b120aca6ece438207f8dcaa842e69ff0f', 51 | signature: '0x3cd0c5a3abe5214b5001e44d73d02b6fa7068f46256090c1043ebcd23483c2d0ad4038d42b0b247fefa54c123675a5a4984431c9033261f96f0084d42a5d52c7', 52 | mainnetDigest: '0x778f68046136b3a42d3f715762b1e114926da740d4a3b9ada63d0af2964d6302', 53 | mainnetSignature: '0x39e66dc0fcacad5f09cc92a92ec6e279c8445e68c9c417d1b67a7a268465bc737bb7b56caedd14c12a10b2f71dabd50e46941de3c26b7039c8e1be5d3d4282e7' 54 | } as ExtendedSignedSwapRequestData 55 | 56 | interface ExtendedSignedSwapReleaseData extends SignedSwapReleaseData { 57 | digest: string 58 | mainnetDigest: string 59 | mainnetSignature: string 60 | } 61 | 62 | export const signedSwapReleaseData = { 63 | testnet: true, 64 | encoded: '0x01003b9aca000000000000008140328700000f424000621d7ef8003c01003c01', 65 | initiator: '0x63FC2aD3d021a4D7e64323529a55a9442C444dA0', 66 | recipient: '0xD1D84F0e28D6fedF03c73151f98dF95139700aa7', 67 | digest: '0xf0331cc7c17b25ed6bfd9bd1ea3bc35d0afbc9dd6148d5c5ad585ad24fa3944c', 68 | signature: '0x7b865163e2e513a187f8a6d9a73f7ae4a5026d510da2c48a486888ba54e4a483bb7e6ed417a721247b27dba3968e8b08179eb940ebb8e4865b574149e0cf7097', 69 | mainnetDigest: '0x46e800b7c736d9fe41e74f6719ff6b1c230e04b3b47f58896714b6f14e371193', 70 | mainnetSignature: '0xf8eabaa8bd8f26c5d0338a0b1fcc9e577bb33c77ede12c130ca39a506129a36fdffde39331c79c9c37fa0497ae53bb4ba3e8ec3a8e59cc8f601d6a7dfbeccf6e' 71 | } as ExtendedSignedSwapReleaseData -------------------------------------------------------------------------------- /packages/base/src/meson/MesonPresets.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonPresets 3 | */ 4 | 5 | import { 6 | IMesonNetworkData, 7 | IMesonPresets, 8 | } from '../types' 9 | 10 | import { MesonNetwork } from './MesonNetwork' 11 | 12 | export class MesonPresets implements IMesonPresets { 13 | 14 | public static create (networks: IMesonNetworkData[], useTestnet = false): MesonPresets { 15 | return new MesonPresets(networks, useTestnet) 16 | } 17 | 18 | protected isTestnet = false 19 | 20 | protected networks: MesonNetwork[] = [] 21 | 22 | protected networkIdMap: Record = {} 23 | 24 | protected networkShortCoinTypeMap: Record = {} 25 | 26 | protected networkChainIdMap: Record = {} 27 | 28 | protected constructor (networks: IMesonNetworkData[], useTestnet = false) { 29 | this.initNetworks(networks, useTestnet) 30 | } 31 | 32 | public initNetworks (data: IMesonNetworkData[], useTestnet = false) { 33 | 34 | this.isTestnet = useTestnet 35 | this.networks = [] 36 | this.networkIdMap = {} 37 | this.networkShortCoinTypeMap = {} 38 | this.networkChainIdMap = {} 39 | 40 | data.forEach(config => { 41 | const network = MesonNetwork.create(config) 42 | 43 | this.networkIdMap[network.networkId] = network 44 | this.networkShortCoinTypeMap[network.shortSlip44] = network 45 | this.networkChainIdMap[network.chainId] = network 46 | this.networks.push(network) 47 | }) 48 | } 49 | 50 | // region Public Methods 51 | 52 | public get useTestnet (): boolean { 53 | return this.isTestnet 54 | } 55 | 56 | public getNetworks (): MesonNetwork[] { 57 | return this.networks 58 | } 59 | 60 | public hasNetwork (networkId: string): boolean { 61 | return Boolean(this.networkIdMap[networkId]) 62 | } 63 | 64 | public hasNetworkByChain (chainId: string): boolean { 65 | return Boolean(this.networkChainIdMap[chainId]) 66 | } 67 | 68 | public hasNetworkByShortCoinType (shortSlip44: string): boolean { 69 | return Boolean(this.networkShortCoinTypeMap[shortSlip44]) 70 | } 71 | 72 | public getNetworkByNetworkId (networkId: string): MesonNetwork { 73 | if (!this.networkIdMap[networkId]) { 74 | throw new Error(`Network id = '${networkId}' not found`) 75 | } 76 | 77 | return this.networkIdMap[networkId] 78 | } 79 | 80 | public getNetworkFromShortCoinType (shortCoinType: string): MesonNetwork { 81 | if (!this.networkShortCoinTypeMap[shortCoinType]) { 82 | throw new Error(`Network shortCoinType = '${shortCoinType}' not found`) 83 | } 84 | 85 | return this.networkShortCoinTypeMap[shortCoinType] 86 | } 87 | 88 | public getNetworkFromChainId (chainId: string): MesonNetwork { 89 | if (!this.networkChainIdMap[chainId]) { 90 | throw new Error(`Network chainId = '${chainId}' not found`) 91 | } 92 | 93 | return this.networkChainIdMap[chainId] 94 | } 95 | 96 | // endregion 97 | } 98 | -------------------------------------------------------------------------------- /contracts/TransferToMesonContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | interface IMesonMinimal { 5 | function tokenForIndex(uint8 tokenIndex) external view returns (address); 6 | function _isCoreToken(uint8 tokenIndex) external view returns (bool); 7 | function _amountFactor(uint8 tokenIndex) external view returns (uint256); 8 | function simpleExecuteSwap(uint256 encodedSwap) payable external; 9 | } 10 | 11 | contract TransferToMesonFactory { 12 | function deploy(address mesonAddress, uint16 destChain, bytes32 destAddr, address via) external returns (address deployedAddress) { 13 | bytes memory bytecode = abi.encodePacked( 14 | type(TransferToMesonContract).creationCode, 15 | abi.encode(mesonAddress, destChain, destAddr, via) 16 | ); 17 | 18 | assembly { 19 | deployedAddress := create2(0, add(bytecode, 32), mload(bytecode), "") 20 | if iszero(deployedAddress) { 21 | revert(0, 0) 22 | } 23 | } 24 | } 25 | } 26 | 27 | contract TransferToMesonContract { 28 | bytes4 private constant ERC20_APPROVE_SELECTOR = bytes4(keccak256("approve(address,uint256)")); 29 | 30 | IMesonMinimal public immutable meson; 31 | uint16 public immutable destChain; 32 | bytes32 public immutable destAddr; // Could be used for non-EVMs 33 | address public immutable via; 34 | 35 | error EInvalidEncoded(); 36 | error EIncorrectDestChain(); 37 | error ENeedToContract(); 38 | error EApprove(); 39 | 40 | constructor(address mesonAddress, uint16 _destChain, bytes32 _destAddr, address _via) { 41 | meson = IMesonMinimal(mesonAddress); 42 | destChain = _destChain; 43 | destAddr = _destAddr; 44 | via = _via; 45 | } 46 | 47 | receive() external payable {} 48 | 49 | function transferToMeson(uint256 encodedSwap) external { 50 | require((encodedSwap & 0x3000000000000000000000000000000000000000000000000000) == 0x3000000000000000000000000000000000000000000000000000, EInvalidEncoded()); 51 | require(destChain == uint16(encodedSwap >> 32), EIncorrectDestChain()); 52 | if (via != address(0)) { 53 | require((encodedSwap & 0x8000000000000000000000000000000000000000000000000000) == 0, ENeedToContract()); 54 | } 55 | 56 | uint8 tokenIndex = uint8(encodedSwap); 57 | uint256 amount = (encodedSwap >> 208) & 0xFFFFFFFFFF; 58 | 59 | if (meson._isCoreToken(tokenIndex)) { 60 | meson.simpleExecuteSwap{value: amount * 10 ** 12}(encodedSwap); 61 | } else { 62 | address tokenAddr = meson.tokenForIndex(tokenIndex); 63 | (bool success, bytes memory data) = tokenAddr.call( 64 | abi.encodeWithSelector(ERC20_APPROVE_SELECTOR, address(meson), amount * meson._amountFactor(tokenIndex)) 65 | ); 66 | require(success && (data.length == 0 || abi.decode(data, (bool))), EApprove()); 67 | 68 | meson.simpleExecuteSwap(encodedSwap); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /packages/adaptors/src/tron/contract.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file contract 3 | */ 4 | import { utils } from 'ethers' 5 | 6 | import TronWeb from 'tronweb' 7 | import { IMesonTronFailoverNetworkClient } from './type' 8 | import { TronWallet } from './wallet' 9 | 10 | export class TronContract { 11 | 12 | readonly #contract 13 | 14 | public readonly wallet: TronWallet | null 15 | 16 | public readonly networkClient: IMesonTronFailoverNetworkClient 17 | 18 | constructor (address: string, abi, adaptor: TronWallet | IMesonTronFailoverNetworkClient) { 19 | this.wallet = (adaptor instanceof TronWallet) ? adaptor : null 20 | this.networkClient = (adaptor instanceof TronWallet) ? adaptor.networkClient : adaptor 21 | this.#contract = this.wallet 22 | ? this.wallet.tronWeb.contract(abi, address) 23 | : this.networkClient.contract(abi, address) 24 | 25 | Object.entries(this.#contract.methodInstances) 26 | .forEach(([name, { abi }]: [string, {abi: any}]) => { 27 | if (abi?.type === 'function') { 28 | if (['view', 'pure'].includes(abi.stateMutability)) { 29 | Object.defineProperty(this, name, { 30 | enumerable: true, 31 | value: (...args) => this._read(name, abi, args), 32 | writable: false, 33 | }) 34 | } else { 35 | Object.defineProperty(this, name, { 36 | enumerable: true, 37 | value: (...args) => this._write(name, abi, args), 38 | writable: false, 39 | }) 40 | } 41 | } 42 | }) 43 | } 44 | 45 | get address () { 46 | return TronWeb.address.fromHex(this.#contract.address) 47 | } 48 | 49 | get provider () { 50 | return this.networkClient 51 | } 52 | 53 | get signer () { 54 | if (this.wallet) { 55 | return this.wallet 56 | } 57 | throw new Error('TronWeb instance doesn\'t have a signer.') 58 | } 59 | 60 | get interface () { 61 | return new utils.Interface(this.#contract.abi) 62 | } 63 | 64 | get filters () { 65 | throw new Error('TronContract.filters not implemented') 66 | } 67 | 68 | connect (adaptor: TronWallet | IMesonTronFailoverNetworkClient) { 69 | return new TronContract(this.address, this.#contract.abi, adaptor) 70 | } 71 | 72 | queryFilter () { 73 | } 74 | 75 | on () { 76 | } 77 | 78 | removeAllListeners () { 79 | } 80 | 81 | async _read (name: string, abi, args: any[]) { 82 | let overrides 83 | if (args.length > abi.inputs.length) { 84 | overrides = args.pop() 85 | } 86 | return await this.#contract[name](...args).call(overrides) 87 | } 88 | 89 | async _write (name: string, abi, args: any[]) { 90 | let overrides 91 | if (args.length > abi.inputs.length) { 92 | overrides = args.pop() 93 | } 94 | return await this.signer.sendTransaction({ 95 | contract: this.#contract, 96 | method: name, 97 | args, 98 | }, overrides) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/ton/TonWallet.ts: -------------------------------------------------------------------------------- 1 | // import { ethers } from 'ethers' 2 | import { KeyPair } from '@ton/crypto' 3 | import { beginCell, storeMessage } from '@ton/core' 4 | import { Address, Cell, internal, external, OpenedContract, Sender, WalletContractV4 } from '@ton/ton' 5 | 6 | import TonAdaptor from './TonAdaptor' 7 | 8 | export default class TonWallet extends TonAdaptor { 9 | readonly #publicKey: Buffer 10 | readonly #secretKey: Buffer 11 | readonly #wallet: WalletContractV4 12 | readonly #walletContract: OpenedContract 13 | readonly #walletSender: Sender 14 | readonly #address: Address 15 | 16 | constructor(adaptor: TonAdaptor, keypair?: KeyPair) { 17 | super(adaptor.client) 18 | if (keypair) { 19 | this.#publicKey = keypair.publicKey 20 | this.#secretKey = keypair.secretKey 21 | this.#wallet = WalletContractV4.create({ workchain: 0, publicKey: keypair.publicKey }) 22 | this.#walletContract = adaptor.client.open(this.#wallet) 23 | this.#walletSender = this.#walletContract.sender(keypair.secretKey) 24 | this.#address = this.#wallet.address 25 | } 26 | } 27 | 28 | get pubkey(): Buffer { 29 | return this.#publicKey 30 | } 31 | 32 | get address(): string { 33 | return this.#address.toString({ bounceable: false }) 34 | } 35 | 36 | async transfer(to: string, value: bigint) { 37 | return this.sendTransaction({ to, value }) 38 | } 39 | 40 | async sendTransaction(data: { to: string, value: bigint, body?: Cell, swapId?: string }) { 41 | const seqno = await this.#walletContract.getSeqno() 42 | const transfer = this.#wallet.createTransfer({ 43 | seqno, 44 | secretKey: this.#secretKey, 45 | messages: [internal(data)] 46 | }) 47 | const msg = external({ to: this.#address, init: null, body: transfer }) 48 | const cell = beginCell().store(storeMessage(msg)).endCell() 49 | const hash = cell.hash().toString('hex') 50 | await this.client.sendFile(cell.toBoc()) 51 | return { 52 | hash, 53 | wait: (_: number) => this.waitForTransaction(hash), 54 | } 55 | } 56 | } 57 | 58 | export class TonExtWallet extends TonWallet { 59 | readonly ext: any 60 | 61 | constructor(adaptor: TonAdaptor, ext) { 62 | super(adaptor) 63 | this.ext = ext 64 | } 65 | 66 | get address() { 67 | return this.ext?.currentAccount?.address 68 | } 69 | 70 | async sendTransaction(data: { to: string, value: bigint, body?: Cell, swapId?: string }) { 71 | const submitTs = Math.floor(Date.now() / 1e3) 72 | const hash = await this.ext?.sendTransaction({ 73 | validUntil: submitTs + 120, 74 | messages: [ 75 | { 76 | address: data.to.toString(), 77 | amount: data.value.toString(), 78 | payload: data.body?.toBoc().toString('base64'), 79 | } 80 | ] 81 | }) 82 | return { 83 | hash, 84 | wait: () => this.waitForTransaction(hash), 85 | } 86 | } 87 | 88 | async deploy(): Promise { 89 | throw new Error('Cannot deploy with extention wallet') 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC20Minimal.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Minimal ERC20 interface for Uniswap 5 | /// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3 6 | interface IERC20Minimal { 7 | /// @notice Returns the balance of a token 8 | /// @param account The account for which to look up the number of tokens it has, i.e. its balance 9 | /// @return The number of tokens held by the account 10 | function balanceOf(address account) external view returns (uint256); 11 | 12 | /// @notice Transfers the amount of token from the `msg.sender` to the recipient 13 | /// @param recipient The account that will receive the amount transferred 14 | /// @param amount The number of tokens to send from the sender to the recipient 15 | /// @return Returns true for a successful transfer, false for an unsuccessful transfer 16 | function transfer(address recipient, uint256 amount) external returns (bool); 17 | 18 | /// @notice Returns the current allowance given to a spender by an owner 19 | /// @param owner The account of the token owner 20 | /// @param spender The account of the token spender 21 | /// @return The current allowance granted by `owner` to `spender` 22 | function allowance(address owner, address spender) external view returns (uint256); 23 | 24 | /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount` 25 | /// @param spender The account which will be allowed to spend a given amount of the owners tokens 26 | /// @param amount The amount of tokens allowed to be used by `spender` 27 | /// @return Returns true for a successful approval, false for unsuccessful 28 | function approve(address spender, uint256 amount) external returns (bool); 29 | 30 | /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender` 31 | /// @param sender The account from which the transfer will be initiated 32 | /// @param recipient The recipient of the transfer 33 | /// @param amount The amount of the transfer 34 | /// @return Returns true for a successful transfer, false for unsuccessful 35 | function transferFrom( 36 | address sender, 37 | address recipient, 38 | uint256 amount 39 | ) external returns (bool); 40 | 41 | /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`. 42 | /// @param from The account from which the tokens were sent, i.e. the balance decreased 43 | /// @param to The account to which the tokens were sent, i.e. the balance increased 44 | /// @param value The amount of tokens that were transferred 45 | event Transfer(address indexed from, address indexed to, uint256 value); 46 | 47 | /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes. 48 | /// @param owner The account that approved spending of its tokens 49 | /// @param spender The account for which the spending allowance was modified 50 | /// @param value The new allowance from the owner to the spender 51 | event Approval(address indexed owner, address indexed spender, uint256 value); 52 | } -------------------------------------------------------------------------------- /scripts/lib/deploy.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat') 2 | const { Wallet: ZkWallet } = require('zksync-web3') 3 | const { Deployer } = require('@matterlabs/hardhat-zksync-deploy') 4 | 5 | const { adaptors } = require('@mesonfi/sdk') 6 | const { meson } = require('@mesonfi/base') 7 | 8 | exports.deployMeson = async function deployMeson(wallet, upgradable, premiumManager, tokens) { 9 | let mesonContract 10 | if (upgradable === 2) { 11 | console.log('Deploying Proxy2ToMeson & UpgradableMeson...') 12 | const impl = await deployContract('UpgradableMeson', wallet, []) 13 | const proxy = await deployContract('Proxy2ToMeson', wallet, [impl.address, premiumManager]) 14 | mesonContract = adaptors.getContract(proxy.address, meson.ABI.Meson, wallet) 15 | } else if (upgradable) { 16 | console.log('Deploying ProxyToMeson & UpgradableMeson...') 17 | const proxy = await deployContract('ProxyToMeson', wallet, [premiumManager]) 18 | mesonContract = adaptors.getContract(proxy.address, meson.ABI.Meson, wallet) 19 | } else { 20 | console.log('Deploying Meson...') 21 | mesonContract = await deployContract('Meson', wallet, [premiumManager]) 22 | } 23 | 24 | await new Promise(resolve => setTimeout(resolve, 2000)) 25 | 26 | console.log('Adding supported tokens', tokens) 27 | const tx = await mesonContract.addMultipleSupportedTokens(tokens.map(t => t.addr), tokens.map(t => t.tokenIndex)) 28 | await tx.wait(1) 29 | return mesonContract 30 | } 31 | 32 | async function deployContract(name, wallet, args = []) { 33 | if (wallet instanceof ZkWallet) { 34 | return await deployZkContract(name, wallet, args) 35 | } else if (wallet instanceof ethers.Wallet) { 36 | return await deployEtherContract(name, wallet, args) 37 | } else { 38 | return await deployTronContract(name, wallet, args) 39 | } 40 | } 41 | exports.deployContract = deployContract 42 | 43 | async function deployZkContract(name, wallet, args) { 44 | const deployer = new Deployer(hre, wallet) 45 | const artifact = await deployer.loadArtifact(name) 46 | const instance = await deployer.deploy(artifact, args) 47 | console.log(`${name} deployed to:`, instance.address) 48 | return instance 49 | } 50 | 51 | async function deployEtherContract(name, wallet, args) { 52 | const factory = await ethers.getContractFactory(name, wallet) 53 | const instance = await factory.deploy(...args) 54 | await instance.deployed() 55 | console.log(`${name} deployed to:`, instance.address) 56 | return instance 57 | } 58 | 59 | async function deployTronContract(name, wallet, args) { 60 | const factory = await ethers.getContractFactory(name) 61 | const abi = JSON.parse(factory.interface.format('json')) 62 | const constructor = abi.find(({ type }) => type === 'constructor') 63 | if (constructor) { 64 | constructor.stateMutability = constructor.payable ? 'payable' : 'nonpayable' 65 | } 66 | const deployed = await wallet.tronWeb.contract().new({ 67 | abi, 68 | bytecode: factory.bytecode, 69 | feeLimit: 5000_000000, 70 | callValue: 0, 71 | parameters: args 72 | }) 73 | const instance = adaptors.getContract(deployed.address, abi, wallet) 74 | console.log(`${name} deployed to:`, instance.address) 75 | return instance 76 | } 77 | -------------------------------------------------------------------------------- /packages/client/src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file index 3 | */ 4 | import type { BigNumber } from '@ethersproject/bignumber' 5 | import { 6 | IMesonFailoverNetworkClient, IMesonNetworkClient, 7 | IMesonWallet, 8 | IMesonWalletWithExtension, 9 | MesonData, 10 | WithProvider, 11 | } from '@mesonfi/adaptors' 12 | import { 13 | ERC20Contract, IMesonBalance, 14 | IMesonNetwork, 15 | MesonAddressFormat, 16 | MesonContract, 17 | } from '@mesonfi/base' 18 | import type { CallOverrides } from 'ethers' 19 | 20 | export interface IMesonTokenWithAddress { 21 | tokenIndex: number 22 | addr: string 23 | } 24 | 25 | export interface IMesonClient { 26 | readonly mesonInstance: WithProvider 27 | readonly provider: IMesonFailoverNetworkClient 28 | readonly network: IMesonNetwork 29 | readonly networkId: string 30 | readonly addressFormat: T 31 | readonly address: string 32 | 33 | ready(overrides?: CallOverrides): Promise 34 | 35 | getTokenBalance(addr: string, tokenIndex: number): Promise 36 | 37 | getBalance(addr: string): Promise 38 | 39 | getBalanceInPool(owner: string, tokenIndex: number): Promise 40 | 41 | getTokenContract(tokenAddr: string): WithProvider 42 | 43 | getAllowance(address: string, tokenIndex: number): Promise 44 | 45 | formatAddress(addr: string): string 46 | 47 | serviceFeeCollected(tokenIndex: number, overrides?: CallOverrides): Promise 48 | 49 | ownerOfPool(poolIndex: number, overrides?: CallOverrides): Promise 50 | } 51 | 52 | export interface IMesonClients { 53 | 54 | isAddress(addressFormat: MesonAddressFormat, address: string): boolean 55 | 56 | formatAddress(addressFormat: MesonAddressFormat, address: string): string 57 | 58 | clipRecipient(addressFormat: MesonAddressFormat, recipient: string): string 59 | 60 | getFailoverNetworkClient(networkId: string, force?: boolean): IMesonFailoverNetworkClient 61 | 62 | getNetworkClient(networkId: string, url?: string): IMesonNetworkClient 63 | 64 | getWalletByPrivateKey(privateKey: string, networkId: string): IMesonWallet 65 | 66 | getWalletFromExtension(ext: MesonData, networkId: string): IMesonWalletWithExtension 67 | 68 | getMesonInstance(networkId: string): WithProvider 69 | 70 | getERC20Instance(tokenAddr: string, networkId: string): WithProvider 71 | 72 | getMesonClient(networkId: string): IMesonClient 73 | 74 | getMesonInstanceByWallet(wallet: IMesonWallet | IMesonWalletWithExtension): WithProvider 75 | 76 | getERC20InstanceByWallet(address: string, wallet: IMesonWallet | IMesonWalletWithExtension): WithProvider 77 | 78 | getMesonClientByWallet(wallet: IMesonWallet | IMesonWalletWithExtension): IMesonClient 79 | } 80 | -------------------------------------------------------------------------------- /packages/rpc/src/MesonRpcMonitor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file RpcMonitor 3 | */ 4 | import { 5 | meson, 6 | MesonNetworkStatus, 7 | IMesonPresets, 8 | } from '@mesonfi/base' 9 | import { adaptors } from '@mesonfi/adaptors' 10 | import { MesonRpcStatusCache } from './MesonRpcStatusCache' 11 | import { IMesonRpcs } from './types' 12 | 13 | export interface MesonRpcMonitorOptions { 14 | getRpcURLs: () => Record 15 | presets: IMesonPresets 16 | } 17 | 18 | export class MesonRpcMonitor extends MesonRpcStatusCache implements IMesonRpcs { 19 | 20 | protected getRpcURLs: () => Record 21 | protected presets: IMesonPresets 22 | 23 | constructor (options: MesonRpcMonitorOptions) { 24 | super() 25 | this.getRpcURLs = options.getRpcURLs 26 | this.presets = options.presets 27 | } 28 | 29 | // internal methods, use for meson and free 30 | public setAllRpcStatus (map: Record): void { 31 | for (const [networkId, data] of Object.entries(map)) { 32 | this.update(networkId, data) 33 | } 34 | 35 | this.setReady() 36 | } 37 | 38 | public async refreshAllRpcStatus (): Promise { 39 | try { 40 | this.setAllRpcStatus(await this.fetchRpcs()) 41 | } catch (err) { 42 | console.error(err) 43 | } 44 | } 45 | 46 | public async fetchRpcs (): Promise> { 47 | const map = this.getRpcURLs() 48 | 49 | const tasks = Object.keys(map) 50 | .filter(item => this.presets.hasNetwork(item)) 51 | .map(async networkId => { 52 | const network = this.presets.getNetworkByNetworkId(networkId) 53 | const urls = map[networkId] || [] 54 | 55 | if (!map[networkId].length) { 56 | urls.push(network.url) 57 | } 58 | 59 | const status = await Promise.all(urls.map(async url => { 60 | return this.getStatus(networkId, url) 61 | })) 62 | 63 | return [networkId, status] as const 64 | }).flat(1) 65 | 66 | return Object.fromEntries(await Promise.all(tasks)) 67 | } 68 | 69 | protected async getStatus (networkId: string, url: string): Promise { 70 | 71 | const network = this.presets.getNetworkByNetworkId(networkId) 72 | const { NetworkClient } = adaptors.getAdaptorConfig(network.addressFormat) 73 | const networkClient = new NetworkClient(url, network, adaptors.getWebSocketConstructor()) 74 | 75 | try { 76 | 77 | const startTime = Date.now() 78 | const block = await networkClient.getBlockInfo() 79 | const endTime = Date.now() 80 | const gasPrice = await networkClient.getGasPrice() 81 | 82 | return { 83 | url, 84 | networkId: networkClient.networkId, 85 | addressFormat: networkClient.addressFormat, 86 | healthy: true, 87 | latency: endTime - startTime, 88 | ...block, 89 | gasPrice: gasPrice.toString(), 90 | } 91 | } catch (error) { 92 | return { 93 | url, 94 | networkId: networkClient.networkId, 95 | addressFormat: networkClient.addressFormat, 96 | healthy: false, 97 | error: meson.getErrorMessage(error), 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /contracts/Token/UCTUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; 5 | import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; 6 | 7 | /// @title UCTUpgradeable 8 | /// @notice The contract of UCT, a token minted by Meson for promotional events 9 | /// UCT (USD Coupon Token) is issued by Meson team to mark participants for 10 | /// community events (such as airdrops, cashbacks, etc). UCT is not an asset 11 | /// and it has no value. UCT obtained directly from Meson during the event period 12 | /// can be redeemed for the actual USDT/USDC rewards on https://meson.fi/ at 13 | /// a ratio of 100:1. UCT has no usage other than redemption for USDT/USDC, 14 | /// and all UCTs will be destroyed at the end of the event. 15 | contract UCTUpgradeable is UUPSUpgradeable, ERC20Upgradeable { 16 | address private _owner; 17 | address private _minter; 18 | address private _mesonContract; 19 | 20 | function initialize(address minter, address mesonContract) public initializer { 21 | __ERC20_init("USD Coupon Token (https://meson.fi)", "UCT"); 22 | _owner = _msgSender(); 23 | _minter = minter; 24 | require(mesonContract != address(0), "Address of meson contract cannot be zero"); 25 | _mesonContract = mesonContract; 26 | } 27 | 28 | function decimals() public pure override returns (uint8) { 29 | return 4; 30 | } 31 | 32 | function batchMint(address[] memory targets, uint256 amount) external onlyMinter { 33 | require(targets.length > 0, "Target array is empty"); 34 | require(targets.length < 2048, "Target array is too large"); 35 | for (uint i = 0; i < targets.length; i++) { 36 | _mint(targets[i], amount); 37 | } 38 | } 39 | 40 | function batchMint2(address[] memory targets, uint256[] memory amounts) external onlyMinter { 41 | require(targets.length > 0, "Target array is empty"); 42 | require(targets.length < 2048, "Target array is too large"); 43 | require(targets.length == amounts.length, "Targets and amounts should have the same length"); 44 | for (uint i = 0; i < targets.length; i++) { 45 | _mint(targets[i], amounts[i]); 46 | } 47 | } 48 | 49 | function _authorizeUpgrade(address) internal view override { 50 | require(_msgSender() == _owner, "Unauthorized"); 51 | } 52 | 53 | /// @notice Override the default ERC20 allowance method 54 | /// mesonContract will have max allowance so users don't need to execute approve 55 | function allowance(address owner, address spender) public view override returns (uint256) { 56 | if (spender == _mesonContract) { 57 | uint256 x = 0; 58 | unchecked { x--; } 59 | return x; 60 | } 61 | return ERC20Upgradeable.allowance(owner, spender); 62 | } 63 | 64 | function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) { 65 | address msgSender = _msgSender(); 66 | if (msgSender == _mesonContract && ERC20Upgradeable.allowance(sender, msgSender) < amount) { 67 | uint256 x = 0; 68 | unchecked { x--; } 69 | _approve(sender, msgSender, x); 70 | } 71 | return ERC20Upgradeable.transferFrom(sender, recipient, amount); 72 | } 73 | 74 | modifier onlyOwner() { 75 | require(_owner == _msgSender(), "Caller is not the owner"); 76 | _; 77 | } 78 | 79 | modifier onlyMinter() { 80 | require(_minter == _msgSender(), "Caller is not the owner"); 81 | _; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /scripts/estimate-gas.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat') 2 | const { 3 | MesonClient, 4 | EthersWalletSwapSigner, 5 | SignedSwapRequest, 6 | SignedSwapRelease, 7 | } = require('@mesonfi/sdk') 8 | 9 | const { deployContract, deployMeson } = require('./lib/deploy') 10 | const { wallet: unconnectedWallet } = require('../test/shared/wallet') 11 | const { getPartialSwap } = require('../test/shared/meson') 12 | 13 | const testnetMode = true 14 | 15 | module.exports = async function main(upgradable) { 16 | const wallet = unconnectedWallet.connect(ethers.provider) 17 | const swapSigner = new EthersWalletSwapSigner(wallet) 18 | 19 | const totalSupply = ethers.utils.parseUnits('10000', 6) 20 | const tokenContract = await deployContract('MockToken', wallet, ['Mock Token', 'MT', totalSupply, 6]) 21 | 22 | const tokenIndex = 1 23 | const tokens = [{ addr: tokenContract.address, tokenIndex }] 24 | const mesonContract = await deployMeson(wallet, !!upgradable, wallet.address, tokens) 25 | const mesonClient = await MesonClient.Create(mesonContract, swapSigner) 26 | 27 | // approve 28 | const approveTx = await tokenContract.approve(mesonContract.address, totalSupply) 29 | getUsedGas('approve', approveTx.hash) 30 | await approveTx.wait(1) 31 | 32 | // deposits 33 | const amount = ethers.utils.parseUnits('1000', 6) 34 | const depositTx1 = await mesonClient.depositAndRegister(tokenIndex, amount, '1') 35 | getUsedGas('first deposit', depositTx1.hash) 36 | await depositTx1.wait(1) 37 | 38 | const depositTx2 = await mesonClient.deposit(tokenIndex, amount) 39 | getUsedGas('another deposit', depositTx2.hash) 40 | await depositTx2.wait(1) 41 | 42 | // requestSwap (no gas) 43 | const swapData = getPartialSwap() 44 | const outChain = await mesonContract.getShortCoinType() 45 | const swap = mesonClient.requestSwap(swapData, outChain) 46 | const request = await swap.signForRequest(testnetMode) 47 | const signedRequest = new SignedSwapRequest(request) 48 | signedRequest.checkSignature(testnetMode) 49 | 50 | const swapData2 = getPartialSwap({ amount: ethers.utils.parseUnits('500', 6) }) 51 | const swap2 = mesonClient.requestSwap(swapData2, outChain) 52 | const request2 = await swap2.signForRequest(testnetMode) 53 | const signedRequest2 = new SignedSwapRequest(request2) 54 | signedRequest2.checkSignature(testnetMode) 55 | 56 | // postSwap 57 | const postSwapTx1 = await mesonClient.postSwap(signedRequest) 58 | getUsedGas('first postSwap', postSwapTx1.hash) 59 | await postSwapTx1.wait(1) 60 | 61 | const postSwapTx2 = await mesonClient.postSwap(signedRequest2) 62 | getUsedGas('another postSwap', postSwapTx2.hash) 63 | await postSwapTx2.wait(1) 64 | 65 | // lock 66 | const lockTx = await mesonClient.lock(signedRequest) 67 | getUsedGas('lock', lockTx.hash) 68 | await lockTx.wait(1) 69 | 70 | // export release signature 71 | const release = await swap.signForRelease(swapData.recipient, testnetMode) 72 | const signedRelease = new SignedSwapRelease(release) 73 | signedRelease.checkSignature(testnetMode) 74 | 75 | // release 76 | const releaseTx = await mesonClient.release(signedRelease) 77 | getUsedGas('release', releaseTx.hash) 78 | 79 | // executeSwap 80 | const executeTx = await mesonClient.executeSwap(signedRelease, true) 81 | await getUsedGas('execute', executeTx.hash) 82 | } 83 | 84 | async function getUsedGas(name, hash) { 85 | return ethers.provider.getTransactionReceipt(hash).then((receipt) => { 86 | console.log(name, ':', receipt.cumulativeGasUsed.toString()) 87 | }) 88 | } 89 | -------------------------------------------------------------------------------- /contracts/test/MesonStatesTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.28; 3 | 4 | import "../utils/MesonStates.sol"; 5 | 6 | contract MesonStatesTest is MesonStates { 7 | function addSupportToken(address token, uint8 index) external { 8 | _addSupportToken(token, index); 9 | } 10 | 11 | function encodeSwap( 12 | uint8 version, 13 | uint40 amount, 14 | uint80 salt, 15 | uint40 fee, 16 | uint40 expireTs, 17 | bytes2 outChain, 18 | uint8 outToken, 19 | bytes2 inChain, 20 | uint8 inToken 21 | ) external pure returns (bytes memory) { 22 | return 23 | abi.encodePacked( 24 | version, 25 | amount, 26 | salt, 27 | fee, 28 | expireTs, 29 | outChain, 30 | outToken, 31 | inChain, 32 | inToken 33 | ); 34 | } 35 | 36 | function decodeSwap(uint256 encodedSwap, uint40 poolIndex) external pure returns ( 37 | uint8 version, 38 | uint256 amount, 39 | uint256 feeForLp, 40 | uint256 serviceFee, 41 | uint80 salt, 42 | uint256 expireTs, 43 | bytes2 inChain, 44 | uint8 inTokenIndex, 45 | bytes2 outChain, 46 | uint8 outTokenIndex, 47 | bytes6 poolTokenIndexForOutToken 48 | ) { 49 | version = _versionFrom(encodedSwap); 50 | amount = _amountFrom(encodedSwap); 51 | feeForLp = _feeForLp(encodedSwap); 52 | serviceFee = _serviceFee(encodedSwap); 53 | salt = _saltFrom(encodedSwap); 54 | expireTs = _expireTsFrom(encodedSwap); 55 | inChain = bytes2(_inChainFrom(encodedSwap)); 56 | inTokenIndex = _inTokenIndexFrom(encodedSwap); 57 | outChain = bytes2(_outChainFrom(encodedSwap)); 58 | outTokenIndex = _outTokenIndexFrom(encodedSwap); 59 | poolTokenIndexForOutToken = bytes6(_poolTokenIndexForOutToken(encodedSwap, poolIndex)); 60 | } 61 | 62 | function decodePostedSwap(uint200 postedSwap) external pure returns ( 63 | address initiator, 64 | uint40 poolIndex 65 | ) { 66 | initiator = _initiatorFromPosted(postedSwap); 67 | poolIndex = _poolIndexFromPosted(postedSwap); 68 | } 69 | 70 | function lockedSwapFrom(uint256 until, uint40 poolIndex) external pure returns (uint80) { 71 | return _lockedSwapFrom(until, poolIndex); 72 | } 73 | 74 | function decodeLockedSwap(uint80 lockedSwap) external pure returns (uint40 poolIndex, uint256 until) { 75 | poolIndex = _poolIndexFromLocked(lockedSwap); 76 | until = _untilFromLocked(lockedSwap); 77 | } 78 | 79 | function poolTokenIndexFrom(uint8 tokenIndex, uint40 poolIndex) external pure returns (bytes6) { 80 | return bytes6(_poolTokenIndexFrom(tokenIndex, poolIndex)); 81 | } 82 | 83 | function decodePoolTokenIndex(uint48 poolTokenIndex) external pure returns ( 84 | uint8 tokenIndex, 85 | uint40 poolIndex 86 | ) { 87 | tokenIndex = _tokenIndexFrom(poolTokenIndex); 88 | poolIndex = _poolIndexFrom(poolTokenIndex); 89 | } 90 | 91 | function checkRequestSignature( 92 | uint256 encodedSwap, 93 | bytes32 r, 94 | bytes32 yParityAndS, 95 | address signer 96 | ) external pure { 97 | _checkRequestSignature(encodedSwap, r, yParityAndS, signer); 98 | } 99 | 100 | function checkReleaseSignature( 101 | uint256 encodedSwap, 102 | address recipient, 103 | bytes32 r, 104 | bytes32 yParityAndS, 105 | address signer 106 | ) external pure { 107 | _checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, signer); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /packages/adaptors/src/ethers/client.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file client 3 | */ 4 | import { BigNumber } from '@ethersproject/bignumber' 5 | import { errors, providers } from 'ethers' 6 | import { Provider as ZkProvider } from 'zksync-web3' 7 | 8 | import { IMesonNetwork } from '@mesonfi/base' 9 | import { MesonNetworkClientBase } from '../MesonNetworkClientBase' 10 | 11 | import { MesonData, WebSocketConstructor } from '../types' 12 | import { IMesonEthersNetworkClient } from './type' 13 | 14 | // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging 15 | export class EthersNetworkClient extends MesonNetworkClientBase<'ethers'> implements IMesonEthersNetworkClient { 16 | 17 | public readonly nodeUrl: string 18 | 19 | constructor (url: string, network: IMesonNetwork, WebSocket: WebSocketConstructor | null) { 20 | 21 | super(url, network) 22 | this.nodeUrl = url 23 | return this.initProviders(network, WebSocket) 24 | } 25 | 26 | public async sendTransaction (signedTransaction: string | Promise): Promise { 27 | return new Promise((resolve, reject) => { 28 | 29 | const h = setTimeout(() => { 30 | console.log('tx_timeout') 31 | reject(new Error('Time out')) 32 | }, 30_000) 33 | 34 | this.callSuper('sendTransaction', signedTransaction).then(res => { 35 | clearTimeout(h) 36 | resolve(res) 37 | }).catch(reject) 38 | }) 39 | } 40 | 41 | public async perform (method: string, params: MesonData) { 42 | try { 43 | return await this.callSuper('perform', method, params) 44 | } catch (e) { 45 | if (e.code === errors.CALL_EXCEPTION) { 46 | e.code = errors.SERVER_ERROR 47 | } 48 | throw e 49 | } 50 | } 51 | 52 | public async getBlockInfo () { 53 | 54 | const latestBlockResp = await this.send('eth_getBlockByNumber', ['latest', false]) 55 | 56 | return { 57 | lastBlockNumber: Number(latestBlockResp.number).toString(), 58 | lastBlockTimestamp: Number(latestBlockResp.timestamp).toString(), 59 | } 60 | } 61 | 62 | public getBlockNumber (): Promise { 63 | return this.callSuper('getBlockNumber') 64 | } 65 | 66 | public getBalance (addr: string): Promise { 67 | return this.callSuper('getBalance', addr) 68 | } 69 | 70 | private initProviders (network: IMesonNetwork, WebSocket: WebSocketConstructor | null) { 71 | 72 | const url = this.configUrl 73 | const providerNetwork = { name: network.name, chainId: Number(network.chainId) } 74 | 75 | if (url.startsWith('ws')) { 76 | const socketUrl = WebSocket ? new WebSocket(url) : url 77 | return this.inherit(providers.WebSocketProvider, [socketUrl, providerNetwork]) 78 | } 79 | 80 | const connectionInfo = { 81 | url, 82 | timeout: 10_000, 83 | throttleLimit: 3, 84 | throttleCallback: async (attempt: number, url: string) => { 85 | console.log('[429]', url, attempt) 86 | return true 87 | }, 88 | } 89 | 90 | if (network.id.startsWith('zksync') || network.id.startsWith('zklink')) { 91 | return this.inherit(ZkProvider, [connectionInfo, providerNetwork]) 92 | } 93 | 94 | return this.inherit(providers.StaticJsonRpcProvider, [connectionInfo, providerNetwork]) 95 | } 96 | } 97 | 98 | // eslint-disable-next-line @typescript-eslint/no-empty-object-type,@typescript-eslint/no-unsafe-declaration-merging 99 | export interface EthersNetworkClient extends IMesonEthersNetworkClient { 100 | } 101 | -------------------------------------------------------------------------------- /packages/clients/src/MesonClients.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MesonClients 3 | */ 4 | 5 | import { MesonClient } from '@mesonfi/sdk' 6 | import { type IMesonRpcs, rpcs } from '@mesonfi/rpc' 7 | import presets, { MesonPresets } from '@mesonfi/presets' 8 | 9 | export type WebSocketConstructor = new (url: string) => WebSocket; 10 | 11 | export interface MesonClientManagerOptions { 12 | rpcManagerURL: string 13 | WebSocket: WebSocketConstructor 14 | presets?: MesonPresets 15 | } 16 | 17 | export class MesonClientManager { 18 | private cache: Record = {} 19 | 20 | private presets: MesonPresets = presets 21 | 22 | private rpcManagerURL: string | null = null 23 | 24 | private WebSocketConstructor?: WebSocketConstructor 25 | 26 | private rpcs: IMesonRpcs | null = null 27 | 28 | public getClient (networkId: string, force = false): MesonClient { 29 | if (this.cache[networkId] && !force) { 30 | return this.cache[networkId] 31 | } 32 | 33 | const client = this.createMesonClient(networkId) 34 | 35 | if (!force) { 36 | this.cache[networkId] = client 37 | } 38 | 39 | return client 40 | } 41 | 42 | public getRpcs (): IMesonRpcs { 43 | if (!this.rpcs) { 44 | throw new Error('call init method first') 45 | } 46 | 47 | return this.rpcs 48 | } 49 | 50 | public async init (options: MesonClientManagerOptions) { 51 | const { rpcManagerURL, WebSocket } = options 52 | 53 | this.WebSocketConstructor = WebSocket 54 | this.presets = options.presets || presets 55 | 56 | if (rpcManagerURL !== this.rpcManagerURL) { 57 | this.rpcManagerURL = rpcManagerURL 58 | this.rpcs = new rpcs.Rpcs(rpcManagerURL) 59 | 60 | await this.refreshAllRpcStatus() 61 | } 62 | } 63 | 64 | public async refreshAllRpcStatus (): Promise { 65 | const rpcs = this.rpcs 66 | 67 | if (!rpcs) { 68 | throw new Error('call init method first') 69 | } 70 | 71 | await rpcs.refreshAllRpcStatus() 72 | 73 | const WebSocket = this.getWebSocketConstructor() 74 | 75 | Object.keys(this.cache).forEach(networkId => { 76 | const urls = rpcs.getHealthyRpcStatus(networkId).map(item => item.url).filter(Boolean) 77 | 78 | if (urls.length > 0) { 79 | Object.assign(this.cache[networkId], { 80 | wallet: this.presets.createFailoverAdaptor(networkId, urls, { WebSocket, threshold: 1 }), 81 | }) 82 | } 83 | }) 84 | } 85 | 86 | protected getWebSocketConstructor (): WebSocketConstructor { 87 | if (!this.WebSocketConstructor) { 88 | throw new Error('WebSocketConstructor is not registered') 89 | } 90 | 91 | return this.WebSocketConstructor 92 | } 93 | 94 | protected createMesonClient (networkId: string): MesonClient { 95 | const network = this.presets.getNetwork(networkId) 96 | 97 | let urls: string[] = network.url ? [network.url] : [] 98 | if (this.rpcs) { 99 | const rpcStatusObject = this.rpcs.getHealthyRpcStatus(networkId) 100 | const rpcUrls = rpcStatusObject.map(status => status.url).filter(Boolean) 101 | 102 | if (rpcUrls.length > 0) { 103 | urls = rpcUrls 104 | } 105 | } 106 | 107 | if (!urls.length) { 108 | throw new Error('no client url was found') 109 | } 110 | 111 | const adaptor = this.presets.createFailoverAdaptor(networkId, urls, { 112 | WebSocket: this.getWebSocketConstructor(), 113 | threshold: 1, 114 | }) 115 | 116 | return this.presets.createMesonClient(networkId, adaptor) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /packages/adaptors/src/aptos/wallet.ts: -------------------------------------------------------------------------------- 1 | import { utils } from 'ethers' 2 | import { Account as AptosAccount, Ed25519PrivateKey } from '@aptos-labs/ts-sdk' 3 | import { MesonData } from '../types' 4 | import { 5 | IMesonAptosFailoverNetworkClient, 6 | IMesonAptosWallet, 7 | IMesonAptosWalletWithExtension, 8 | } from './type' 9 | 10 | export class AptosWallet implements IMesonAptosWallet { 11 | 12 | public static fromPrivateKey (privateKey: string, client: IMesonAptosFailoverNetworkClient): IMesonAptosWallet { 13 | if (privateKey && !privateKey.startsWith('0x')) { 14 | privateKey = '0x' + privateKey 15 | } 16 | const key = new Ed25519PrivateKey(privateKey) 17 | const signer = AptosAccount.fromPrivateKey({ privateKey: key }) 18 | return new AptosWallet(client, signer) 19 | } 20 | 21 | public readonly networkClient: IMesonAptosFailoverNetworkClient 22 | 23 | public readonly addressFormat = 'aptos' 24 | 25 | readonly account: AptosAccount 26 | 27 | constructor (client: IMesonAptosFailoverNetworkClient, account: AptosAccount) { 28 | this.networkClient = client 29 | this.account = account 30 | } 31 | 32 | get address (): string { 33 | return this.account.accountAddress.toString() 34 | } 35 | 36 | signMessage (msg: string) { 37 | return this.account.sign(utils.toUtf8Bytes(msg)).toString() 38 | } 39 | 40 | async sendTransaction (payload, options) { 41 | const transaction = await this.networkClient.transaction.build.simple({ 42 | sender: this.address, 43 | data: { 44 | function: payload.function, 45 | functionArguments: payload.arguments, 46 | typeArguments: payload.type_arguments, 47 | }, 48 | }) 49 | const tx = await this.networkClient.signAndSubmitTransaction({ signer: this.account, transaction }) 50 | 51 | return { 52 | hash: utils.hexZeroPad(tx.hash, 32), 53 | wait: () => this.networkClient.waitForTransaction(tx.hash), 54 | } 55 | } 56 | 57 | async deploy (module: string, metadata: string) { 58 | // let hash = await this.client.publishPackage( 59 | // this.account, 60 | // new HexString(metadata).toUint8Array(), 61 | // [new TxnBuilderTypes.Module(new HexString(module).toUint8Array())] 62 | // ) 63 | // hash = utils.hexZeroPad(hash, 32) 64 | 65 | // return { 66 | // hash, 67 | // wait: () => this.waitForTransaction(hash) 68 | // } 69 | } 70 | } 71 | 72 | export class AptosExtWallet extends AptosWallet implements IMesonAptosWalletWithExtension { 73 | 74 | public static fromExtension (ext: MesonData, client: IMesonAptosFailoverNetworkClient): IMesonAptosWalletWithExtension { 75 | return new AptosExtWallet(client, ext) 76 | } 77 | 78 | readonly ext: MesonData 79 | 80 | constructor (client: IMesonAptosFailoverNetworkClient, ext: MesonData) { 81 | super(client, null) 82 | this.ext = ext 83 | } 84 | 85 | get address () { 86 | // TODO: might be different for different exts 87 | return this.ext.signer.account() as string 88 | } 89 | 90 | async sendTransaction (payload, options) { 91 | // This method is provided by `@manahippo/aptos-wallet-adapter` 92 | const tx = await this.ext.signer.signAndSubmitTransaction(payload, options) 93 | // TODO: error handling 94 | return { 95 | hash: utils.hexZeroPad(tx.hash, 32), 96 | wait: () => this.networkClient.waitForTransaction(tx.hash), 97 | } 98 | } 99 | 100 | async deploy (): Promise { 101 | throw new Error('Cannot deploy with extension wallet') 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /packages/sdk/src/adaptors/starknet/StarkWallet.ts: -------------------------------------------------------------------------------- 1 | import { utils } from 'ethers' 2 | import { 3 | Account as StarkAccount, 4 | CallData, 5 | ec, 6 | hash, 7 | constants, 8 | CairoCustomEnum, 9 | CairoOption, 10 | CairoOptionVariant, 11 | } from 'starknet' 12 | import StarkAdaptor from './StarkAdaptor' 13 | 14 | const AX_ACCOUNT_CLASSHASH = '0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f' 15 | 16 | export default class StarkWallet extends StarkAdaptor { 17 | readonly #privateKey: string 18 | readonly publicKey: string 19 | readonly #calldata: string[] 20 | readonly address: string 21 | readonly account: StarkAccount 22 | 23 | constructor(adaptor: StarkAdaptor, opt: { privateKey?: string, account?: StarkAccount }) { 24 | super(adaptor.client) 25 | if (opt.privateKey) { 26 | this.#privateKey = opt.privateKey 27 | this.publicKey = ec.starkCurve.getStarkKey(opt.privateKey) 28 | this.#calldata = CallData.compile({ 29 | owner: new CairoCustomEnum({ Starknet: { pubkey: this.publicKey } }), 30 | guardian: new CairoOption(CairoOptionVariant.None), 31 | }) 32 | this.address = utils.hexZeroPad(hash.calculateContractAddressFromHash( 33 | this.publicKey, 34 | AX_ACCOUNT_CLASSHASH, 35 | this.#calldata, 36 | 0 37 | ), 32) 38 | this.account = new StarkAccount({ 39 | nodeUrl: adaptor.nodeUrl 40 | }, this.address, opt.privateKey, undefined, constants.TRANSACTION_VERSION.V3) 41 | } else if (opt.account) { 42 | this.account = opt.account 43 | this.address = utils.hexZeroPad(this.account.address, 32) 44 | } 45 | } 46 | 47 | async deploy() { 48 | const tx = await this.account.deployAccount({ 49 | classHash: AX_ACCOUNT_CLASSHASH, 50 | constructorCalldata: this.#calldata, 51 | contractAddress: this.address, 52 | addressSalt: this.publicKey, 53 | }) 54 | return { 55 | hash: tx.transaction_hash, 56 | wait: (confirmations: number) => this.waitForTransaction(tx.transaction_hash, confirmations) 57 | } 58 | } 59 | 60 | async transfer({ to, value }) { 61 | this._coreToken.connect(this.account) 62 | const tx = await this._coreToken.transfer(to, value) 63 | this._coreToken.connect(null) 64 | return { 65 | hash: tx.transaction_hash, 66 | wait: (confirmations: number) => this.waitForTransaction(tx.transaction_hash, confirmations) 67 | } 68 | } 69 | 70 | async sendTransaction({ instance, method, args }) { 71 | const tx = await instance[method](...args) 72 | return { 73 | hash: tx.transaction_hash, 74 | wait: (confirmations: number) => this.waitForTransaction(tx.transaction_hash, confirmations) 75 | } 76 | } 77 | 78 | async signMessage(msg: string) { 79 | let signData: Uint8Array 80 | if (utils.isHexString(msg)) { 81 | signData = utils.arrayify(msg) 82 | } else { 83 | signData = utils.toUtf8Bytes(msg) 84 | } 85 | const msgHash = hash.computeHashOnElements([...signData]) 86 | const { r, s, recovery } = ec.starkCurve.sign(msgHash, this.#privateKey) 87 | return utils.splitSignature({ r: utils.hexlify(r), s: utils.hexlify(s), recoveryParam: recovery }).compact 88 | } 89 | } 90 | 91 | export class StarkExtWallet extends StarkWallet { 92 | readonly ext: any 93 | 94 | constructor(adaptor: StarkAdaptor, ext) { 95 | super(adaptor, { account: ext?.connection?.wallet?.account }) 96 | this.ext = ext 97 | } 98 | 99 | async deploy(): Promise { 100 | throw new Error('Cannot deploy with extention wallet') 101 | } 102 | } 103 | --------------------------------------------------------------------------------