├── .changeset └── config.json ├── .github ├── CODEOWNERS └── workflows │ ├── publish.yml │ └── tests.yml ├── .gitignore ├── .gitmodules ├── README.md ├── local_vendor ├── OPinit │ └── proto │ │ └── opinit │ │ └── ophost │ │ └── v1 │ │ ├── tx.proto │ │ └── types.proto └── initia │ └── proto │ └── initia │ └── move │ └── v1 │ └── tx.proto ├── package-lock.json ├── package.json ├── packages ├── core │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── CHANGELOG.md │ ├── Makefile │ ├── README.md │ ├── e2e │ │ ├── transactions.test.ts │ │ └── utils.ts │ ├── jest.config.cjs │ ├── package.json │ ├── parser.d.ts │ ├── parser.js │ ├── scripts │ │ ├── codegen.js │ │ ├── dev-setup.sh │ │ ├── port-forward.sh │ │ └── prepublish.js │ ├── src │ │ ├── __test__ │ │ │ └── client.test.ts │ │ ├── amino │ │ │ ├── README.md │ │ │ ├── addresses.ts │ │ │ ├── encoding.ts │ │ │ ├── pubkey.ts │ │ │ └── signature.ts │ │ ├── chains.ts │ │ ├── client-types.ts │ │ ├── client.ts │ │ ├── codegen │ │ │ └── .gitkeep │ │ ├── constants │ │ │ ├── abis.ts │ │ │ └── constants.ts │ │ ├── index.ts │ │ ├── injective │ │ │ └── index.ts │ │ ├── parser.ts │ │ ├── proto-signing │ │ │ ├── README.md │ │ │ ├── directethsecp256k1wallet.ts │ │ │ ├── pubkey.ts │ │ │ └── signer.ts │ │ ├── request-client.ts │ │ ├── transactions.ts │ │ └── types │ │ │ ├── __test__ │ │ │ └── converters.test.ts │ │ │ ├── converters.ts │ │ │ ├── index.ts │ │ │ ├── lifecycle.ts │ │ │ ├── routing.ts │ │ │ ├── shared.ts │ │ │ └── unified.ts │ ├── starship │ │ ├── ci.yaml │ │ └── local.yaml │ ├── transactions.d.ts │ ├── transactions.js │ ├── tsconfig.build.json │ ├── tsconfig.json │ ├── tsup.config.ts │ ├── types.d.ts │ ├── types.js │ ├── vitest.config.mjs │ ├── vitest.e2e.config.mjs │ └── vitest.unit.config.mjs └── examples │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ └── skip-api-quickstart-example.js │ └── tsconfig.json ├── prettier.config.js ├── turbo.json └── vendor ├── index.js └── package.json /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @codingki @NotJeremyLiu 2 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | 9 | concurrency: ${{ github.workflow }}-${{ github.ref }} 10 | 11 | permissions: 12 | actions: write 13 | contents: write 14 | id-token: write 15 | pull-requests: write 16 | 17 | jobs: 18 | release: 19 | name: Release 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout Repo 23 | uses: actions/checkout@v3 24 | 25 | - name: Setup Node.js 18.x 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version: 18.x 29 | 30 | - name: Install Dependencies 31 | run: npm ci 32 | 33 | - name: Create Release Pull Request or Publish to npm 34 | id: changesets 35 | uses: changesets/action@v1 36 | with: 37 | # This expects you to have a script called release which does a build for your packages and calls changeset publish 38 | publish: yarn release 39 | env: 40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 41 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 42 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [pull_request, push] 3 | 4 | jobs: 5 | test: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout 9 | uses: actions/checkout@v3 10 | 11 | - name: Use Node 18.x 12 | uses: actions/setup-node@v3 13 | with: 14 | node-version: 18 15 | 16 | - name: Install dependencies 17 | run: npm ci 18 | 19 | - name: Generate cosmjs types 20 | run: npm run codegen 21 | working-directory: ./packages/core 22 | 23 | - name: Test 24 | run: npm test 25 | 26 | e2e-tests: 27 | runs-on: ubuntu-latest-m 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v3 31 | 32 | - name: Use Node 18.x 33 | uses: actions/setup-node@v3 34 | with: 35 | node-version: 18 36 | 37 | - name: Install dependencies 38 | run: npm ci 39 | working-directory: ./packages/core 40 | 41 | - name: Generate cosmjs types 42 | run: npm run codegen 43 | working-directory: ./packages/core 44 | 45 | - name: Setup starship 46 | run: npm run e2e:setup HELM_FILE=starship/ci.yaml 47 | working-directory: ./packages/core 48 | 49 | - name: Start starship 50 | run: make start HELM_FILE=starship/ci.yaml 51 | working-directory: ./packages/core 52 | 53 | - name: Run e2e tests 54 | run: npm run e2e:test 55 | working-directory: ./packages/core 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | .node_repl_history 4 | .npm 5 | .turbo 6 | .vscode 7 | *.log 8 | coverage 9 | dist 10 | lib 11 | main 12 | mjs 13 | module 14 | node_modules 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/cosmos-proto"] 2 | path = vendor/cosmos-proto 3 | url = https://github.com/cosmos/cosmos-proto.git 4 | 5 | [submodule "vendor/cosmos-sdk"] 6 | path = vendor/cosmos-sdk 7 | url = https://github.com/cosmos/cosmos-sdk.git 8 | 9 | [submodule "vendor/evmos"] 10 | path = vendor/evmos 11 | url = https://github.com/evmos/evmos.git 12 | 13 | [submodule "vendor/noble-cctp"] 14 | path = vendor/noble-cctp 15 | url = https://github.com/circlefin/noble-cctp.git 16 | 17 | [submodule "vendor/wasmd"] 18 | path = vendor/wasmd 19 | url = https://github.com/CosmWasm/wasmd.git 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecation Notice 2 | 3 | **⚠️ This project is deprecated** 4 | 5 | This repository is no longer actively maintained and may not receive future updates or bug fixes. Please use the now maintained and developed [@skip-go/core](https://www.npmjs.com/package/@skip-go/core) as a replacement. 6 | 7 | ## Migration Guide 8 | @skip-router/core@5.2.0 is the same as @skip-go/core@0.2.0. To migrate packages with minimal disruption, please upgrade to @skip-router/core@5.2.0 and then replace the package with @skip-go/core@0.2.0, then upgrading to the latest version from there. 9 | 10 | Thank you for your understanding and for using our software. 11 | 12 | For any questions, please reach out to us in our [discord](https://skip.build/discord) if you have any questions and/or need assistance migrating! 13 | 14 | ![header](https://files.readme.io/4f92aa7-DALLE_Cover_Photo_1..png) 15 | 16 | # Skip Router SDK 17 | 18 | Skip Router is an SDK for Skip API for creating seamless cross-chain experiences for end-users with IBC. 19 | 20 | ## Packages 21 | 22 | - [`@skip-router/core`](https://npm.im/@skip-router/core) - JavaScript SDK for Skip API 23 | 24 | ## Documentation 25 | 26 | - [Skip API documentation](https://api-docs.skip.money) 27 | - [Skip API Reference](https://api-docs.skip.money/reference) 28 | - [Skip API Reference (Swagger)](https://api-swagger.skip.money) 29 | 30 | ## Examples 31 | 32 | - https://github.com/skip-mev/skip-next-simple-example 33 | - https://github.com/skip-mev/router-sdk-example 34 | - https://github.com/skip-mev/skip-router-sdk/blob/main/packages/examples/src/skip-api-quickstart-example.js 35 | 36 | ## Maintainers 37 | 38 | - @thal0x 39 | - @codingki 40 | -------------------------------------------------------------------------------- /local_vendor/OPinit/proto/opinit/ophost/v1/tx.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package opinit.ophost.v1; 3 | 4 | import "amino/amino.proto"; 5 | import "cosmos/base/v1beta1/coin.proto"; 6 | import "cosmos/msg/v1/msg.proto"; 7 | import "cosmos_proto/cosmos.proto"; 8 | import "gogoproto/gogo.proto"; 9 | import "opinit/ophost/v1/types.proto"; 10 | 11 | option go_package = "github.com/initia-labs/OPinit/x/ophost/types"; 12 | option (gogoproto.goproto_getters_all) = false; 13 | 14 | // Msg defines the rollup Msg service. 15 | service Msg { 16 | option (cosmos.msg.v1.service) = true; 17 | 18 | // InitiateTokenDeposit defines a user facing l1 => l2 token transfer interface. 19 | rpc InitiateTokenDeposit(MsgInitiateTokenDeposit) returns (MsgInitiateTokenDepositResponse); 20 | 21 | } 22 | 23 | 24 | // MsgInitiateTokenDeposit defines a SDK message for adding a new validator. 25 | message MsgInitiateTokenDeposit { 26 | option (cosmos.msg.v1.signer) = "sender"; 27 | option (amino.name) = "ophost/MsgInitiateTokenDeposit"; 28 | 29 | option (gogoproto.equal) = false; 30 | option (gogoproto.goproto_getters) = false; 31 | 32 | string sender = 1 [(gogoproto.moretags) = "yaml:\"sender\"", (cosmos_proto.scalar) = "cosmos.AddressString"]; 33 | uint64 bridge_id = 2 [(gogoproto.moretags) = "yaml:\"bridge_id\""]; 34 | string to = 3 [(gogoproto.moretags) = "yaml:\"to\"", (cosmos_proto.scalar) = "cosmos.AddressString"]; 35 | cosmos.base.v1beta1.Coin amount = 4 36 | [(gogoproto.moretags) = "yaml:\"amount\"", (gogoproto.nullable) = false, (amino.dont_omitempty) = true]; 37 | bytes data = 5 [(gogoproto.moretags) = "yaml:\"data\"", (gogoproto.nullable) = true, (amino.dont_omitempty) = false]; 38 | } 39 | 40 | // MsgInitiateTokenDepositResponse returns a message handle result. 41 | message MsgInitiateTokenDepositResponse { 42 | uint64 sequence = 1; 43 | } -------------------------------------------------------------------------------- /local_vendor/OPinit/proto/opinit/ophost/v1/types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package opinit.ophost.v1; 3 | 4 | import "amino/amino.proto"; 5 | import "cosmos/base/v1beta1/coin.proto"; 6 | import "cosmos_proto/cosmos.proto"; 7 | import "gogoproto/gogo.proto"; 8 | import "google/protobuf/timestamp.proto"; 9 | import "google/protobuf/duration.proto"; 10 | 11 | option go_package = "github.com/initia-labs/OPinit/x/ophost/types"; 12 | option (gogoproto.equal_all) = true; 13 | option (gogoproto.goproto_getters_all) = false; 14 | 15 | // Params defines the set of ophost parameters. 16 | message Params { 17 | option (amino.name) = "ophost/Params"; 18 | option (gogoproto.equal) = true; 19 | option (gogoproto.goproto_stringer) = false; 20 | 21 | // The amount to be paid by l2 creator. 22 | repeated cosmos.base.v1beta1.Coin registration_fee = 1 [ 23 | (gogoproto.nullable) = false, 24 | (amino.dont_omitempty) = true, 25 | (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" 26 | ]; 27 | } 28 | 29 | // BridgeConfig defines the set of bridge config. 30 | message BridgeConfig { 31 | // The address of the challenger. 32 | repeated string challengers = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; 33 | // The address of the proposer. 34 | string proposer = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; 35 | // The information about batch submission. 36 | BatchInfo batch_info = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; 37 | // The time interval at which checkpoints must be submitted. 38 | // NOTE: this param is currently not used, but will be used for challenge in future. 39 | google.protobuf.Duration submission_interval = 4 [ 40 | (gogoproto.stdduration) = true, 41 | (gogoproto.jsontag) = "submission_interval,omitempty", 42 | (gogoproto.nullable) = false, 43 | (amino.dont_omitempty) = true 44 | ]; 45 | // The minium time duration that must elapse before a withdrawal can be finalized. 46 | google.protobuf.Duration finalization_period = 5 [ 47 | (gogoproto.stdduration) = true, 48 | (gogoproto.jsontag) = "finalization_period,omitempty", 49 | (gogoproto.nullable) = false, 50 | (amino.dont_omitempty) = true 51 | ]; 52 | // The time of the first l2 block recorded. 53 | // NOTE: this param is currently not used, but will be used for challenge in future. 54 | google.protobuf.Timestamp submission_start_time = 6 55 | [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (amino.dont_omitempty) = true]; 56 | // Normally it is IBC channelID for permissioned IBC relayer. 57 | bytes metadata = 7; 58 | } 59 | 60 | // BatchInfo defines the set of batch information. 61 | message BatchInfo { 62 | // The address of the batch submitter. 63 | string submitter = 1; 64 | // The target chain 65 | string chain = 2; 66 | } 67 | 68 | // TokenPair defines l1 and l2 token pair 69 | message TokenPair { 70 | string l1_denom = 1; 71 | string l2_denom = 2; 72 | } 73 | 74 | // Output is a l2 block submitted by proposer. 75 | message Output { 76 | // Hash of the l2 output. 77 | bytes output_root = 1; 78 | // Timestamp of the l1 block that the output root was submitted in. 79 | google.protobuf.Timestamp l1_block_time = 2 80 | [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (amino.dont_omitempty) = true]; 81 | // The l2 block number that the output root was submitted in. 82 | uint64 l2_block_number = 3; 83 | } 84 | 85 | // BatchInfoWithOutput defines the batch information with output. 86 | message BatchInfoWithOutput { 87 | BatchInfo batch_info = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; 88 | Output output = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; 89 | } -------------------------------------------------------------------------------- /local_vendor/initia/proto/initia/move/v1/tx.proto: -------------------------------------------------------------------------------- 1 | // This is copied from the initia repo. Everything unrelated to MsgExecute is deleted. 2 | 3 | syntax = "proto3"; 4 | package initia.move.v1; 5 | 6 | import "gogoproto/gogo.proto"; 7 | import "google/protobuf/descriptor.proto"; 8 | 9 | option go_package = "github.com/initia-labs/initia/x/move/types"; 10 | option (gogoproto.goproto_getters_all) = false; 11 | 12 | // Msg defines the move Msg service. 13 | service Msg { 14 | option (cosmos.msg.v1.service) = true; 15 | 16 | // Execute runs a entry function with the given message 17 | rpc Execute(MsgExecute) returns (MsgExecuteResponse); 18 | } 19 | 20 | // MsgExecute is the message to execute the given module function 21 | message MsgExecute { 22 | option (signer) = "sender"; 23 | 24 | // Sender is the that actor that signed the messages 25 | string sender = 1 [(scalar) = "cosmos.AddressString"]; 26 | // ModuleAddr is the address of the module deployer 27 | string module_address = 2; 28 | // ModuleName is the name of module to execute 29 | string module_name = 3; 30 | // FunctionName is the name of a function to execute 31 | string function_name = 4; 32 | // TypeArgs is the type arguments of a function to execute 33 | // ex) "0x1::BasicCoin::Initia", "bool", "u8", "u64" 34 | repeated string type_args = 5; 35 | // Args is the arguments of a function to execute 36 | // - number: little endian 37 | // - string: base64 bytes 38 | repeated bytes args = 6; 39 | } 40 | 41 | // MsgExecuteResponse returns execution result data. 42 | message MsgExecuteResponse {} 43 | 44 | // cosmos_proto/cosmos.proto 45 | extend google.protobuf.MessageOptions { 46 | 47 | // implements_interface is used to indicate the type name of the interface 48 | // that a message implements so that it can be used in google.protobuf.Any 49 | // fields that accept that interface. A message can implement multiple 50 | // interfaces. Interfaces should be declared using a declare_interface 51 | // file option. 52 | repeated string implements_interface = 93001; 53 | } 54 | 55 | extend google.protobuf.FieldOptions { 56 | 57 | // accepts_interface is used to annotate that a google.protobuf.Any 58 | // field accepts messages that implement the specified interface. 59 | // Interfaces should be declared using a declare_interface file option. 60 | string accepts_interface = 93001; 61 | 62 | // scalar is used to indicate that this field follows the formatting defined 63 | // by the named scalar which should be declared with declare_scalar. Code 64 | // generators may choose to use this information to map this field to a 65 | // language-specific type representing the scalar. 66 | string scalar = 93002; 67 | } 68 | 69 | extend google.protobuf.FileOptions { 70 | 71 | // declare_interface declares an interface type to be used with 72 | // accepts_interface and implements_interface. Interface names are 73 | // expected to follow the following convention such that their declaration 74 | // can be discovered by tools: for a given interface type a.b.C, it is 75 | // expected that the declaration will be found in a protobuf file named 76 | // a/b/interfaces.proto in the file descriptor set. 77 | repeated InterfaceDescriptor declare_interface = 793021; 78 | 79 | // declare_scalar declares a scalar type to be used with 80 | // the scalar field option. Scalar names are 81 | // expected to follow the following convention such that their declaration 82 | // can be discovered by tools: for a given scalar type a.b.C, it is 83 | // expected that the declaration will be found in a protobuf file named 84 | // a/b/scalars.proto in the file descriptor set. 85 | repeated ScalarDescriptor declare_scalar = 793022; 86 | } 87 | 88 | // InterfaceDescriptor describes an interface type to be used with 89 | // accepts_interface and implements_interface and declared by declare_interface. 90 | message InterfaceDescriptor { 91 | 92 | // name is the name of the interface. It should be a short-name (without 93 | // a period) such that the fully qualified name of the interface will be 94 | // package.name, ex. for the package a.b and interface named C, the 95 | // fully-qualified name will be a.b.C. 96 | string name = 1; 97 | 98 | // description is a human-readable description of the interface and its 99 | // purpose. 100 | string description = 2; 101 | } 102 | 103 | // ScalarDescriptor describes an scalar type to be used with 104 | // the scalar field option and declared by declare_scalar. 105 | // Scalars extend simple protobuf built-in types with additional 106 | // syntax and semantics, for instance to represent big integers. 107 | // Scalars should ideally define an encoding such that there is only one 108 | // valid syntactical representation for a given semantic meaning, 109 | // i.e. the encoding should be deterministic. 110 | message ScalarDescriptor { 111 | 112 | // name is the name of the scalar. It should be a short-name (without 113 | // a period) such that the fully qualified name of the scalar will be 114 | // package.name, ex. for the package a.b and scalar named C, the 115 | // fully-qualified name will be a.b.C. 116 | string name = 1; 117 | 118 | // description is a human-readable description of the scalar and its 119 | // encoding format. For instance a big integer or decimal scalar should 120 | // specify precisely the expected encoding format. 121 | string description = 2; 122 | 123 | // field_type is the type of field with which this scalar can be used. 124 | // Scalars can be used with one and only one type of field so that 125 | // encoding standards and simple and clear. Currently only string and 126 | // bytes fields are supported for scalars. 127 | repeated ScalarType field_type = 3; 128 | } 129 | 130 | enum ScalarType { 131 | SCALAR_TYPE_UNSPECIFIED = 0; 132 | SCALAR_TYPE_STRING = 1; 133 | SCALAR_TYPE_BYTES = 2; 134 | } 135 | 136 | // cosmos/msgs/v1/msg.proto 137 | extend google.protobuf.ServiceOptions { 138 | // service indicates that the service is a Msg service and that requests 139 | // must be transported via blockchain transactions rather than gRPC. 140 | // Tooling can use this annotation to distinguish between Msg services and 141 | // other types of services via reflection. 142 | bool service = 11110000; 143 | } 144 | 145 | extend google.protobuf.MessageOptions { 146 | // signer must be used in cosmos messages in order 147 | // to signal to external clients which fields in a 148 | // given cosmos message must be filled with signer 149 | // information (address). 150 | // The field must be the protobuf name of the message 151 | // field extended with this MessageOption. 152 | // The field must either be of string kind, or of message 153 | // kind in case the signer information is contained within 154 | // a message inside the cosmos message. 155 | repeated string signer = 11110000; 156 | } 157 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "skip-router", 3 | "workspaces": [ 4 | "packages/*", 5 | "vendor/" 6 | ], 7 | "scripts": { 8 | "build": "turbo run build", 9 | "postinstall": "git submodule update --init --recursive", 10 | "release": "turbo run build lint test && changeset publish", 11 | "test": "turbo run test" 12 | }, 13 | "devDependencies": { 14 | "@changesets/cli": "^2.27.1", 15 | "@types/jest": "^29.5.12", 16 | "@typescript-eslint/eslint-plugin": "^6.21.0", 17 | "@typescript-eslint/parser": "^6.21.0", 18 | "eslint": "^8.56.0", 19 | "eslint-config-prettier": "^9.1.0", 20 | "eslint-plugin-prettier": "^5.1.3", 21 | "eslint-plugin-simple-import-sort": "^10.0.0", 22 | "jest": "^29.7.0", 23 | "jest-environment-jsdom": "^29.7.0", 24 | "msw": "^1.2.3", 25 | "prettier": "^3.2.5", 26 | "ts-jest": "^29.1.2", 27 | "tsup": "^8.0.1", 28 | "turbo": "^1.12.3", 29 | "typescript": "5.2.x" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/core/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | const eslintConfig = { 3 | env: { 4 | browser: true, 5 | node: true, 6 | }, 7 | extends: [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/recommended", 10 | "plugin:prettier/recommended", 11 | ], 12 | ignorePatterns: [ 13 | "dist/", 14 | "node_modules/", 15 | "src/codegen/", 16 | // 17 | ], 18 | parser: "@typescript-eslint/parser", 19 | parserOptions: { 20 | ecmaVersion: "latest", 21 | sourceType: "module", 22 | }, 23 | plugins: ["@typescript-eslint", "simple-import-sort"], 24 | rules: { 25 | "@typescript-eslint/ban-types": [ 26 | "error", 27 | { 28 | types: { 29 | // un-ban a type that's banned by default 30 | "{}": false, 31 | }, 32 | extendDefaults: true, 33 | }, 34 | ], 35 | }, 36 | root: true, 37 | }; 38 | 39 | module.exports = eslintConfig; 40 | -------------------------------------------------------------------------------- /packages/core/.gitignore: -------------------------------------------------------------------------------- 1 | src/codegen/** 2 | -------------------------------------------------------------------------------- /packages/core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @skip-router/core 2 | 3 | ## 5.2.1 4 | 5 | ### Patch Changes 6 | 7 | - 11c529f: DEPRECATION NOTICE, please use @skip-go/core moving forward. 8 | 9 | ## 5.2.0 10 | 11 | ### Minor Changes 12 | 13 | - d06a1e4: Add evm_slippage_tolerance_percent to smart_swap_options 14 | - 7ab600d: Allow multiple chain filtering for chains and assets requests 15 | - dc5c8f9: Adds support for the op init transfer operation and lifecycle tracking objects 16 | 17 | ## 5.1.1 18 | 19 | ### Patch Changes 20 | 21 | - f0c663d: fix testnet validate gas balance 22 | 23 | ## 5.1.0 24 | 25 | ### Minor Changes 26 | 27 | - 05630c1: Add evm_swaps to smart_swap_options 28 | 29 | ## 5.0.5 30 | 31 | ### Patch Changes 32 | 33 | - 3c47bf1: fix: onlyTestnets not working in assets 34 | 35 | ## 5.0.4 36 | 37 | ### Patch Changes 38 | 39 | - a91e0e0: find gasTokenUsed on stride-1 even validateGasBalance off 40 | 41 | ## 5.0.3 42 | 43 | ### Patch Changes 44 | 45 | - d1d0161: backward compatible addressList 46 | 47 | ## 5.0.2 48 | 49 | ### Patch Changes 50 | 51 | - f17d415: allow stride to check tia balance for gas 52 | 53 | ## 5.0.1 54 | 55 | ### Patch Changes 56 | 57 | - d226070: Updates address validate logic to check route.requiredChainAddresses instead of route.chainIDs 58 | 59 | ## 5.0.0 60 | 61 | ### Major Changes 62 | 63 | - 26652d3: Added new field onlyTestnets to assets,chains,venues endpoints. Deprecates isTestnet field from chains endpoint. 64 | 65 | ## 4.2.0 66 | 67 | ### Minor Changes 68 | 69 | - 484387a: Adds support for allow_swaps boolean flag in /route and /msgs_direct, allowing caller to specify to not have swaps in their route search 70 | 71 | ### Patch Changes 72 | 73 | - c3a1a02: Add chain_ids_to_affiliates field to MsgsRequest and MsgsDirectRequest 74 | 75 | ## 4.1.1 76 | 77 | ### Patch Changes 78 | 79 | - a88619c: format amount gas error 80 | 81 | ## 4.1.0 82 | 83 | ### Minor Changes 84 | 85 | - 48d998b: - Updated API types to include signer addresses on CosmosTX, EvmTX, and SvmTx 86 | - Updated `getGasPrice` param to (chainID: string, chainType: "cosmos" | "evm" | "svm") => Promise 87 | - Added `getFallbackGasAmount` param in `executeRoute` 88 | - Improved jsdoc 89 | - Updated `validateGasBalance`, `estimateGasForMessage`, `validateGasBalances` to an object args 90 | 91 | ## 4.0.1 92 | 93 | ### Patch Changes 94 | 95 | - f558aa4: add missing ibcCapabilities from Chain type 96 | 97 | ## 4.0.0 98 | 99 | ### Major Changes 100 | 101 | - 3c91d03: - Remove client_id 102 | - Add smart swap types 103 | - Add smart swap options 104 | - Add smart swap types and swap venues field to swap 105 | - Add apiKey param 106 | 107 | ## 3.0.2 108 | 109 | ### Patch Changes 110 | 111 | - 2af8ccd: Add required chain addresses field to route response 112 | 113 | ## 3.0.1 114 | 115 | ### Patch Changes 116 | 117 | - ccdb6ef: bump initia-registry 118 | 119 | ## 3.0.0 120 | 121 | ### Major Changes 122 | 123 | - 8846e1a: userAddresses param type change in executeRoute 124 | 125 | ## 2.4.4 126 | 127 | ### Patch Changes 128 | 129 | - b4fd9ed: add amountIn and amountOut in operations 130 | 131 | ## 2.4.3 132 | 133 | ### Patch Changes 134 | 135 | - 59364ac: [API-2703] Add from_chain_id to swap 136 | 137 | ## 2.4.2 138 | 139 | ### Patch Changes 140 | 141 | - 52f94b7: lock initia-registry deps 142 | 143 | ## 2.4.1 144 | 145 | ### Patch Changes 146 | 147 | - 6af35dc: Don't use BigInt for amino types 148 | 149 | ## 2.4.0 150 | 151 | ### Minor Changes 152 | 153 | - 9922837: Add swap_venue for backwards compatibility 154 | 155 | ## 2.3.0 156 | 157 | ### Minor Changes 158 | 159 | - 9ab81a5: Change solana blockhash commitment level from finalized to confirmed for sendTransaction preflight checks and when checking for transaction inclusion 160 | 161 | ## 2.2.0 162 | 163 | ### Minor Changes 164 | 165 | - 8b93aa7: Change swap_venue to swap_venues for Route and MsgsDirect requests 166 | 167 | ## 2.1.0 168 | 169 | ### Minor Changes 170 | 171 | - a2f7ffa: Rename rapid_relay to smart_relay 172 | 173 | ## 2.0.5 174 | 175 | ### Patch Changes 176 | 177 | - 8c4cafb: changes the access level of specific members and methods from private to protected 178 | 179 | ## 2.0.4 180 | 181 | ### Patch Changes 182 | 183 | - 8e0de72: bump cosmjs version and chain registry 184 | 185 | ## 2.0.3 186 | 187 | ### Patch Changes 188 | 189 | - 4903d27: executeSVMTransaction api submit after sign 190 | 191 | ## 2.0.2 192 | 193 | ### Patch Changes 194 | 195 | - d162e7d: executeSVMTransaction wait finalized tx strategy 196 | 197 | ## 2.0.1 198 | 199 | ### Patch Changes 200 | 201 | - 2203797: Use 'confirmed' preflight commitment when sending transactions 202 | 203 | ## 2.0.0 204 | 205 | ### Major Changes 206 | 207 | - 519b34f: Support solana tx and rapid relay 208 | 209 | ### Patch Changes 210 | 211 | - 519b34f: Add svmTx to execute route 212 | - 519b34f: Add include testnets 213 | - 519b34f: fix cctp message MsgDepositForBurnWithCaller 214 | - 519b34f: Catch up to main 215 | - 519b34f: solana signing 216 | - 519b34f: fix cosmos_tx msgs signing 217 | - 519b34f: track retry and backoff 218 | - 519b34f: update svmTx type 219 | 220 | ## 2.0.0-rc.8 221 | 222 | ### Patch Changes 223 | 224 | - fix cosmos_tx msgs signing 225 | 226 | ## 2.0.0-rc.7 227 | 228 | ### Patch Changes 229 | 230 | - fix cctp message MsgDepositForBurnWithCaller 231 | 232 | ## 2.0.0-rc.6 233 | 234 | ### Patch Changes 235 | 236 | - track retry and backoff 237 | 238 | ## 2.0.0-rc.5 239 | 240 | ### Patch Changes 241 | 242 | - solana signing 243 | 244 | ## 2.0.0-rc.4 245 | 246 | ### Patch Changes 247 | 248 | - update svmTx type 249 | 250 | ## 2.0.0-rc.3 251 | 252 | ### Patch Changes 253 | 254 | - Add svmTx to execute route 255 | 256 | ## 2.0.0-rc.2 257 | 258 | ### Patch Changes 259 | 260 | - Catch up to main 261 | 262 | ## 2.0.0-rc.1 263 | 264 | ### Patch Changes 265 | 266 | - Add include testnets 267 | 268 | ## 2.0.0-rc.0 269 | 270 | ### Major Changes 271 | 272 | - b9b139d: Add svm flags 273 | 274 | ## 2.0.0-2.0.0-rc.0.0 275 | 276 | ### Major Changes 277 | 278 | - Add svm flags 279 | 280 | ## 1.4.0 281 | 282 | ### Minor Changes 283 | 284 | - d9092f9: update viem version to 2.x 285 | 286 | ## 1.3.13 287 | 288 | ### Patch Changes 289 | 290 | - c229ca5: Add released field to transfer_asset_release 291 | 292 | ## 1.3.12 293 | 294 | ### Patch Changes 295 | 296 | - a60e293: adjust types SwapVenu and assetFromSource 297 | 298 | ## 1.3.11 299 | 300 | ### Patch Changes 301 | 302 | - ddbf415: fix account not parsed by accountParser 303 | 304 | ## 1.3.10 305 | 306 | ### Patch Changes 307 | 308 | - cddd3e8: Define and use correct hyperlane types for lifecycle tracking 309 | 310 | ## 1.3.9 311 | 312 | ### Patch Changes 313 | 314 | - 3111d66: Add hyperlane transfer 315 | 316 | ## 1.3.8 317 | 318 | ### Patch Changes 319 | 320 | - c6dd6dc: fix executeRoute undefined getGasPrice params, transactionStatus retryOptions 321 | 322 | ## 1.3.7 323 | 324 | ### Patch Changes 325 | 326 | - 445a9c7: Add denom in and denom out to all operations 327 | - 30f5613: Add types for Hyperlane support 328 | 329 | ## 1.3.6 330 | 331 | ### Patch Changes 332 | 333 | - a11b433: add usdFeeAmount in axelarTransfer route operations 334 | 335 | ## 1.3.5 336 | 337 | ### Patch Changes 338 | 339 | - 2429849: fix memo ledger error 340 | 341 | ## 1.3.4 342 | 343 | ### Patch Changes 344 | 345 | - 76c37d4: fix cosmos ledger signing 346 | 347 | ## 1.3.3 348 | 349 | ### Patch Changes 350 | 351 | - cc0b2bd: properly encode MsgExecuteContract for Injective 352 | 353 | ## 1.3.2 354 | 355 | ### Patch Changes 356 | 357 | - a624a2a: Fix a bug in BaseAccount signing for dymension 358 | 359 | ## 1.3.1 360 | 361 | ### Patch Changes 362 | 363 | - 3fe6bd0: Fixes bugs in signing for ethermint-like chains 364 | 365 | ## 1.3.0 366 | 367 | ### Minor Changes 368 | 369 | - a61ce2e: Improve stargate account parser, proto signing, and bundling 370 | 371 | ## 1.2.15 372 | 373 | ### Patch Changes 374 | 375 | - 1cba455: undo cosmjs upgrade 376 | - ae1b120: Register EthAccount proto type 377 | 378 | ## 1.2.14 379 | 380 | ### Patch Changes 381 | 382 | - e313807: When getting default gas token don't fail on no chain registry data 383 | 384 | ## 1.2.13 385 | 386 | ### Patch Changes 387 | 388 | - 586a771: Set proper typeUrl on pubkey when it is an ethermint key 389 | 390 | ## 1.2.12 391 | 392 | ### Patch Changes 393 | 394 | - 9b9cb70: Improve amino/registry types, handle stride account parsing 395 | 396 | ## 1.2.11 397 | 398 | ### Patch Changes 399 | 400 | - 74643e9: added onTransactionTracked opts 401 | 402 | ## 1.2.10 403 | 404 | ### Patch Changes 405 | 406 | - b361077: Add allow_multi_tx parameter to route request 407 | 408 | ## 1.2.9 409 | 410 | ### Patch Changes 411 | 412 | - 491d16a: Add CCTP types to transaction tracking 413 | 414 | ## 1.2.8 415 | 416 | ### Patch Changes 417 | 418 | - 7411597: Add bridges endpoint and route parameter 419 | 420 | ## 1.2.7 421 | 422 | ### Patch Changes 423 | 424 | - bdb8183: Fix type error 425 | 426 | ## 1.2.6 427 | 428 | ### Patch Changes 429 | 430 | - 505ff19: Fix type definitions from generated code 431 | 432 | ## 1.2.5 433 | 434 | ### Patch Changes 435 | 436 | - fbc169c: Define valid values for experimental features array 437 | 438 | ## 1.2.4 439 | 440 | ### Patch Changes 441 | 442 | - 803eb8b: rename unsafe to allow_unsafe 443 | - 1ed5e7b: Add `getFeeForMessage`, `getRecommendedGasPrice`, and `getFeeInfoForChain` methods to SkipRouter 444 | - 738dd7d: Update router to support CCTP bridging operations returned by the API 445 | 446 | ## 1.2.3 447 | 448 | ### Patch Changes 449 | 450 | - c98fb7c: use timeout height instead of timestamp on amino signing 451 | 452 | ## 1.2.2 453 | 454 | ### Patch Changes 455 | 456 | - 35aa11b: Expose gas methods in SkipRouter 457 | 458 | ## 1.2.1 459 | 460 | ### Patch Changes 461 | 462 | - 77d97b4: Add 'unsafe' flag to route request 463 | 464 | ## 1.2.0 465 | 466 | ### Minor Changes 467 | 468 | - e1ce04a: Update recommendAssets to handle multiple requests 469 | 470 | ## 1.1.3 471 | 472 | ### Patch Changes 473 | 474 | - 579e28b: Add fee fields to Transfer field 475 | - 67a9a04: Add assetsBetweenChains 476 | 477 | ## 1.1.2 478 | 479 | ### Patch Changes 480 | 481 | - 959b51c: Simulate cosmos transactions to estimate gas 482 | - 89b7472: Add ibcOriginAssets 483 | 484 | ## 1.1.1 485 | 486 | ### Patch Changes 487 | 488 | - 3a89472: Add fields for price impact and usd amounts 489 | 490 | ## 1.1.0 491 | 492 | ### Minor Changes 493 | 494 | - c0336ea: recommended asset field added to data models 495 | 496 | ### Patch Changes 497 | 498 | - def7ec0: Handle multi-transfer 499 | 500 | ## 1.0.5 501 | 502 | ### Patch Changes 503 | 504 | - 018ca30: update onTransactionCompleted callback to include chain id and hash 505 | 506 | ## 1.0.4 507 | 508 | ### Patch Changes 509 | 510 | - bdd3773: Add description and coingecko id to asset types 511 | 512 | ## 1.0.3 513 | 514 | ### Patch Changes 515 | 516 | - cd03ff5: Add fee asset field to AxelarTransfer 517 | 518 | ## 1.0.2 519 | 520 | ### Patch Changes 521 | 522 | - f4f16e2: Utilize client_id parameter in API requests 523 | 524 | ## 1.0.1 525 | 526 | ### Patch Changes 527 | 528 | - 1dc36fd: Raise gas estimate for MsgExecuteContract calls 529 | 530 | ## 1.0.0 531 | 532 | ### Major Changes 533 | 534 | - 0b71558: - Adds support for EVM transactions. 535 | - Rename `getOfflineSigner` to `getCosmosSigner`. 536 | - Adds `getEVMSigner`. 537 | - Adds `onTransactionBroadcast` which is called when a transaction is broadcasted to the chain. 538 | 539 | ### Patch Changes 540 | 541 | - b8ada23: Add changesets for proper releases 542 | - 903b43d: - Updates lifecycle tracking types to include the explorer links now provided by the API 543 | - Renamed `onTransactionSuccess` to `onTransactionCompleted` because it's not only called on success 544 | - Pass full `TxStatusResponse` to `onTransactionCompleted` instead of abridged data. 545 | -------------------------------------------------------------------------------- /packages/core/Makefile: -------------------------------------------------------------------------------- 1 | HELM_NAME = skip-router 2 | HELM_FILE = starship/local.yaml 3 | HELM_REPO = starship 4 | HELM_CHART = devnet 5 | HELM_VERSION = 0.1.46-rc3 6 | 7 | ############################################################################### 8 | ### All commands ### 9 | ############################################################################### 10 | 11 | .PHONY: setup 12 | setup: check setup-helm 13 | 14 | .PHONY: start 15 | start: install port-forward 16 | 17 | .PHONY: test 18 | test: 19 | npm run e2e:test 20 | 21 | .PHONY: stop 22 | stop: stop-forward delete 23 | 24 | .PHONY: clean 25 | clean: stop clean-kind 26 | 27 | ############################################################################### 28 | ### Helm commands ### 29 | ############################################################################### 30 | 31 | .PHONY: setup-helm 32 | setup-helm: 33 | helm repo add $(HELM_REPO) https://cosmology-tech.github.io/starship/ 34 | helm repo update 35 | helm search repo $(HELM_REPO)/$(HELM_CHART) --version $(HELM_VERSION) 36 | 37 | .PHONY: install 38 | install: 39 | @echo "Installing the helm chart. This is going to take a while....." 40 | @echo "You can check the status with \"kubectl get pods\", run in another terminal please" 41 | helm install -f $(HELM_FILE) $(HELM_NAME) $(HELM_REPO)/$(HELM_CHART) --version $(HELM_VERSION) --wait --timeout 50m 42 | 43 | .PHONY: upgrade 44 | upgrade: 45 | helm upgrade --debug -f $(HELM_FILE) $(HELM_NAME) $(HELM_REPO)/$(HELM_CHART) --version $(HELM_VERSION) 46 | 47 | .PHONY: debug 48 | debug: 49 | helm install --dry-run --debug -f $(HELM_FILE) $(HELM_NAME) $(HELM_REPO)/$(HELM_CHART) 50 | 51 | .PHONY: delete 52 | delete: 53 | -helm delete $(HELM_NAME) 54 | 55 | ############################################################################### 56 | ### Port forward ### 57 | ############################################################################### 58 | 59 | .PHONY: port-forward 60 | port-forward: 61 | bash $(CURDIR)/scripts/port-forward.sh --config=$(HELM_FILE) 62 | 63 | .PHONY: stop-forward 64 | stop-forward: 65 | -pkill -f "port-forward" 66 | 67 | ############################################################################### 68 | ### Local Kind Setup ### 69 | ############################################################################### 70 | KIND_CLUSTER=starship 71 | 72 | .PHONY: check 73 | check: 74 | bash $(CURDIR)/scripts/dev-setup.sh 75 | 76 | .PHONY: setup-kind 77 | setup-kind: 78 | kind create cluster --name $(KIND_CLUSTER) 79 | 80 | .PHONY: clean-kind 81 | clean-kind: 82 | kind delete cluster --name $(KIND_CLUSTER) -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # Deprecation Notice 2 | 3 | **⚠️ This project is deprecated** 4 | 5 | This repository is no longer actively maintained and may not receive future updates or bug fixes. Please use the now maintained and developed [@skip-go/core](https://www.npmjs.com/package/@skip-go/core) as a replacement. 6 | 7 | ## Migration Guide 8 | @skip-router/core@5.2.0 is the same as @skip-go/core@0.2.0. To migrate packages with minimal disruption, please upgrade to @skip-router/core@5.2.0 and then replace the package with @skip-go/core@0.2.0, then upgrading to the latest version from there. 9 | 10 | Thank you for your understanding and for using our software. 11 | 12 | For any questions, please reach out to us in our [discord](https://skip.build/discord) if you have any questions and/or need assistance migrating! 13 | 14 | ![header](https://files.readme.io/4f92aa7-DALLE_Cover_Photo_1..png) 15 | 16 | [![npm/v](https://badgen.net/npm/v/@skip-router/core)](https://www.npmjs.com/package/@skip-router/core) 17 | [![npm/dt](https://badgen.net/npm/dt/@skip-router/core?)](https://www.npmjs.com/package/@skip-router/core) 18 | [![stars](https://badgen.net/github/stars/skip-mev/skip-router-sdk?)](https://github.com/skip-mev/skip-router-sdk) 19 | 20 | # @skip-router/core 21 | 22 | JavaScript SDK for Skip API 23 | 24 | ## Install 25 | 26 | ```bash 27 | npm install @skip-router/core 28 | ``` 29 | 30 | ## Usage 31 | 32 | Read more at Skip API docs website on [Getting Started: TypeScript SDK](https://api-docs.skip.money/docs/getting-started). 33 | 34 | ## Development 35 | 36 | ```bash 37 | # clone repository 38 | git clone https://github.com/skip-mev/skip-router-sdk.git 39 | cd skip-router-sdk 40 | 41 | # prepare submodules 42 | git submodule update --init --recursive 43 | 44 | # install dependencies 45 | npm install 46 | 47 | # run watch server to build on changes 48 | npm -w @skip-router/core run watch 49 | 50 | # build packages 51 | npm run build 52 | ``` 53 | 54 | ## Unit Tests 55 | 56 | ```bash 57 | # run unit tests 58 | npm run test 59 | 60 | # run unit tests in watch mode 61 | npm run test -- --watch 62 | 63 | # run unit tests with coverage 64 | npm run test -- --coverage 65 | ``` 66 | 67 | ## E2E Tests 68 | 69 | E2E tests depend on [Starship](https://starship.cosmology.tech) to test interactions with various blockchains. 70 | 71 | ```bash 72 | # run starship setup 73 | npm run e2e:setup 74 | 75 | # run starship devnets 76 | npm run e2e:start 77 | 78 | # run e2e tests 79 | npm run e2e:test 80 | 81 | # stop starship devnets 82 | npm run e2e:stop 83 | ``` 84 | 85 | ## Documentation 86 | 87 | - [Skip API documentation](https://api-docs.skip.money) 88 | - [Skip API Reference](https://api-docs.skip.money/reference) 89 | - [Skip API Reference (Swagger)](https://api-swagger.skip.money) 90 | -------------------------------------------------------------------------------- /packages/core/e2e/transactions.test.ts: -------------------------------------------------------------------------------- 1 | import { Secp256k1HdWallet } from "@cosmjs/amino"; 2 | import { FaucetClient } from "@cosmjs/faucet-client"; 3 | import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; 4 | import { 5 | GasPrice, 6 | isDeliverTxFailure, 7 | isDeliverTxSuccess, 8 | } from "@cosmjs/stargate"; 9 | import { InjectiveDirectEthSecp256k1Wallet } from "@injectivelabs/sdk-ts"; 10 | 11 | import { SKIP_API_URL, SkipRouter } from "../src"; 12 | import { 13 | COSMOSHUB_ENDPOINT, 14 | COSMOSHUB_FAUCET, 15 | EVMOS_REST_ENDPOINT, 16 | EVMOS_RPC_ENDPOINT, 17 | INJECTIVE_REST_ENDPOINT, 18 | INJECTIVE_RPC_ENDPOINT, 19 | OSMOSIS_ENDPOINT, 20 | OSMOSIS_FAUCET, 21 | } from "./utils"; 22 | 23 | describe("transaction execution", () => { 24 | it("signs and executes an IBC transfer", async () => { 25 | const client = new SkipRouter({ 26 | apiURL: SKIP_API_URL, 27 | endpointOptions: { 28 | getRpcEndpointForChain: async () => { 29 | return COSMOSHUB_ENDPOINT; 30 | }, 31 | }, 32 | }); 33 | 34 | const signer = await DirectSecp256k1HdWallet.fromMnemonic( 35 | "opinion knife other balcony surge more bamboo canoe romance ask argue teach anxiety adjust spike mystery wolf alone torch tail six decide wash alley", 36 | ); 37 | 38 | const getCosmosSigner = async (chainID: string) => { 39 | return signer; 40 | }; 41 | 42 | const getGasPrice = async (chainID: string) => { 43 | return GasPrice.fromString("0.25uatom"); 44 | }; 45 | 46 | const accounts = await signer.getAccounts(); 47 | 48 | const signerAddress = accounts[0].address; 49 | 50 | const faucet = new FaucetClient(COSMOSHUB_FAUCET); 51 | await faucet.credit(signerAddress, "uatom"); 52 | 53 | const timeout = BigInt(Date.now()) * BigInt(1000000); 54 | 55 | const message = { 56 | chainID: "gaia-1", 57 | path: ["gaia-1", "osmosis-1"], 58 | msg: `{"source_port":"transfer","source_channel":"channel-0","token":{"denom":"uatom","amount":"1000000"},"sender":"${signerAddress}","receiver":"osmo1rc6h59ev8m7mdpg584v7m5t24k2ut3dy5nekjw4mdsfjysyjvv3q65m8pj","timeout_height":{},"timeout_timestamp":"${timeout}","memo":"{\\"wasm\\":{\\"contract\\":\\"osmo1rc6h59ev8m7mdpg584v7m5t24k2ut3dy5nekjw4mdsfjysyjvv3q65m8pj\\",\\"msg\\":{\\"swap_and_action\\":{\\"user_swap\\":{\\"swap_exact_coin_in\\":{\\"swap_venue_name\\":\\"osmosis-poolmanager\\",\\"operations\\":[{\\"pool\\":\\"1\\",\\"denom_in\\":\\"ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2\\",\\"denom_out\\":\\"uosmo\\"}]}},\\"min_coin\\":{\\"denom\\":\\"uosmo\\",\\"amount\\":\\"18961936\\"},\\"timeout_timestamp\\":1693222298030492937,\\"post_swap_action\\":{\\"bank_send\\":{\\"to_address\\":\\"osmo1f2f9vryyu53gr8vhsksn66kugnxaa7k8jdpk0e\\"}},\\"affiliates\\":[]}}}}"}`, 59 | msgTypeURL: "/ibc.applications.transfer.v1.MsgTransfer", 60 | }; 61 | 62 | const tx = await client.executeCosmosMessage({ 63 | signerAddress, 64 | getCosmosSigner, 65 | getGasPrice, 66 | messages: [message], 67 | chainID: "gaia-1", 68 | }); 69 | 70 | expect(isDeliverTxSuccess(tx)).toBe(true); 71 | }); 72 | 73 | it("signs and executes an IBC transfer (amino)", async () => { 74 | const client = new SkipRouter({ 75 | apiURL: SKIP_API_URL, 76 | endpointOptions: { 77 | getRpcEndpointForChain: async () => { 78 | return COSMOSHUB_ENDPOINT; 79 | }, 80 | }, 81 | }); 82 | 83 | const signer = await Secp256k1HdWallet.fromMnemonic( 84 | "opinion knife other balcony surge more bamboo canoe romance ask argue teach anxiety adjust spike mystery wolf alone torch tail six decide wash alley", 85 | ); 86 | const getCosmosSigner = async (chainID: string) => { 87 | return signer; 88 | }; 89 | const getGasPrice = async (chainID: string) => { 90 | return GasPrice.fromString("0.25uatom"); 91 | }; 92 | 93 | const accounts = await signer.getAccounts(); 94 | 95 | const signerAddress = accounts[0].address; 96 | 97 | const faucet = new FaucetClient(COSMOSHUB_FAUCET); 98 | await faucet.credit(signerAddress, "uatom"); 99 | 100 | const timeout = BigInt(Date.now()) * BigInt(1000000); 101 | 102 | const message = { 103 | chainID: "gaia-1", 104 | path: ["gaia-1", "osmosis-1"], 105 | msg: `{"source_port":"transfer","source_channel":"channel-0","token":{"denom":"uatom","amount":"1000000"},"sender":"${signerAddress}","receiver":"osmo1rc6h59ev8m7mdpg584v7m5t24k2ut3dy5nekjw4mdsfjysyjvv3q65m8pj","timeout_height":{},"timeout_timestamp":"${timeout}","memo":"{\\"wasm\\":{\\"contract\\":\\"osmo1rc6h59ev8m7mdpg584v7m5t24k2ut3dy5nekjw4mdsfjysyjvv3q65m8pj\\",\\"msg\\":{\\"swap_and_action\\":{\\"user_swap\\":{\\"swap_exact_coin_in\\":{\\"swap_venue_name\\":\\"osmosis-poolmanager\\",\\"operations\\":[{\\"pool\\":\\"1\\",\\"denom_in\\":\\"ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2\\",\\"denom_out\\":\\"uosmo\\"}]}},\\"min_coin\\":{\\"denom\\":\\"uosmo\\",\\"amount\\":\\"18961936\\"},\\"timeout_timestamp\\":1693222298030492937,\\"post_swap_action\\":{\\"bank_send\\":{\\"to_address\\":\\"osmo1f2f9vryyu53gr8vhsksn66kugnxaa7k8jdpk0e\\"}},\\"affiliates\\":[]}}}}"}`, 106 | msgTypeURL: "/ibc.applications.transfer.v1.MsgTransfer", 107 | }; 108 | 109 | const tx = await client.executeCosmosMessage({ 110 | signerAddress, 111 | getCosmosSigner, 112 | getGasPrice, 113 | messages: [message], 114 | chainID: "gaia-1", 115 | }); 116 | 117 | expect(isDeliverTxSuccess(tx)).toBe(true); 118 | }); 119 | 120 | it("signs and executes an IBC transfer (injective)", async () => { 121 | const client = new SkipRouter({ 122 | apiURL: SKIP_API_URL, 123 | endpointOptions: { 124 | getRpcEndpointForChain: async () => { 125 | return INJECTIVE_RPC_ENDPOINT; 126 | }, 127 | getRestEndpointForChain: async () => { 128 | return INJECTIVE_REST_ENDPOINT; 129 | }, 130 | }, 131 | }); 132 | 133 | const signer = await InjectiveDirectEthSecp256k1Wallet.fromKey( 134 | Uint8Array.from( 135 | Buffer.from( 136 | "408890c2b5eba1664bbd33ced41ec0d1322c48b2f65934142e0d8855b552204c", 137 | "hex", 138 | ), 139 | ), 140 | ); 141 | 142 | const getCosmosSigner = async (chainID: string) => { 143 | return signer; 144 | }; 145 | 146 | const accounts = await signer.getAccounts(); 147 | 148 | const signerAddress = accounts[0].address; 149 | const getGasPrice = async (chainID: string) => { 150 | return GasPrice.fromString("0.25inj"); 151 | }; 152 | 153 | const timeout = BigInt(Date.now()) * BigInt(1000000); 154 | 155 | const message = { 156 | chainID: "injective-1", 157 | path: ["injective-1", "osmosis-1"], 158 | msg: `{"source_port":"transfer","source_channel":"channel-0","token":{"denom":"inj","amount":"1000000000000000000"},"sender":"${signerAddress}","receiver":"osmo1rc6h59ev8m7mdpg584v7m5t24k2ut3dy5nekjw4mdsfjysyjvv3q65m8pj","timeout_height":{},"timeout_timestamp":"${timeout}","memo":"{\\"wasm\\":{\\"contract\\":\\"osmo1rc6h59ev8m7mdpg584v7m5t24k2ut3dy5nekjw4mdsfjysyjvv3q65m8pj\\",\\"msg\\":{\\"swap_and_action\\":{\\"user_swap\\":{\\"swap_exact_coin_in\\":{\\"swap_venue_name\\":\\"osmosis-poolmanager\\",\\"operations\\":[{\\"pool\\":\\"1\\",\\"denom_in\\":\\"ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2\\",\\"denom_out\\":\\"uosmo\\"}]}},\\"min_coin\\":{\\"denom\\":\\"uosmo\\",\\"amount\\":\\"18961936\\"},\\"timeout_timestamp\\":1693222298030492937,\\"post_swap_action\\":{\\"bank_send\\":{\\"to_address\\":\\"osmo1f2f9vryyu53gr8vhsksn66kugnxaa7k8jdpk0e\\"}},\\"affiliates\\":[]}}}}"}`, 159 | msgTypeURL: "/ibc.applications.transfer.v1.MsgTransfer", 160 | }; 161 | 162 | const tx = await client.executeCosmosMessage({ 163 | signerAddress, 164 | // @ts-expect-error : skipping type check for testing purposes 165 | getCosmosSigner, 166 | getGasPrice, 167 | messages: [message], 168 | chainID: "injective-1", 169 | }); 170 | 171 | expect(isDeliverTxSuccess(tx)).toBe(true); 172 | }); 173 | 174 | it("signs and executes an IBC transfer (evmos)", async () => { 175 | const client = new SkipRouter({ 176 | apiURL: SKIP_API_URL, 177 | endpointOptions: { 178 | getRpcEndpointForChain: async () => { 179 | return EVMOS_RPC_ENDPOINT; 180 | }, 181 | getRestEndpointForChain: async () => { 182 | return EVMOS_REST_ENDPOINT; 183 | }, 184 | }, 185 | }); 186 | 187 | const signer = await InjectiveDirectEthSecp256k1Wallet.fromKey( 188 | Uint8Array.from( 189 | Buffer.from( 190 | "408890c2b5eba1664bbd33ced41ec0d1322c48b2f65934142e0d8855b552204c", 191 | "hex", 192 | ), 193 | ), 194 | "evmos", 195 | ); 196 | const getCosmosSigner = async (chainID: string) => { 197 | return signer; 198 | }; 199 | 200 | const getGasPrice = async (chainID: string) => { 201 | return GasPrice.fromString("7aevmos"); 202 | }; 203 | 204 | const accounts = await signer.getAccounts(); 205 | 206 | const signerAddress = accounts[0].address; 207 | 208 | const timeout = BigInt(Date.now()) * BigInt(1000000); 209 | 210 | const message = { 211 | chainID: "evmos_9000-1", 212 | path: ["evmos_9000-1", "osmosis-1"], 213 | msg: `{"source_port":"transfer","source_channel":"channel-0","token":{"denom":"aevmos","amount":"1000000000000000000"},"sender":"${signerAddress}","receiver":"osmo1rc6h59ev8m7mdpg584v7m5t24k2ut3dy5nekjw4mdsfjysyjvv3q65m8pj","timeout_height":{},"timeout_timestamp":"${timeout}","memo":"{\\"wasm\\":{\\"contract\\":\\"osmo1rc6h59ev8m7mdpg584v7m5t24k2ut3dy5nekjw4mdsfjysyjvv3q65m8pj\\",\\"msg\\":{\\"swap_and_action\\":{\\"user_swap\\":{\\"swap_exact_coin_in\\":{\\"swap_venue_name\\":\\"osmosis-poolmanager\\",\\"operations\\":[{\\"pool\\":\\"1\\",\\"denom_in\\":\\"ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2\\",\\"denom_out\\":\\"uosmo\\"}]}},\\"min_coin\\":{\\"denom\\":\\"uosmo\\",\\"amount\\":\\"18961936\\"},\\"timeout_timestamp\\":1693222298030492937,\\"post_swap_action\\":{\\"bank_send\\":{\\"to_address\\":\\"osmo1f2f9vryyu53gr8vhsksn66kugnxaa7k8jdpk0e\\"}},\\"affiliates\\":[]}}}}"}`, 214 | msgTypeURL: "/ibc.applications.transfer.v1.MsgTransfer", 215 | }; 216 | 217 | const tx = await client.executeCosmosMessage({ 218 | signerAddress, 219 | messages: [message], 220 | // @ts-expect-error : skipping type check for testing purposes 221 | getCosmosSigner, 222 | getGasPrice, 223 | chainID: "evmos_9000-1", 224 | }); 225 | 226 | expect(isDeliverTxSuccess(tx)).toBe(true); 227 | }); 228 | 229 | it("signs and executes a cosmwasm execute message", async () => { 230 | const signer = await DirectSecp256k1HdWallet.fromMnemonic( 231 | "opinion knife other balcony surge more bamboo canoe romance ask argue teach anxiety adjust spike mystery wolf alone torch tail six decide wash alley", 232 | { 233 | prefix: "osmo", 234 | }, 235 | ); 236 | const getCosmosSigner = async (chainID: string) => { 237 | return signer; 238 | }; 239 | 240 | const getGasPrice = async (chainID: string) => { 241 | return GasPrice.fromString("0.25uosmo"); 242 | }; 243 | 244 | const accounts = await signer.getAccounts(); 245 | const signerAddress = accounts[0].address; 246 | 247 | const faucet = new FaucetClient(OSMOSIS_FAUCET); 248 | await faucet.credit(signerAddress, "uosmo"); 249 | 250 | const client = new SkipRouter({ 251 | apiURL: SKIP_API_URL, 252 | endpointOptions: { 253 | getRpcEndpointForChain: async () => { 254 | return OSMOSIS_ENDPOINT; 255 | }, 256 | }, 257 | }); 258 | 259 | const message = { 260 | chainID: "osmosis-1", 261 | path: ["osmosis-1", "cosmoshub-4"], 262 | msg: `{"sender":"${signerAddress}","contract":"osmo1rc6h59ev8m7mdpg584v7m5t24k2ut3dy5nekjw4mdsfjysyjvv3q65m8pj","msg":{"swap_and_action":{"user_swap":{"swap_exact_coin_in":{"operations":[{"denom_in":"uosmo","denom_out":"ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2","pool":"1"}],"swap_venue_name":"osmosis-poolmanager"}},"min_coin":{"denom":"ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2","amount":"495"},"timeout_timestamp":1693265108785341058,"post_swap_action":{"ibc_transfer":{"ibc_info":{"memo":"","receiver":"cosmos1f2f9vryyu53gr8vhsksn66kugnxaa7k86kjxet","recover_address":"osmo1f2f9vryyu53gr8vhsksn66kugnxaa7k8jdpk0e","source_channel":"channel-0"}}},"affiliates":[]}},"funds":[{"denom":"uosmo","amount":"10000"}]}`, 263 | msgTypeURL: "/cosmwasm.wasm.v1.MsgExecuteContract", 264 | }; 265 | 266 | const tx = await client.executeCosmosMessage({ 267 | signerAddress, 268 | getCosmosSigner, 269 | getGasPrice, 270 | messages: [message], 271 | chainID: "osmosis-1", 272 | }); 273 | 274 | // CheckTx must pass but the execution will fail in DeliverTx due to invalid contract address 275 | expect(isDeliverTxFailure(tx)).toBe(true); 276 | expect(tx.rawLog).toEqual( 277 | "failed to execute message; message index: 0: contract: not found", 278 | ); 279 | }); 280 | 281 | it("signs and executes a cosmwasm execute message (amino)", async () => { 282 | const client = new SkipRouter({ 283 | apiURL: SKIP_API_URL, 284 | endpointOptions: { 285 | getRpcEndpointForChain: async () => { 286 | return OSMOSIS_ENDPOINT; 287 | }, 288 | }, 289 | }); 290 | 291 | const signer = await Secp256k1HdWallet.fromMnemonic( 292 | "opinion knife other balcony surge more bamboo canoe romance ask argue teach anxiety adjust spike mystery wolf alone torch tail six decide wash alley", 293 | { 294 | prefix: "osmo", 295 | }, 296 | ); 297 | const getCosmosSigner = async (chainID: string) => { 298 | return signer; 299 | }; 300 | 301 | const getGasPrice = async (chainID: string) => { 302 | return GasPrice.fromString("0.25uosmo"); 303 | }; 304 | 305 | const accounts = await signer.getAccounts(); 306 | 307 | const signerAddress = accounts[0].address; 308 | 309 | const faucet = new FaucetClient(OSMOSIS_FAUCET); 310 | await faucet.credit(signerAddress, "uosmo"); 311 | 312 | const message = { 313 | chainID: "osmosis-1", 314 | path: ["osmosis-1", "cosmoshub-4"], 315 | msg: `{"sender":"${signerAddress}","contract":"osmo1rc6h59ev8m7mdpg584v7m5t24k2ut3dy5nekjw4mdsfjysyjvv3q65m8pj","msg":{"swap_and_action":{"user_swap":{"swap_exact_coin_in":{"operations":[{"denom_in":"uosmo","denom_out":"ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2","pool":"1"}],"swap_venue_name":"osmosis-poolmanager"}},"min_coin":{"denom":"ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2","amount":"495"},"timeout_timestamp":1693265108785341058,"post_swap_action":{"ibc_transfer":{"ibc_info":{"memo":"","receiver":"cosmos1f2f9vryyu53gr8vhsksn66kugnxaa7k86kjxet","recover_address":"osmo1f2f9vryyu53gr8vhsksn66kugnxaa7k8jdpk0e","source_channel":"channel-0"}}},"affiliates":[]}},"funds":[{"denom":"uosmo","amount":"10000"}]}`, 316 | msgTypeURL: "/cosmwasm.wasm.v1.MsgExecuteContract", 317 | }; 318 | 319 | const tx = await client.executeCosmosMessage({ 320 | signerAddress, 321 | getCosmosSigner, 322 | getGasPrice, 323 | messages: [message], 324 | chainID: "osmosis-1", 325 | }); 326 | 327 | // CheckTx must pass but the execution will fail in DeliverTx due to invalid contract address 328 | expect(isDeliverTxFailure(tx)).toBe(true); 329 | expect(tx.rawLog).toEqual( 330 | "failed to execute message; message index: 0: contract: not found", 331 | ); 332 | }); 333 | 334 | it("executeRoute with undefined getGasPrice", async () => { 335 | const client = new SkipRouter({ 336 | apiURL: SKIP_API_URL, 337 | endpointOptions: { 338 | getRpcEndpointForChain: async () => { 339 | return OSMOSIS_ENDPOINT; 340 | }, 341 | }, 342 | getCosmosSigner: async () => { 343 | return DirectSecp256k1HdWallet.fromMnemonic( 344 | "opinion knife other balcony surge more bamboo canoe romance ask argue teach anxiety adjust spike mystery wolf alone torch tail six decide wash alley", 345 | { 346 | prefix: "osmo", 347 | }, 348 | ); 349 | }, 350 | }); 351 | 352 | const signer = await Secp256k1HdWallet.fromMnemonic( 353 | "opinion knife other balcony surge more bamboo canoe romance ask argue teach anxiety adjust spike mystery wolf alone torch tail six decide wash alley", 354 | { 355 | prefix: "osmo", 356 | }, 357 | ); 358 | 359 | const accounts = await signer.getAccounts(); 360 | 361 | const signerAddress = accounts[0].address; 362 | 363 | const faucet = new FaucetClient(OSMOSIS_FAUCET); 364 | await faucet.credit(signerAddress, "uosmo"); 365 | 366 | try { 367 | await client.executeRoute({ 368 | route: { 369 | sourceAssetDenom: "uosmo", 370 | sourceAssetChainID: "osmosis-1", 371 | destAssetDenom: 372 | "ibc/14F9BC3E44B8A9C1BE1FB08980FAB87034C9905EF17CF2F5008FC085218811CC", 373 | destAssetChainID: "cosmoshub-4", 374 | amountIn: "1000000", 375 | amountOut: "1000000", 376 | operations: [ 377 | { 378 | transfer: { 379 | port: "transfer", 380 | channel: "channel-0", 381 | fromChainID: "osmosis-1", 382 | toChainID: "cosmoshub-4", 383 | pfmEnabled: true, 384 | supportsMemo: true, 385 | denomIn: "uosmo", 386 | denomOut: 387 | "ibc/14F9BC3E44B8A9C1BE1FB08980FAB87034C9905EF17CF2F5008FC085218811CC", 388 | bridgeID: "IBC", 389 | destDenom: 390 | "ibc/14F9BC3E44B8A9C1BE1FB08980FAB87034C9905EF17CF2F5008FC085218811CC", 391 | chainID: "osmosis-1", 392 | smartRelay: true, 393 | }, 394 | }, 395 | ], 396 | chainIDs: ["osmosis-1", "cosmoshub-4"], 397 | doesSwap: false, 398 | estimatedAmountOut: "1000000", 399 | txsRequired: 1, 400 | usdAmountIn: "1.68", 401 | usdAmountOut: "1.68", 402 | estimatedFees: [], 403 | }, 404 | userAddresses: [ 405 | { 406 | address: signerAddress, 407 | chainID: "osmosis-1", 408 | }, 409 | { 410 | address: "cosmos1g3jjhgkyf36pjhe7u5cw8j9u6cgl8x929ej430", 411 | chainID: "cosmoshub-4", 412 | }, 413 | ], 414 | validateGasBalance: true, 415 | slippageTolerancePercent: "3", 416 | onTransactionBroadcast: async (tx) => { 417 | expect(tx).toBeTruthy(); 418 | }, 419 | }); 420 | } catch (error) { 421 | // we expect an error here because we are using local rpc endpoint 422 | console.log(error); 423 | expect(error).toBeTruthy(); 424 | } 425 | }, 120000); 426 | }); 427 | -------------------------------------------------------------------------------- /packages/core/e2e/utils.ts: -------------------------------------------------------------------------------- 1 | export const COSMOSHUB_ENDPOINT = "http://localhost:26657"; 2 | export const COSMOSHUB_FAUCET = "http://localhost:8083"; 3 | 4 | export const OSMOSIS_ENDPOINT = "http://localhost:26653"; 5 | export const OSMOSIS_FAUCET = "http://localhost:8082"; 6 | 7 | export const EVMOS_RPC_ENDPOINT = "http://localhost:26658"; 8 | export const EVMOS_REST_ENDPOINT = "http://localhost:1318"; 9 | 10 | export const INJECTIVE_RPC_ENDPOINT = "http://localhost:26659"; 11 | export const INJECTIVE_REST_ENDPOINT = "http://localhost:1319"; 12 | -------------------------------------------------------------------------------- /packages/core/jest.config.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const { pathsToModuleNameMapper } = require("ts-jest"); 3 | const { compilerOptions } = require("./tsconfig"); 4 | 5 | const esModules = [ 6 | "@evmos/provider", 7 | "@evmos/transactions", 8 | "@evmos/eip712", 9 | "@evmos/proto", 10 | ].join("|"); 11 | 12 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 13 | module.exports = { 14 | preset: "ts-jest", 15 | testEnvironment: "node", 16 | roots: [""], 17 | modulePaths: [compilerOptions.baseUrl], // <-- This will be set to 'baseUrl' value 18 | moduleNameMapper: pathsToModuleNameMapper( 19 | compilerOptions.paths /*, { prefix: '/' } */, 20 | ), 21 | transformIgnorePatterns: [`/node_modules/(?!${esModules})`], 22 | transform: { 23 | "^.+\\.js$": "babel-jest", 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@skip-router/core", 3 | "description": "JavaScript SDK for Skip API", 4 | "version": "5.2.1", 5 | "repository": "https://github.com/skip-mev/skip-router-sdk", 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist/*", 10 | "*.js", 11 | "*.d.ts" 12 | ], 13 | "sideEffects": false, 14 | "scripts": { 15 | "build": "tsup", 16 | "clean": "rm -rf dist", 17 | "codegen": "node scripts/codegen.js", 18 | "e2e:clean": "make stop clean", 19 | "e2e:setup": "make setup && make setup-kind", 20 | "e2e:start": "make start", 21 | "e2e:stop": "make stop", 22 | "e2e:test": "vitest --dangerouslyIgnoreUnhandledErrors -c vitest.e2e.config.mjs --test-timeout=30000", 23 | "postpublish": "git reset --hard", 24 | "prepublishOnly": "node scripts/prepublish.js", 25 | "test": "vitest -c vitest.unit.config.mjs", 26 | "watch": "tsup --watch", 27 | "watch:link": "tsup --watch --onSuccess \"yalc push\"" 28 | }, 29 | "peerDependencies": { 30 | "chain-registry": "^1.33.11" 31 | }, 32 | "dependencies": { 33 | "@cosmjs/amino": "0.32.3", 34 | "@cosmjs/cosmwasm-stargate": "0.32.3", 35 | "@cosmjs/encoding": "0.32.3", 36 | "@cosmjs/math": "0.32.3", 37 | "@cosmjs/proto-signing": "0.32.3", 38 | "@cosmjs/stargate": "0.32.3", 39 | "@cosmjs/tendermint-rpc": "0.32.3", 40 | "@initia/initia-registry": "0.1.9", 41 | "@injectivelabs/core-proto-ts": "0.0.x", 42 | "@injectivelabs/sdk-ts": "1.x", 43 | "@keplr-wallet/unit": "^0.12.67", 44 | "@solana/wallet-adapter-base": "^0.9.23", 45 | "@solana/web3.js": "^1.91.1", 46 | "axios": "1.x", 47 | "cosmjs-types": "0.8.x", 48 | "keccak256": "1.x", 49 | "kujira.js": "0.9.x", 50 | "viem": "2.x" 51 | }, 52 | "devDependencies": { 53 | "@cosmjs/faucet": "0.32.3", 54 | "@cosmjs/faucet-client": "0.32.3", 55 | "@cosmology/telescope": "^1.4.12", 56 | "@protobufs/gogoproto": "^0.0.10", 57 | "@protobufs/google": "^0.0.10", 58 | "minimatch": "^9.0.3", 59 | "proxy-from-env": "^1.1.0", 60 | "vitest": "^1.2.2" 61 | }, 62 | "publishConfig": { 63 | "access": "public", 64 | "provenance": true 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /packages/core/parser.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./dist/parser"; 2 | -------------------------------------------------------------------------------- /packages/core/parser.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./dist/parser"); 2 | -------------------------------------------------------------------------------- /packages/core/scripts/codegen.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | /* eslint-disable @typescript-eslint/no-var-requires */ 3 | 4 | const fs = require("fs/promises"); 5 | const path = require("path"); 6 | const telescope = require("@cosmology/telescope").default; 7 | const protoDirs = require("../../../vendor"); 8 | 9 | async function codegen() { 10 | const outPath = path.resolve(__dirname, "../src/codegen/"); 11 | 12 | await fs 13 | .rm(outPath, { recursive: true, force: true }) 14 | .catch(() => {}) 15 | .then(() => fs.mkdir(outPath, { recursive: true })) 16 | .then(() => fs.writeFile(path.resolve(outPath, ".gitkeep"), "", "utf-8")); 17 | 18 | await telescope({ 19 | protoDirs, 20 | outPath, 21 | options: { 22 | aminoEncoding: { 23 | customTypes: { 24 | useCosmosSDKDec: true, 25 | }, 26 | enabled: true, 27 | exceptions: { 28 | // https://github.com/evmos/evmos/blob/v16.0.3/crypto/ethsecp256k1/ethsecp256k1.go#L33 29 | "/ethermint.crypto.v1.ethsecp256k1.PrivKey": { 30 | aminoType: "ethermint/PrivKeyEthSecp256k1", 31 | }, 32 | // https://github.com/evmos/evmos/blob/v16.0.3/crypto/ethsecp256k1/ethsecp256k1.go#L35 33 | "/ethermint.crypto.v1.ethsecp256k1.PubKey": { 34 | aminoType: "ethermint/PubKeyEthSecp256k1", 35 | }, 36 | }, 37 | typeUrlToAmino: (typeUrl) => { 38 | /** 39 | * regex to match typeUrl, e.g.: 40 | * - typeUrl : /ethermint.evm.v1.MsgUpdateParams 41 | * - mod : ethermint 42 | * - submod : evm 43 | * - version : v1 44 | * - type : MsgUpdateParams 45 | */ 46 | const matcher = 47 | /^\/(?\w+)\.(?\w+)\.(?\w+)\.(?\w+)/; 48 | 49 | const { mod, submod, type } = typeUrl.match(matcher)?.groups ?? {}; 50 | 51 | // https://github.com/circlefin/noble-cctp/blob/release-2024-01-09T183203/x/cctp/types/codec.go#L30-L56 52 | if (typeUrl.startsWith("/circle.cctp.v1.Msg")) { 53 | return typeUrl.replace("/circle.cctp.v1.Msg", "cctp/"); 54 | } 55 | 56 | /** 57 | * lookup mod to assign primary MsgUpdateParams amino type, e.g.: 58 | * 59 | * - typeUrl : ethermint.evm.v1.MsgUpdateParams 60 | * - mod : ethermint 61 | * - submod : evm 62 | * - type : ethermint/MsgUpdateParams 63 | * 64 | * @type {Record} 65 | */ 66 | const lookup = { 67 | ethermint: "evm", 68 | evmos: "revenue", 69 | }; 70 | 71 | if (mod && lookup[mod]) { 72 | if (type === "MsgUpdateParams" && lookup[mod] === submod) { 73 | return `${mod}/MsgUpdateParams`; 74 | } 75 | if (type === "MsgUpdateParams") { 76 | return `${mod}/${submod}/MsgUpdateParams`; 77 | } 78 | if (type?.startsWith("Msg")) { 79 | return `${mod}/${type}`; 80 | } 81 | return `${submod}/${type}`; 82 | } 83 | }, 84 | }, 85 | bundle: { 86 | enabled: false, 87 | }, 88 | interfaces: { 89 | enabled: false, 90 | useByDefault: false, 91 | useUnionTypes: false, 92 | }, 93 | lcdClients: { 94 | enabled: false, 95 | }, 96 | prototypes: { 97 | addTypeUrlToDecoders: true, 98 | addTypeUrlToObjects: true, 99 | enableRegistryLoader: false, 100 | enabled: true, 101 | methods: { 102 | decode: true, 103 | encode: true, 104 | fromAmino: true, 105 | fromJSON: true, 106 | fromProto: true, 107 | toAmino: true, 108 | toJSON: true, 109 | toProto: true, 110 | }, 111 | parser: { 112 | keepCase: false, 113 | }, 114 | typingsFormat: { 115 | customTypes: { 116 | useCosmosSDKDec: true, 117 | }, 118 | duration: "duration", 119 | num64: "long", 120 | timestamp: "date", 121 | useDeepPartial: false, 122 | useExact: false, 123 | }, 124 | }, 125 | rpcClients: { 126 | enabled: false, 127 | }, 128 | stargateClients: { 129 | enabled: false, 130 | }, 131 | tsDisable: { 132 | disableAll: true, 133 | }, 134 | }, 135 | }); 136 | } 137 | 138 | void codegen(); 139 | -------------------------------------------------------------------------------- /packages/core/scripts/dev-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | function color() { 6 | local color=$1 7 | shift 8 | local black=30 red=31 green=32 yellow=33 blue=34 magenta=35 cyan=36 white=37 9 | local color_code=${!color:-$green} 10 | printf "\033[%sm%s\033[0m\n" "$color_code" "$*" 11 | } 12 | 13 | # Define a function to install a binary on macOS 14 | install_macos() { 15 | case $1 in 16 | docker) color red "Please install docker. Follow: https://docs.docker.com/desktop/install/mac-install/" ;; 17 | kubectl) brew install kubectl ;; 18 | helm) brew install helm ;; 19 | yq) brew install yq ;; 20 | kind) brew install kind ;; 21 | esac 22 | } 23 | 24 | # Define a function to install a binary on Linux 25 | install_linux() { 26 | color green "Installing $1 at ~/.local/bin, please add it to PATH" 27 | mkdir -p ~/.local/bin 28 | case $1 in 29 | docker) color red "Please install docker. Follow: https://docs.docker.com/engine/install/ubuntu/" ;; 30 | kubectl) curl -Lks "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" > ~/.local/bin/kubectl && chmod +x ~/.local/bin/kubectl ;; 31 | helm) curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash ;; 32 | yq) curl -Lks "https://github.com/mikefarah/yq/releases/download/v4.33.3/yq_linux_amd64" > ~/.local/bin/yq && chmod +x ~/.local/bin/yq ;; 33 | kind) curl -Lks https://kind.sigs.k8s.io/dl/v0.18.0/kind-linux-amd64 > ~/.local/bin/kind && chmod +x ~/.local/bin/kind ;; 34 | esac 35 | } 36 | 37 | # Define a function to install a binary 38 | install_binary() { 39 | if [[ $(uname -s) == "Darwin" ]]; then 40 | install_macos $1 41 | else 42 | install_linux $1 43 | fi 44 | } 45 | 46 | # Define a function to check for the presence of a binary 47 | check_binary() { 48 | if ! command -v $1 &> /dev/null 49 | then 50 | echo "$1 is not installed" 51 | install_binary $1 52 | if ! command -v $1 &> /dev/null 53 | then 54 | color red "Installation of $1 failed, exiting..." 55 | color red "Please install $1 manually, then run me again to verify the installation" 56 | exit 1 57 | fi 58 | fi 59 | } 60 | 61 | # Check the binaries 62 | check_binary kubectl 63 | check_binary helm 64 | check_binary yq 65 | check_binary kind 66 | check_binary docker 67 | 68 | color green "All binaries are installed" -------------------------------------------------------------------------------- /packages/core/scripts/port-forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | function color() { 6 | local color=$1 7 | shift 8 | local black=30 red=31 green=32 yellow=33 blue=34 magenta=35 cyan=36 white=37 9 | local color_code=${!color:-$green} 10 | printf "\033[%sm%s\033[0m\n" "$color_code" "$*" 11 | } 12 | 13 | function stop_port_forward() { 14 | color green "Trying to stop all port-forward, if any...." 15 | PIDS=$(ps -ef | grep -i -e 'kubectl port-forward' | grep -v 'grep' | cat | awk '{print $2}') || true 16 | for p in $PIDS; do 17 | kill -15 $p 18 | done 19 | sleep 2 20 | } 21 | 22 | # Default values 23 | CHAIN_RPC_PORT=26657 24 | CHAIN_LCD_PORT=1317 25 | CHAIN_EXPOSER_PORT=8081 26 | CHAIN_FAUCET_PORT=8000 27 | EXPLORER_LCD_PORT=8080 28 | REGISTRY_LCD_PORT=8080 29 | REGISTRY_GRPC_PORT=9090 30 | 31 | for i in "$@"; do 32 | case $i in 33 | -c=*|--config=*) 34 | CONFIGFILE="${i#*=}" 35 | shift # past argument=value 36 | ;; 37 | -*|--*) 38 | echo "Unknown option $i" 39 | exit 1 40 | ;; 41 | *) 42 | ;; 43 | esac 44 | done 45 | 46 | stop_port_forward 47 | 48 | echo "Port forwarding for config ${CONFIGFILE}" 49 | echo "Port forwarding all chains" 50 | num_chains=$(yq -r ".chains | length - 1" ${CONFIGFILE}) 51 | if [[ $num_chains -lt 0 ]]; then 52 | echo "No chains to port-forward: num: $num_chains" 53 | exit 1 54 | fi 55 | for i in $(seq 0 $num_chains); do 56 | chain=$(yq -r ".chains[$i].name" ${CONFIGFILE} ) 57 | if [[ "$chain" == "evmos_9000-1" ]]; then 58 | chain="evmos-9000-1" 59 | fi 60 | localrpc=$(yq -r ".chains[$i].ports.rpc" ${CONFIGFILE} ) 61 | locallcd=$(yq -r ".chains[$i].ports.rest" ${CONFIGFILE} ) 62 | localexp=$(yq -r ".chains[$i].ports.exposer" ${CONFIGFILE}) 63 | localfaucet=$(yq -r ".chains[$i].ports.faucet" ${CONFIGFILE}) 64 | [[ "$localrpc" != "null" ]] && kubectl port-forward pods/$chain-genesis-0 $localrpc:$CHAIN_RPC_PORT > /dev/null 2>&1 & 65 | [[ "$locallcd" != "null" ]] && kubectl port-forward pods/$chain-genesis-0 $locallcd:$CHAIN_LCD_PORT > /dev/null 2>&1 & 66 | [[ "$localexp" != "null" ]] && kubectl port-forward pods/$chain-genesis-0 $localexp:$CHAIN_EXPOSER_PORT > /dev/null 2>&1 & 67 | [[ "$localfaucet" != "null" ]] && kubectl port-forward pods/$chain-genesis-0 $localfaucet:$CHAIN_FAUCET_PORT > /dev/null 2>&1 & 68 | sleep 1 69 | color yellow "chains: forwarded $chain lcd to http://localhost:$locallcd, rpc to http://localhost:$localrpc, faucet to http://localhost:$localfaucet" 70 | done 71 | 72 | echo "Port forward services" 73 | 74 | if [[ $(yq -r ".registry.enabled" $CONFIGFILE) == "true" ]]; 75 | then 76 | kubectl port-forward service/registry 8081:$REGISTRY_LCD_PORT > /dev/null 2>&1 & 77 | kubectl port-forward service/registry 9091:$REGISTRY_GRPC_PORT > /dev/null 2>&1 & 78 | sleep 1 79 | color yellow "registry: forwarded registry lcd to grpc http://localhost:8081, to http://localhost:9091" 80 | fi 81 | 82 | if [[ $(yq -r ".explorer.enabled" $CONFIGFILE) == "true" ]]; 83 | then 84 | kubectl port-forward service/explorer 8080:$EXPLORER_LCD_PORT > /dev/null 2>&1 & 85 | sleep 1 86 | color green "Open the explorer to get started.... http://localhost:8080" 87 | fi -------------------------------------------------------------------------------- /packages/core/scripts/prepublish.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | 3 | const fs = require("fs/promises"); 4 | const path = require("path"); 5 | const packageJson = require("../package.json"); 6 | 7 | async function prepublish() { 8 | delete packageJson.scripts; 9 | delete packageJson.devDependencies; 10 | const targetPath = path.resolve(process.cwd(), "package.json"); 11 | await fs.writeFile(targetPath, JSON.stringify(packageJson, null, 2), { 12 | encoding: "utf-8", 13 | }); 14 | } 15 | 16 | void prepublish(); 17 | -------------------------------------------------------------------------------- /packages/core/src/amino/README.md: -------------------------------------------------------------------------------- 1 | # amino 2 | 3 | https://github.com/archmage-live/archmage-x/tree/develop/lib/network/cosm 4 | -------------------------------------------------------------------------------- /packages/core/src/amino/addresses.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/archmage-live/archmage-x/blob/develop/lib/network/cosm/amino/addresses.ts 2 | 3 | import { 4 | Pubkey, 5 | pubkeyToRawAddress as cosmPubkeyToRawAddress, 6 | } from "@cosmjs/amino"; 7 | import { keccak256 } from "@cosmjs/crypto"; 8 | import { fromBase64, toBech32 } from "@cosmjs/encoding"; 9 | 10 | import { isEthSecp256k1Pubkey } from "./pubkey"; 11 | 12 | export function rawEthSecp256k1PubkeyToRawAddress( 13 | pubkeyData: Uint8Array, 14 | ): Uint8Array { 15 | if (pubkeyData.length !== 65) { 16 | throw new Error( 17 | `Invalid ETHSecp256k1 pubkey length (compressed): ${pubkeyData.length}`, 18 | ); 19 | } 20 | return keccak256(pubkeyData.slice(1)).slice(-20); 21 | } 22 | 23 | export function pubkeyToRawAddress(pubkey: Pubkey): Uint8Array { 24 | if (isEthSecp256k1Pubkey(pubkey)) { 25 | const pubkeyData = fromBase64(pubkey.value); 26 | return rawEthSecp256k1PubkeyToRawAddress(pubkeyData); 27 | } else { 28 | return cosmPubkeyToRawAddress(pubkey); 29 | } 30 | } 31 | 32 | export function pubkeyToAddress(pubkey: Pubkey, prefix: string): string { 33 | return toBech32(prefix, pubkeyToRawAddress(pubkey)); 34 | } 35 | -------------------------------------------------------------------------------- /packages/core/src/amino/encoding.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/archmage-live/archmage-x/blob/develop/lib/network/cosm/amino/encoding.ts 2 | 3 | import { toBase64 } from "@cosmjs/encoding"; 4 | 5 | import { EthSecp256k1Pubkey, pubkeyType } from "./pubkey"; 6 | 7 | export function encodeEthSecp256k1Pubkey( 8 | pubkey: Uint8Array, 9 | ): EthSecp256k1Pubkey { 10 | if (pubkey.length !== 33 || (pubkey[0] !== 0x02 && pubkey[0] !== 0x03)) { 11 | throw new Error( 12 | "Public key must be compressed secp256k1, i.e. 33 bytes starting with 0x02 or 0x03", 13 | ); 14 | } 15 | return { 16 | type: pubkeyType.ethsecp256k1, 17 | value: toBase64(pubkey), 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/amino/pubkey.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/archmage-live/archmage-x/blob/develop/lib/network/cosm/amino/pubkey.ts 2 | 3 | import { 4 | Pubkey, 5 | SinglePubkey, 6 | pubkeyType as cosmPubkeyType, 7 | } from "@cosmjs/amino"; 8 | 9 | export interface EthSecp256k1Pubkey extends SinglePubkey { 10 | readonly type: "ethermint/PubKeyEthSecp256k1"; 11 | readonly value: string; 12 | } 13 | 14 | export function isEthSecp256k1Pubkey( 15 | pubkey: Pubkey, 16 | ): pubkey is EthSecp256k1Pubkey { 17 | return (pubkey as EthSecp256k1Pubkey).type === "ethermint/PubKeyEthSecp256k1"; 18 | } 19 | 20 | export const pubkeyType = { 21 | ethsecp256k1: "ethermint/PubKeyEthSecp256k1" as const, 22 | ...cosmPubkeyType, 23 | }; 24 | -------------------------------------------------------------------------------- /packages/core/src/amino/signature.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/archmage-live/archmage-x/blob/develop/lib/network/cosm/amino/signature.ts 2 | 3 | import { 4 | StdSignature, 5 | decodeSignature as cosmDecodeSignature, 6 | } from "@cosmjs/amino"; 7 | import { fromBase64, toBase64 } from "@cosmjs/encoding"; 8 | 9 | import { encodeEthSecp256k1Pubkey } from "./encoding"; 10 | import { pubkeyType } from "./pubkey"; 11 | 12 | /** 13 | * Takes a binary pubkey and signature to create a signature object 14 | * 15 | * @param pubkey a compressed eth_secp256k1 public key 16 | * @param signature a 64 byte fixed length representation of eth_secp256k1 signature components r and s 17 | */ 18 | export function encodeEthSecp256k1Signature( 19 | pubkey: Uint8Array, 20 | signature: Uint8Array, 21 | ): StdSignature { 22 | if (signature.length !== 64) { 23 | throw new Error( 24 | "Signature must be 64 bytes long. Merlion uses a 2x32 byte fixed length encoding for the eth_secp256k1 signature integers r and s.", 25 | ); 26 | } 27 | 28 | return { 29 | pub_key: encodeEthSecp256k1Pubkey(pubkey), 30 | signature: toBase64(signature), 31 | }; 32 | } 33 | 34 | export function decodeSignature(signature: StdSignature): { 35 | readonly pubkey: Uint8Array; 36 | readonly signature: Uint8Array; 37 | } { 38 | switch (signature.pub_key.type) { 39 | // Note: please don't add cases here without writing additional unit tests 40 | case pubkeyType.ethsecp256k1: 41 | return { 42 | pubkey: fromBase64(signature.pub_key.value), 43 | signature: fromBase64(signature.signature), 44 | }; 45 | default: 46 | return cosmDecodeSignature(signature); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/core/src/chains.ts: -------------------------------------------------------------------------------- 1 | import * as chainRegistry from "chain-registry"; 2 | import * as initiaRegistry from "@initia/initia-registry"; 3 | 4 | /** @deprecated */ 5 | const DYDX_CHAIN = { 6 | $schema: "../chain.schema.json", 7 | chain_name: "dydx", 8 | status: "live", 9 | website: "https://dydx.exchange/", 10 | network_type: "mainnet", 11 | pretty_name: "dYdX Protocol", 12 | chain_id: "dydx-mainnet-1", 13 | bech32_prefix: "dydx", 14 | daemon_name: "dydxprotocold", 15 | node_home: "$HOME/.dydxprotocol", 16 | key_algos: ["secp256k1"], 17 | slip44: 118, 18 | fees: { 19 | fee_tokens: [ 20 | { 21 | denom: "adydx", 22 | fixed_min_gas_price: 12500000000, 23 | low_gas_price: 12500000000, 24 | average_gas_price: 12500000000, 25 | high_gas_price: 20000000000, 26 | }, 27 | { 28 | denom: 29 | "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5", 30 | fixed_min_gas_price: 0.025, 31 | low_gas_price: 0.025, 32 | average_gas_price: 0.025, 33 | high_gas_price: 0.03, 34 | }, 35 | ], 36 | }, 37 | staking: { 38 | staking_tokens: [ 39 | { 40 | denom: "adydx", 41 | }, 42 | ], 43 | }, 44 | codebase: { 45 | git_repo: "https://github.com/dydxprotocol/v4-chain/", 46 | recommended_version: "v1.0.0", 47 | compatible_versions: ["v1.0.0"], 48 | cosmos_sdk_version: "v0.47.4", 49 | cosmwasm_enabled: false, 50 | genesis: { 51 | genesis_url: 52 | "https://raw.githubusercontent.com/dydxopsdao/networks/main/dydx-mainnet-1/genesis.json", 53 | }, 54 | versions: [ 55 | { 56 | name: "v1", 57 | recommended_version: "v1.0.0", 58 | compatible_versions: ["v1.0.0"], 59 | cosmos_sdk_version: "v0.47.4", 60 | }, 61 | ], 62 | }, 63 | logo_URIs: { 64 | png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/dydx/images/dydx.png", 65 | svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/dydx/images/dydx.svg", 66 | }, 67 | peers: { 68 | seeds: [ 69 | { 70 | id: "20e1000e88125698264454a884812746c2eb4807", 71 | address: "seeds.lavenderfive.com:23856", 72 | provider: "Lavender.Five Nodes 🐝", 73 | }, 74 | { 75 | id: "ebc272824924ea1a27ea3183dd0b9ba713494f83", 76 | address: "dydx-mainnet-seed.autostake.com:27366", 77 | provider: "AutoStake 🛡️ Slash Protected", 78 | }, 79 | { 80 | id: "65b740ee326c9260c30af1f044e9cda63c73f7c1", 81 | address: "seeds.kingnodes.net:23856", 82 | provider: "Kingnodes", 83 | }, 84 | { 85 | id: "4c30c8a95e26b07b249813b677caab28bf0c54eb", 86 | address: "rpc.dydx.nodestake.top:666", 87 | provider: "NodeStake", 88 | }, 89 | { 90 | id: "400f3d9e30b69e78a7fb891f60d76fa3c73f0ecc", 91 | address: "dydx.rpc.kjnodes.com:17059", 92 | provider: "kjnodes", 93 | }, 94 | { 95 | id: "e1b058e5cfa2b836ddaa496b10911da62dcf182e", 96 | address: "dydx-seed-de.allnodes.me:26656", 97 | provider: "Allnodes ⚡️ Nodes & Staking", 98 | }, 99 | { 100 | id: "e726816f42831689eab9378d5d577f1d06d25716", 101 | address: "dydx-seed-us.allnodes.me:26656", 102 | provider: "Allnodes ⚡️ Nodes & Staking", 103 | }, 104 | ], 105 | persistent_peers: [ 106 | { 107 | id: "ebc272824924ea1a27ea3183dd0b9ba713494f83", 108 | address: "dydx-mainnet-peer.autostake.com:27366", 109 | provider: "AutoStake 🛡️ Slash Protected", 110 | }, 111 | ], 112 | }, 113 | apis: { 114 | rpc: [ 115 | { 116 | address: "https://dydx-rpc.lavenderfive.com:443", 117 | provider: "Lavender.Five Nodes 🐝", 118 | }, 119 | { 120 | address: "https://dydx-mainnet-rpc.autostake.com:443", 121 | provider: "AutoStake 🛡️ Slash Protected", 122 | }, 123 | { 124 | address: "https://rpc-dydx.ecostake.com:443", 125 | provider: "ecostake", 126 | }, 127 | { 128 | address: "https://rpc.dydx.nodestake.top:443", 129 | provider: "NodeStake", 130 | }, 131 | { 132 | address: "https://dydx.rpc.kjnodes.com:443", 133 | provider: "kjnodes", 134 | }, 135 | { 136 | address: "https://dydx-rpc.publicnode.com:443", 137 | provider: "Allnodes ⚡️ Nodes & Staking", 138 | }, 139 | ], 140 | rest: [ 141 | { 142 | address: "https://dydx-api.lavenderfive.com:443", 143 | provider: "Lavender.Five Nodes 🐝", 144 | }, 145 | { 146 | address: "https://dydx-mainnet-lcd.autostake.com:443", 147 | provider: "AutoStake 🛡️ Slash Protected", 148 | }, 149 | { 150 | address: "https://rest-dydx.ecostake.com:443", 151 | provider: "ecostake", 152 | }, 153 | { 154 | address: "https://api.dydx.nodestake.top:443", 155 | provider: "NodeStake", 156 | }, 157 | { 158 | address: "https://dydx.api.kjnodes.com:443", 159 | provider: "kjnodes", 160 | }, 161 | { 162 | address: "https://dydx-rest.publicnode.com", 163 | provider: "Allnodes ⚡️ Nodes & Staking", 164 | }, 165 | ], 166 | grpc: [ 167 | { 168 | address: "https://dydx-grpc.lavenderfive.com", 169 | provider: "Lavender.Five Nodes 🐝", 170 | }, 171 | { 172 | address: "dydx-mainnet-grpc.autostake.com:443", 173 | provider: "AutoStake 🛡️ Slash Protected", 174 | }, 175 | { 176 | address: "https://grpc.dydx.nodestake.top", 177 | provider: "NodeStake", 178 | }, 179 | { 180 | address: "dydx.grpc.kjnodes.com:443", 181 | provider: "kjnodes", 182 | }, 183 | { 184 | address: "dydx-grpc.publicnode.com:443", 185 | provider: "Allnodes ⚡️ Nodes & Staking", 186 | }, 187 | ], 188 | }, 189 | explorers: [ 190 | { 191 | kind: "mintscan", 192 | url: "https://www.mintscan.io/dydx", 193 | tx_page: "https://www.mintscan.io/dydx/txs/${txHash}", 194 | account_page: "https://www.mintscan.io/dydx/account/${accountAddress}", 195 | }, 196 | { 197 | kind: "NodeStake", 198 | url: "https://explorer.nodestake.top/dydx/", 199 | tx_page: "https://explorer.nodestake.top/dydx/txs/${txHash}", 200 | account_page: 201 | "https://explorer.nodestake.top/dydx/account/${accountAddress}", 202 | }, 203 | ], 204 | images: [ 205 | { 206 | png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/dydx/images/dydx.png", 207 | svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/dydx/images/dydx.svg", 208 | }, 209 | ], 210 | }; 211 | 212 | /** @deprecated */ 213 | const CELESTIA_CHAIN = { 214 | $schema: "../chain.schema.json", 215 | chain_name: "celestia", 216 | chain_id: "celestia", 217 | pretty_name: "Celestia", 218 | status: "live", 219 | network_type: "mainnet", 220 | bech32_prefix: "celestia", 221 | daemon_name: "celestia-appd", 222 | node_home: "$HOME/.celestia-app", 223 | key_algos: ["secp256k1"], 224 | slip44: 118, 225 | fees: { 226 | fee_tokens: [ 227 | { 228 | denom: "utia", 229 | fixed_min_gas_price: 0, 230 | low_gas_price: 0.1, 231 | average_gas_price: 0.2, 232 | high_gas_price: 0.4, 233 | }, 234 | ], 235 | }, 236 | codebase: { 237 | git_repo: "https://github.com/celestiaorg/celestia-app", 238 | recommended_version: "v1.3.0", 239 | compatible_versions: ["v1.3.0"], 240 | genesis: { 241 | genesis_url: 242 | "https://raw.githubusercontent.com/celestiaorg/networks/master/celestia/genesis.json", 243 | }, 244 | versions: [ 245 | { 246 | name: "v1.3.0", 247 | recommended_version: "v1.3.0", 248 | compatible_versions: ["v1.3.0"], 249 | }, 250 | ], 251 | }, 252 | peers: { 253 | seeds: [ 254 | { 255 | id: "e6116822e1a5e283d8a85d3ec38f4d232274eaf3", 256 | address: "consensus-full-seed-1.celestia-bootstrap.net:26656", 257 | provider: "Celestia Foundation", 258 | }, 259 | { 260 | id: "cf7ac8b19ff56a9d47c75551bd4864883d1e24b5", 261 | address: "consensus-full-seed-1.celestia-bootstrap.net:26656", 262 | provider: "Celestia Foundation", 263 | }, 264 | ], 265 | }, 266 | apis: { 267 | rpc: [ 268 | { 269 | address: "https://public-celestia-rpc.numia.xyz", 270 | provider: "Numia", 271 | }, 272 | { 273 | address: "https://celestia-rpc.mesa.newmetric.xyz", 274 | provider: "Newmetric", 275 | }, 276 | { 277 | address: "https://rpc.lunaroasis.net", 278 | provider: "Lunar Oasis", 279 | }, 280 | ], 281 | rest: [ 282 | { 283 | address: "https://public-celestia-lcd.numia.xyz", 284 | provider: "Numia", 285 | }, 286 | { 287 | address: "https://celestia-rest.mesa.newmetric.xyz", 288 | provider: "Newmetric", 289 | }, 290 | { 291 | address: "https://api.lunaroasis.net", 292 | provider: "Lunar Oasis", 293 | }, 294 | ], 295 | }, 296 | explorers: [ 297 | { 298 | kind: "Mintscan", 299 | url: "https://mintscan.io/celestia", 300 | tx_page: "https://mintscan.io/celestia/txs/${txHash}", 301 | }, 302 | ], 303 | }; 304 | 305 | /** @deprecated */ 306 | export function chains() { 307 | const chains = chainRegistry.chains; 308 | 309 | if (chains.findIndex((chain) => chain.chain_id === "dydx-mainnet-1") === -1) { 310 | chains.push(DYDX_CHAIN); 311 | } 312 | 313 | if (chains.findIndex((chain) => chain.chain_id === "celestia") === -1) { 314 | chains.push(CELESTIA_CHAIN); 315 | } 316 | 317 | return chains; 318 | } 319 | 320 | export function initiaChains() { 321 | const chains = initiaRegistry.chains; 322 | 323 | return chains; 324 | } 325 | -------------------------------------------------------------------------------- /packages/core/src/client-types.ts: -------------------------------------------------------------------------------- 1 | import { Coin, OfflineAminoSigner } from "@cosmjs/amino"; 2 | import { 3 | GeneratedType, 4 | OfflineDirectSigner, 5 | OfflineSigner, 6 | } from "@cosmjs/proto-signing"; 7 | import { 8 | AminoConverters, 9 | GasPrice, 10 | SignerData, 11 | StdFee, 12 | } from "@cosmjs/stargate"; 13 | 14 | import { WalletClient } from "viem"; 15 | 16 | import * as types from "./types"; 17 | import { Adapter } from "@solana/wallet-adapter-base"; 18 | 19 | export interface UserAddress { 20 | chainID: string; 21 | address: string; 22 | } 23 | 24 | export type EndpointOptions = { 25 | rpc?: string; 26 | rest?: string; 27 | }; 28 | 29 | export interface SkipRouterOptions { 30 | apiURL?: string; 31 | apiKey?: string; 32 | getEVMSigner?: (chainID: string) => Promise; 33 | getCosmosSigner?: (chainID: string) => Promise; 34 | getSVMSigner?: () => Promise; 35 | endpointOptions?: { 36 | endpoints?: Record; 37 | getRpcEndpointForChain?: (chainID: string) => Promise; 38 | getRestEndpointForChain?: (chainID: string) => Promise; 39 | }; 40 | aminoTypes?: AminoConverters; 41 | registryTypes?: Iterable<[string, GeneratedType]>; 42 | } 43 | 44 | export type ExecuteRouteOptions = { 45 | route: types.RouteResponse; 46 | /** 47 | * addresses should be in the same order with the `chainIDs` in the `route` 48 | */ 49 | userAddresses: UserAddress[]; 50 | getEVMSigner?: (chainID: string) => Promise; 51 | getCosmosSigner?: (chainID: string) => Promise; 52 | getSVMSigner?: () => Promise; 53 | onTransactionBroadcast?: (txInfo: { 54 | txHash: string; 55 | chainID: string; 56 | }) => Promise; 57 | onTransactionTracked?: (txInfo: { 58 | txHash: string; 59 | chainID: string; 60 | }) => Promise; 61 | onTransactionCompleted?: ( 62 | chainID: string, 63 | txHash: string, 64 | status: types.TxStatusResponse, 65 | ) => Promise; 66 | validateGasBalance?: boolean; 67 | slippageTolerancePercent?: string; 68 | /** 69 | * If `getGasPrice` is undefined, or returns undefined, the router will attempt to set the recommended gas price 70 | **/ 71 | getGasPrice?: (chainID: string) => Promise; 72 | /** 73 | * If `getFallbackGasAmount` is set, when router fails to simulate the gas amount, it will use the fallback gas amount 74 | */ 75 | getFallbackGasAmount?: GetFallbackGasAmount; 76 | gasAmountMultiplier?: number; 77 | }; 78 | 79 | export type ExecuteCosmosMessageOptions = { 80 | signerAddress: string; 81 | signer: OfflineSigner; 82 | message: types.MultiChainMsg; 83 | fee: StdFee; 84 | }; 85 | 86 | export type ExecuteCosmosMessage = { 87 | signerAddress: string; 88 | getCosmosSigner?: (chainID: string) => Promise; 89 | /** 90 | * If `getGasPrice` is undefined, or returns undefined, the router will attempt to set the recommended gas price 91 | **/ 92 | getGasPrice?: GetGasPrice; 93 | /** 94 | * If `getFallbackGasAmount` is set, when router fails to simulate the gas amount, it will use the fallback gas amount 95 | */ 96 | getFallbackGasAmount?: GetFallbackGasAmount; 97 | chainID: string; 98 | messages: types.CosmosMsg[]; 99 | gasAmountMultiplier?: number; 100 | gasTokenUsed?: Coin; 101 | }; 102 | 103 | export type SignCosmosMessageDirectOptions = { 104 | signerAddress: string; 105 | signer: OfflineDirectSigner; 106 | chainID: string; 107 | cosmosMsgs: types.CosmosMsg[]; 108 | fee: StdFee; 109 | signerData: SignerData; 110 | }; 111 | 112 | export type SignCosmosMessageAminoOptions = { 113 | signerAddress: string; 114 | signer: OfflineAminoSigner; 115 | chainID: string; 116 | cosmosMsgs: types.CosmosMsg[]; 117 | fee: StdFee; 118 | signerData: SignerData; 119 | }; 120 | 121 | export type GetFallbackGasAmount = ( 122 | chainID: string, 123 | chainType: "cosmos" | "evm" | "svm", 124 | ) => Promise; 125 | 126 | export type GetGasPrice = ( 127 | chainID: string, 128 | chainType: "cosmos" | "evm" | "svm", 129 | ) => Promise; 130 | -------------------------------------------------------------------------------- /packages/core/src/codegen/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skip-mev/skip-router-sdk/fc37fa8c7c2c64954557d698f61bf8ef0a18e2df/packages/core/src/codegen/.gitkeep -------------------------------------------------------------------------------- /packages/core/src/constants/abis.ts: -------------------------------------------------------------------------------- 1 | import { Abi } from "viem"; 2 | 3 | export function createAbi(abi: TAbi) { 4 | return abi; 5 | } 6 | 7 | export const erc20ABI = /* #__PURE__ */ createAbi([ 8 | { 9 | type: "event", 10 | name: "Approval", 11 | inputs: [ 12 | { 13 | indexed: true, 14 | name: "owner", 15 | type: "address", 16 | }, 17 | { 18 | indexed: true, 19 | name: "spender", 20 | type: "address", 21 | }, 22 | { 23 | indexed: false, 24 | name: "value", 25 | type: "uint256", 26 | }, 27 | ], 28 | }, 29 | { 30 | type: "event", 31 | name: "Transfer", 32 | inputs: [ 33 | { 34 | indexed: true, 35 | name: "from", 36 | type: "address", 37 | }, 38 | { 39 | indexed: true, 40 | name: "to", 41 | type: "address", 42 | }, 43 | { 44 | indexed: false, 45 | name: "value", 46 | type: "uint256", 47 | }, 48 | ], 49 | }, 50 | { 51 | type: "function", 52 | name: "allowance", 53 | stateMutability: "view", 54 | inputs: [ 55 | { 56 | name: "owner", 57 | type: "address", 58 | }, 59 | { 60 | name: "spender", 61 | type: "address", 62 | }, 63 | ], 64 | outputs: [ 65 | { 66 | name: "", 67 | type: "uint256", 68 | }, 69 | ], 70 | }, 71 | { 72 | type: "function", 73 | name: "approve", 74 | stateMutability: "nonpayable", 75 | inputs: [ 76 | { 77 | name: "spender", 78 | type: "address", 79 | }, 80 | { 81 | name: "amount", 82 | type: "uint256", 83 | }, 84 | ], 85 | outputs: [ 86 | { 87 | name: "", 88 | type: "bool", 89 | }, 90 | ], 91 | }, 92 | { 93 | type: "function", 94 | name: "balanceOf", 95 | stateMutability: "view", 96 | inputs: [ 97 | { 98 | name: "account", 99 | type: "address", 100 | }, 101 | ], 102 | outputs: [ 103 | { 104 | name: "", 105 | type: "uint256", 106 | }, 107 | ], 108 | }, 109 | { 110 | type: "function", 111 | name: "decimals", 112 | stateMutability: "view", 113 | inputs: [], 114 | outputs: [ 115 | { 116 | name: "", 117 | type: "uint8", 118 | }, 119 | ], 120 | }, 121 | { 122 | type: "function", 123 | name: "name", 124 | stateMutability: "view", 125 | inputs: [], 126 | outputs: [ 127 | { 128 | name: "", 129 | type: "string", 130 | }, 131 | ], 132 | }, 133 | { 134 | type: "function", 135 | name: "symbol", 136 | stateMutability: "view", 137 | inputs: [], 138 | outputs: [ 139 | { 140 | name: "", 141 | type: "string", 142 | }, 143 | ], 144 | }, 145 | { 146 | type: "function", 147 | name: "totalSupply", 148 | stateMutability: "view", 149 | inputs: [], 150 | outputs: [ 151 | { 152 | name: "", 153 | type: "uint256", 154 | }, 155 | ], 156 | }, 157 | { 158 | type: "function", 159 | name: "transfer", 160 | stateMutability: "nonpayable", 161 | inputs: [ 162 | { 163 | name: "recipient", 164 | type: "address", 165 | }, 166 | { 167 | name: "amount", 168 | type: "uint256", 169 | }, 170 | ], 171 | outputs: [ 172 | { 173 | name: "", 174 | type: "bool", 175 | }, 176 | ], 177 | }, 178 | { 179 | type: "function", 180 | name: "transferFrom", 181 | stateMutability: "nonpayable", 182 | inputs: [ 183 | { 184 | name: "sender", 185 | type: "address", 186 | }, 187 | { 188 | name: "recipient", 189 | type: "address", 190 | }, 191 | { 192 | name: "amount", 193 | type: "uint256", 194 | }, 195 | ], 196 | outputs: [ 197 | { 198 | name: "", 199 | type: "bool", 200 | }, 201 | ], 202 | }, 203 | ] as const); 204 | -------------------------------------------------------------------------------- /packages/core/src/constants/constants.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_GAS_DENOM_OVERRIDES: Record = 2 | /* #__PURE__ */ { 3 | "noble-1": "uusdc", 4 | }; 5 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./client"; 2 | export * from "./client-types"; 3 | export * from "./types"; 4 | export * from "./transactions"; 5 | -------------------------------------------------------------------------------- /packages/core/src/injective/index.ts: -------------------------------------------------------------------------------- 1 | import { StdFee } from "@cosmjs/amino"; 2 | import { 3 | CosmosTxSigningV1Beta1Signing, 4 | CosmosTxV1Beta1Tx, 5 | } from "@injectivelabs/core-proto-ts"; 6 | import { 7 | createAuthInfo, 8 | createBody, 9 | createFee, 10 | createSignDoc, 11 | createSigners, 12 | } from "@injectivelabs/sdk-ts/dist/cjs/core/modules/tx/utils/tx"; 13 | import { DEFAULT_STD_FEE } from "@injectivelabs/utils"; 14 | import keccak256 from "keccak256"; 15 | 16 | export interface CreateTransactionArgs { 17 | fee?: StdFee; // the fee to include in the transaction 18 | memo?: string; // the memo to include in the transaction 19 | chainId: string; // the chain id of the chain that the transaction is going to be broadcasted to 20 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 21 | message: any | any[]; // the message that should be packed into the transaction 22 | pubKey: string; // the pubKey of the signer of the transaction in base64 23 | sequence: number; // the sequence (nonce) of the signer of the transaction 24 | accountNumber: number; // the account number of the signer of the transaction 25 | signMode?: CosmosTxSigningV1Beta1Signing.SignMode; 26 | timeoutHeight?: number; // the height at which the transaction should be considered invalid 27 | } 28 | 29 | export function createTransaction({ 30 | chainId, 31 | message, 32 | timeoutHeight, 33 | memo = "", 34 | fee = DEFAULT_STD_FEE, 35 | signMode = 1, 36 | pubKey, 37 | accountNumber, 38 | sequence, 39 | }: CreateTransactionArgs) { 40 | const signers = { 41 | pubKey: pubKey, 42 | accountNumber: accountNumber, 43 | sequence: sequence, 44 | }; 45 | 46 | const actualSigners = Array.isArray(signers) ? signers : [signers]; 47 | const [signer] = actualSigners; 48 | 49 | const body = createBody({ message, memo, timeoutHeight }); 50 | 51 | if (!fee.amount[0]) { 52 | throw new Error("createTransaction error: unable to get fee amount"); 53 | } 54 | 55 | const feeMessage = createFee({ 56 | fee: fee.amount[0], 57 | payer: fee.payer, 58 | granter: fee.granter, 59 | gasLimit: parseInt(fee.gas, 10), 60 | }); 61 | 62 | const signInfo = createSigners({ 63 | chainId, 64 | mode: signMode, 65 | signers: actualSigners, 66 | }); 67 | 68 | const authInfo = createAuthInfo({ 69 | signerInfo: signInfo, 70 | fee: feeMessage, 71 | }); 72 | 73 | const bodyBytes = CosmosTxV1Beta1Tx.TxBody.encode(body).finish(); 74 | const authInfoBytes = CosmosTxV1Beta1Tx.AuthInfo.encode(authInfo).finish(); 75 | 76 | const signDoc = createSignDoc({ 77 | chainId, 78 | bodyBytes: bodyBytes, 79 | authInfoBytes: authInfoBytes, 80 | accountNumber: signer.accountNumber, 81 | }); 82 | 83 | const signDocBytes = CosmosTxV1Beta1Tx.SignDoc.encode(signDoc).finish(); 84 | 85 | const toSignBytes = Buffer.from(signDocBytes); 86 | const toSignHash = keccak256(Buffer.from(signDocBytes)); 87 | 88 | const txRaw = CosmosTxV1Beta1Tx.TxRaw.create(); 89 | txRaw.authInfoBytes = authInfoBytes; 90 | txRaw.bodyBytes = bodyBytes; 91 | 92 | return { 93 | txRaw, 94 | signDoc, 95 | signers, 96 | signer, 97 | signBytes: toSignBytes, 98 | signHashedBytes: toSignHash, 99 | bodyBytes: bodyBytes, 100 | authInfoBytes: authInfoBytes, 101 | }; 102 | } 103 | -------------------------------------------------------------------------------- /packages/core/src/parser.ts: -------------------------------------------------------------------------------- 1 | export { accountParser } from "kujira.js"; 2 | -------------------------------------------------------------------------------- /packages/core/src/proto-signing/README.md: -------------------------------------------------------------------------------- 1 | # proto-signing 2 | 3 | https://github.com/archmage-live/archmage-x/tree/develop/lib/network/cosm 4 | -------------------------------------------------------------------------------- /packages/core/src/proto-signing/directethsecp256k1wallet.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/archmage-live/archmage-x/blob/develop/lib/network/cosm/proto-signing/directethsecp256k1wallet.ts 2 | 3 | import { Secp256k1, keccak256 } from "@cosmjs/crypto"; 4 | import { toBech32 } from "@cosmjs/encoding"; 5 | import { DirectSignResponse, makeSignBytes } from "@cosmjs/proto-signing"; 6 | import { SignDoc } from "cosmjs-types/cosmos/tx/v1beta1/tx"; 7 | 8 | import { AccountData, OfflineDirectSigner } from "./signer"; 9 | import { rawEthSecp256k1PubkeyToRawAddress } from "../amino/addresses"; 10 | import { encodeEthSecp256k1Signature } from "../amino/signature"; 11 | 12 | /** 13 | * A wallet that holds a single eth_secp256k1 keypair. 14 | * 15 | * If you want to work with BIP39 mnemonics and multiple accounts, use DirectEthSecp256k1HdWallet. 16 | */ 17 | export class DirectEthSecp256k1Wallet implements OfflineDirectSigner { 18 | /** 19 | * Creates a DirectEthSecp256k1Wallet from the given private key 20 | * 21 | * @param privkey The private key. 22 | * @param prefix The bech32 address prefix (human-readable part). Defaults to "mer". 23 | */ 24 | public static async fromKey( 25 | privkey: Uint8Array, 26 | prefix = "mer", 27 | ): Promise { 28 | const uncompressed = (await Secp256k1.makeKeypair(privkey)).pubkey; 29 | return new DirectEthSecp256k1Wallet( 30 | privkey, 31 | Secp256k1.compressPubkey(uncompressed), 32 | prefix, 33 | ); 34 | } 35 | 36 | private readonly pubkey: Uint8Array; 37 | private readonly privkey: Uint8Array; 38 | private readonly prefix: string; 39 | 40 | private constructor(privkey: Uint8Array, pubkey: Uint8Array, prefix: string) { 41 | this.privkey = privkey; 42 | this.pubkey = pubkey; 43 | this.prefix = prefix; 44 | } 45 | 46 | private get address(): string { 47 | const uncompressed = Secp256k1.uncompressPubkey(this.pubkey); 48 | return toBech32( 49 | this.prefix, 50 | rawEthSecp256k1PubkeyToRawAddress(uncompressed), 51 | ); 52 | } 53 | 54 | public async getAccounts(): Promise { 55 | return [ 56 | { 57 | algo: "eth_secp256k1", 58 | address: this.address, 59 | pubkey: this.pubkey, 60 | }, 61 | ]; 62 | } 63 | 64 | public async signDirect( 65 | address: string, 66 | signDoc: SignDoc, 67 | ): Promise { 68 | const signBytes = makeSignBytes(signDoc); 69 | if (address !== this.address) { 70 | throw new Error(`Address ${address} not found in wallet`); 71 | } 72 | const hashedMessage = keccak256(signBytes); 73 | const signature = await Secp256k1.createSignature( 74 | hashedMessage, 75 | this.privkey, 76 | ); 77 | const signatureBytes = new Uint8Array([ 78 | ...signature.r(32), 79 | ...signature.s(32), 80 | ]); 81 | const stdSignature = encodeEthSecp256k1Signature( 82 | this.pubkey, 83 | signatureBytes, 84 | ); 85 | return { 86 | signed: signDoc, 87 | signature: stdSignature, 88 | }; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /packages/core/src/proto-signing/pubkey.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/archmage-live/archmage-x/blob/develop/lib/network/cosm/proto-signing/pubkey.ts 2 | 3 | import { 4 | MultisigThresholdPubkey, 5 | Pubkey, 6 | SinglePubkey, 7 | encodeSecp256k1Pubkey, 8 | } from "@cosmjs/amino"; 9 | import { fromBase64 } from "@cosmjs/encoding"; 10 | import { encodePubkey as cosmEncodePubkey } from "@cosmjs/proto-signing"; 11 | import { LegacyAminoPubKey } from "cosmjs-types/cosmos/crypto/multisig/keys"; 12 | import { PubKey } from "cosmjs-types/cosmos/crypto/secp256k1/keys"; 13 | import { Any } from "cosmjs-types/google/protobuf/any"; 14 | import { encodeEthSecp256k1Pubkey } from "../amino/encoding"; 15 | import { isEthSecp256k1Pubkey } from "../amino/pubkey"; 16 | import { AccountData } from "./signer"; 17 | 18 | export function makePubkeyAnyFromAccount( 19 | account: AccountData, 20 | chainId?: string, 21 | ) { 22 | const algo = `${account.algo}`; 23 | 24 | // Some impl use `eth_secp256k1` and some use `ethsecp256k1`, so we check for both 25 | const isEthSecp256k1 = algo === "eth_secp256k1" || algo === "ethsecp256k1"; 26 | 27 | const pubkey = isEthSecp256k1 28 | ? encodeEthSecp256k1Pubkey(account.pubkey) 29 | : encodeSecp256k1Pubkey(account.pubkey); 30 | 31 | const pubkeyAny = encodePubkeyToAny(pubkey, chainId); 32 | 33 | return pubkeyAny; 34 | } 35 | 36 | export function encodePubkeyToAny(pubkey: Pubkey, chainId?: string): Any { 37 | if (isEthSecp256k1Pubkey(pubkey)) { 38 | const pubkeyProto = PubKey.fromPartial({ 39 | key: fromBase64(pubkey.value), 40 | }); 41 | let typeUrl = ""; 42 | if (chainId?.includes("injective")) { 43 | typeUrl = "/injective.crypto.v1beta1.ethsecp256k1.PubKey"; 44 | } else { 45 | typeUrl = "/ethermint.crypto.v1.ethsecp256k1.PubKey"; 46 | } 47 | return Any.fromPartial({ 48 | typeUrl, 49 | value: Uint8Array.from(PubKey.encode(pubkeyProto).finish()), 50 | }); 51 | } else { 52 | return cosmEncodePubkey(pubkey); 53 | } 54 | } 55 | 56 | function decodeAnyToPubkey(pubkey: Any): SinglePubkey { 57 | switch (pubkey.typeUrl) { 58 | case "/ethermint.crypto.v1.ethsecp256k1.PubKey": { 59 | const { key } = PubKey.decode(pubkey.value); 60 | return encodeEthSecp256k1Pubkey(key); 61 | } 62 | case "/cosmos.crypto.secp256k1.PubKey": { 63 | const { key } = PubKey.decode(pubkey.value); 64 | return encodeSecp256k1Pubkey(key); 65 | } 66 | default: 67 | throw new Error( 68 | `Pubkey type_url ${pubkey.typeUrl} not recognized as single public key type`, 69 | ); 70 | } 71 | } 72 | 73 | export function decodePubkey(pubkey?: Any | null): Pubkey | null { 74 | if (!pubkey || !pubkey.value) { 75 | return null; 76 | } 77 | 78 | switch (pubkey.typeUrl) { 79 | case "/ethermint.crypto.v1.ethsecp256k1.PubKey": { 80 | return decodeAnyToPubkey(pubkey); 81 | } 82 | case "/cosmos.crypto.secp256k1.PubKey": { 83 | return decodeAnyToPubkey(pubkey); 84 | } 85 | case "/cosmos.crypto.multisig.LegacyAminoPubKey": { 86 | const { threshold, publicKeys } = LegacyAminoPubKey.decode(pubkey.value); 87 | const out: MultisigThresholdPubkey = { 88 | type: "tendermint/PubKeyMultisigThreshold", 89 | value: { 90 | threshold: threshold.toString(), 91 | pubkeys: publicKeys.map(decodeAnyToPubkey), 92 | }, 93 | }; 94 | return out; 95 | } 96 | default: 97 | throw new Error(`Pubkey type_url ${pubkey.typeUrl} not recognized`); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /packages/core/src/proto-signing/signer.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/archmage-live/archmage-x/blob/develop/lib/network/cosm/proto-signing/signer.ts 2 | 3 | import { OfflineAminoSigner } from "@cosmjs/amino"; 4 | import { Algo as CosmAlgo, DirectSignResponse } from "@cosmjs/proto-signing"; 5 | import { SignDoc } from "cosmjs-types/cosmos/tx/v1beta1/tx"; 6 | 7 | export type Algo = "eth_secp256k1" | "ethsecp256k1" | CosmAlgo; 8 | 9 | export interface AccountData { 10 | /** A printable address (typically bech32 encoded) */ 11 | readonly address: string; 12 | readonly algo: Algo; 13 | readonly pubkey: Uint8Array; 14 | } 15 | 16 | export interface OfflineDirectSigner { 17 | readonly getAccounts: () => Promise; 18 | readonly signDirect: ( 19 | signerAddress: string, 20 | signDoc: SignDoc, 21 | ) => Promise; 22 | } 23 | 24 | export type OfflineSigner = OfflineAminoSigner | OfflineDirectSigner; 25 | 26 | export function isOfflineDirectSigner( 27 | signer: OfflineSigner, 28 | ): signer is OfflineDirectSigner { 29 | return (signer as OfflineDirectSigner).signDirect !== undefined; 30 | } 31 | -------------------------------------------------------------------------------- /packages/core/src/request-client.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { AxiosError, AxiosInstance } from "axios"; 3 | 4 | // Request clients wraps the axios client and handles error responses 5 | export class RequestClient { 6 | private httpClient: AxiosInstance; 7 | 8 | constructor({ baseURL, apiKey }: { baseURL: string; apiKey?: string }) { 9 | this.httpClient = axios.create({ 10 | baseURL, 11 | headers: apiKey 12 | ? { 13 | authorization: apiKey, 14 | } 15 | : undefined, 16 | }); 17 | } 18 | 19 | async get( 20 | path: string, 21 | params?: RequestParams, 22 | ): Promise { 23 | try { 24 | const response = await this.httpClient.get(path, { 25 | params, 26 | }); 27 | 28 | return response.data; 29 | } catch (error) { 30 | if (error instanceof AxiosError && error.response?.data?.message) { 31 | throw new Error(error.response.data.message); 32 | } 33 | 34 | throw error; 35 | } 36 | } 37 | 38 | async post( 39 | path: string, 40 | data: Body = {} as Body, 41 | ): Promise { 42 | try { 43 | const response = await this.httpClient.post(path, data); 44 | 45 | return response.data; 46 | } catch (error) { 47 | if (error instanceof AxiosError && error.response?.data?.message) { 48 | throw new Error(error.response.data.message); 49 | } 50 | 51 | throw error; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/core/src/transactions.ts: -------------------------------------------------------------------------------- 1 | import { toUtf8 } from "@cosmjs/encoding"; 2 | import { EncodeObject } from "@cosmjs/proto-signing"; 3 | import MsgTransferInjective from "@injectivelabs/sdk-ts/dist/cjs/core/modules/ibc/msgs/MsgTransfer"; 4 | import { Msgs } from "@injectivelabs/sdk-ts/dist/cjs/core/modules/msgs"; 5 | import MsgExecuteContractInjective from "@injectivelabs/sdk-ts/dist/cjs/core/modules/wasm/msgs/MsgExecuteContract"; 6 | import { MsgSend } from "cosmjs-types/cosmos/bank/v1beta1/tx"; 7 | import { MsgExecuteContract } from "cosmjs-types/cosmwasm/wasm/v1/tx"; 8 | import { MsgTransfer } from "cosmjs-types/ibc/applications/transfer/v1/tx"; 9 | 10 | import { CosmosMsg } from "./types"; 11 | import { 12 | MsgDepositForBurn, 13 | MsgDepositForBurnWithCaller, 14 | } from "./codegen/circle/cctp/v1/tx"; 15 | import { SigningStargateClient } from "@cosmjs/stargate"; 16 | import { MsgExecute } from "./codegen/initia/move/v1/tx"; 17 | 18 | import { MsgInitiateTokenDeposit } from "./codegen/opinit/ophost/v1/tx"; 19 | 20 | export const DEFAULT_GAS_MULTIPLIER = 1.5; 21 | 22 | export function getEncodeObjectFromCosmosMessage( 23 | message: CosmosMsg, 24 | ): EncodeObject { 25 | const msgJson = JSON.parse(message.msg); 26 | 27 | if (message.msgTypeURL === "/ibc.applications.transfer.v1.MsgTransfer") { 28 | return { 29 | typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", 30 | value: MsgTransfer.fromJSON({ 31 | sourcePort: msgJson.source_port, 32 | sourceChannel: msgJson.source_channel, 33 | token: msgJson.token, 34 | sender: msgJson.sender, 35 | receiver: msgJson.receiver, 36 | timeoutHeight: msgJson.timeout_height, 37 | timeoutTimestamp: msgJson.timeout_timestamp, 38 | memo: msgJson.memo, 39 | }), 40 | }; 41 | } 42 | 43 | if (message.msgTypeURL === "/cosmwasm.wasm.v1.MsgExecuteContract") { 44 | return { 45 | typeUrl: message.msgTypeURL, 46 | value: MsgExecuteContract.fromPartial({ 47 | sender: msgJson.sender, 48 | contract: msgJson.contract, 49 | msg: toUtf8(JSON.stringify(msgJson.msg)), 50 | funds: msgJson.funds, 51 | }), 52 | }; 53 | } 54 | 55 | if (message.msgTypeURL === "/cosmos.bank.v1beta1.MsgSend") { 56 | return { 57 | typeUrl: message.msgTypeURL, 58 | value: MsgSend.fromPartial({ 59 | fromAddress: msgJson.from_address, 60 | toAddress: msgJson.to_address, 61 | amount: msgJson.amount, 62 | }), 63 | }; 64 | } 65 | 66 | if (message.msgTypeURL === "/circle.cctp.v1.MsgDepositForBurn") { 67 | return { 68 | typeUrl: message.msgTypeURL, 69 | value: MsgDepositForBurn.fromAmino(msgJson), 70 | }; 71 | } 72 | 73 | if (message.msgTypeURL === "/circle.cctp.v1.MsgDepositForBurnWithCaller") { 74 | return { 75 | typeUrl: message.msgTypeURL, 76 | value: MsgDepositForBurnWithCaller.fromAmino(msgJson), 77 | }; 78 | } 79 | 80 | if (message.msgTypeURL === "/initia.move.v1.MsgExecute") { 81 | return { 82 | typeUrl: message.msgTypeURL, 83 | value: MsgExecute.fromPartial({ 84 | sender: msgJson.sender, 85 | moduleAddress: msgJson.module_address, 86 | moduleName: msgJson.module_name, 87 | functionName: msgJson.function_name, 88 | args: msgJson.args, 89 | }), 90 | }; 91 | } 92 | 93 | if (message.msgTypeURL === "/opinit.ophost.v1.MsgInitiateTokenDeposit") { 94 | return { 95 | typeUrl: message.msgTypeURL, 96 | value: MsgInitiateTokenDeposit.fromPartial({ 97 | sender: msgJson.sender, 98 | to: msgJson.to, 99 | amount: msgJson.amount, 100 | bridgeId: msgJson.bridge_id, 101 | }), 102 | }; 103 | } 104 | 105 | return { 106 | typeUrl: message.msgTypeURL, 107 | value: msgJson, 108 | }; 109 | } 110 | 111 | export function getEncodeObjectFromCosmosMessageInjective( 112 | message: CosmosMsg, 113 | ): Msgs { 114 | const msgJson = JSON.parse(message.msg); 115 | 116 | if (message.msgTypeURL === "/ibc.applications.transfer.v1.MsgTransfer") { 117 | return MsgTransferInjective.fromJSON({ 118 | port: msgJson.source_port, 119 | channelId: msgJson.source_channel, 120 | amount: msgJson.token, 121 | sender: msgJson.sender, 122 | receiver: msgJson.receiver, 123 | timeout: msgJson.timeout_timestamp, 124 | memo: msgJson.memo, 125 | }); 126 | } 127 | 128 | if (message.msgTypeURL === "/cosmwasm.wasm.v1.MsgExecuteContract") { 129 | return MsgExecuteContractInjective.fromJSON({ 130 | sender: msgJson.sender, 131 | contractAddress: msgJson.contract, 132 | msg: msgJson.msg, 133 | funds: msgJson.funds, 134 | }); 135 | } 136 | 137 | throw new Error("Unsupported message type"); 138 | } 139 | 140 | export async function getCosmosGasAmountForMessage( 141 | client: SigningStargateClient, 142 | signerAddress: string, 143 | chainID: string, 144 | messages?: CosmosMsg[], 145 | encodedMsgs?: EncodeObject[], 146 | multiplier: number = DEFAULT_GAS_MULTIPLIER, 147 | ) { 148 | if (!messages && !encodedMsgs) { 149 | throw new Error("Either message or encodedMsg must be provided"); 150 | } 151 | const _encodedMsgs = messages?.map((message) => 152 | getEncodeObjectFromCosmosMessage(message), 153 | ); 154 | encodedMsgs = encodedMsgs || _encodedMsgs; 155 | if (!encodedMsgs) { 156 | throw new Error("Either message or encodedMsg must be provided"); 157 | } 158 | if ( 159 | chainID.includes("evmos") || 160 | chainID.includes("injective") || 161 | chainID.includes("dymension") || 162 | process?.env.NODE_ENV === "test" 163 | ) { 164 | if ( 165 | messages?.find( 166 | (i) => i.msgTypeURL === "/cosmwasm.wasm.v1.MsgExecuteContract", 167 | ) 168 | ) { 169 | return "2400000"; 170 | } 171 | return "280000"; 172 | } 173 | 174 | const estimatedGas = await client.simulate(signerAddress, encodedMsgs, ""); 175 | 176 | const estimatedGasWithBuffer = estimatedGas * multiplier; 177 | 178 | return Math.ceil(estimatedGasWithBuffer).toFixed(0); 179 | } 180 | -------------------------------------------------------------------------------- /packages/core/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./converters"; 2 | export * from "./lifecycle"; 3 | export * from "./routing"; 4 | export * from "./shared"; 5 | export * from "./unified"; 6 | -------------------------------------------------------------------------------- /packages/core/src/types/lifecycle.ts: -------------------------------------------------------------------------------- 1 | export type SubmitTxRequestJSON = { 2 | tx: string; 3 | chain_id: string; 4 | }; 5 | 6 | export type SubmitTxRequest = { 7 | tx: string; 8 | chainID: string; 9 | }; 10 | 11 | export type SubmitTxResponseJSON = { 12 | tx_hash: string; 13 | }; 14 | 15 | export type SubmitTxResponse = { 16 | txHash: string; 17 | }; 18 | 19 | export type StatusState = 20 | | "STATE_UNKNOWN" 21 | | "STATE_SUBMITTED" 22 | | "STATE_PENDING" 23 | | "STATE_RECEIVED" 24 | | "STATE_COMPLETED" 25 | | "STATE_ABANDONED" 26 | | "STATE_COMPLETED_SUCCESS" 27 | | "STATE_COMPLETED_ERROR" 28 | | "STATE_PENDING_ERROR"; 29 | 30 | export type NextBlockingTransferJSON = { 31 | transfer_sequence_index: number; 32 | }; 33 | 34 | export type NextBlockingTransfer = { 35 | transferSequenceIndex: number; 36 | }; 37 | 38 | export type StatusRequestJSON = { 39 | tx_hash: string; 40 | chain_id: string; 41 | }; 42 | 43 | export type StatusRequest = { 44 | txHash: string; 45 | chainID: string; 46 | }; 47 | 48 | export type TransferState = 49 | | "TRANSFER_UNKNOWN" 50 | | "TRANSFER_PENDING" 51 | | "TRANSFER_RECEIVED" 52 | | "TRANSFER_SUCCESS" 53 | | "TRANSFER_FAILURE"; 54 | 55 | export type TransferInfoJSON = { 56 | from_chain_id: string; 57 | to_chain_id: string; 58 | state: TransferState; 59 | packet_txs: PacketJSON; 60 | 61 | // Deprecated 62 | src_chain_id: string; 63 | dst_chain_id: string; 64 | }; 65 | 66 | export type TransferInfo = { 67 | fromChainID: string; 68 | toChainID: string; 69 | state: TransferState; 70 | packetTXs: Packet; 71 | 72 | // Deprecated 73 | srcChainID: string; 74 | dstChainID: string; 75 | }; 76 | 77 | export type TransferAssetReleaseJSON = { 78 | chain_id: string; 79 | denom: string; 80 | released: boolean; 81 | }; 82 | 83 | export type TransferAssetRelease = { 84 | chainID: string; 85 | denom: string; 86 | released: boolean; 87 | }; 88 | 89 | export type TxStatusResponseJSON = { 90 | status: StatusState; 91 | transfer_sequence: TransferEventJSON[]; 92 | next_blocking_transfer: NextBlockingTransferJSON | null; 93 | transfer_asset_release: TransferAssetReleaseJSON | null; 94 | error: StatusError | null; 95 | state: StatusState; 96 | transfers: TransferStatusJSON[]; 97 | }; 98 | 99 | export type TxStatusResponse = { 100 | status: StatusState; 101 | transferSequence: TransferEvent[]; 102 | nextBlockingTransfer: NextBlockingTransfer | null; 103 | transferAssetRelease: TransferAssetRelease | null; 104 | error: StatusError | null; 105 | state: StatusState; 106 | transfers: TransferStatus[]; 107 | }; 108 | 109 | export type TransferStatusJSON = { 110 | state: StatusState; 111 | transfer_sequence: TransferEventJSON[]; 112 | next_blocking_transfer: NextBlockingTransferJSON | null; 113 | transfer_asset_release: TransferAssetReleaseJSON | null; 114 | error: StatusError | null; 115 | }; 116 | 117 | export type TransferStatus = { 118 | state: StatusState; 119 | transferSequence: TransferEvent[]; 120 | nextBlockingTransfer: NextBlockingTransfer | null; 121 | transferAssetRelease: TransferAssetRelease | null; 122 | error: StatusError | null; 123 | }; 124 | 125 | export type PacketJSON = { 126 | send_tx: ChainTransactionJSON | null; 127 | receive_tx: ChainTransactionJSON | null; 128 | acknowledge_tx: ChainTransactionJSON | null; 129 | timeout_tx: ChainTransactionJSON | null; 130 | 131 | error: PacketError | null; 132 | }; 133 | 134 | export type Packet = { 135 | sendTx: ChainTransaction | null; 136 | receiveTx: ChainTransaction | null; 137 | acknowledgeTx: ChainTransaction | null; 138 | timeoutTx: ChainTransaction | null; 139 | 140 | error: PacketError | null; 141 | }; 142 | 143 | export type StatusErrorType = 144 | | "STATUS_ERROR_UNKNOWN" 145 | | "STATUS_ERROR_TRANSACTION_EXECUTION" 146 | | "STATUS_ERROR_INDEXING"; 147 | 148 | export type TransactionExecutionError = { 149 | code: number; 150 | message: string; 151 | }; 152 | 153 | export type StatusErrorJSON = { 154 | code: number; 155 | message: string; 156 | type: StatusErrorType; 157 | details: { 158 | transaction_execution_error: TransactionExecutionError; 159 | }; 160 | }; 161 | 162 | export type StatusError = { 163 | code: number; 164 | message: string; 165 | type: StatusErrorType; 166 | details: { 167 | transactionExecutionError: TransactionExecutionError; 168 | }; 169 | }; 170 | 171 | export type PacketErrorType = 172 | | "PACKET_ERROR_UNKNOWN" 173 | | "PACKET_ERROR_ACKNOWLEDGEMENT" 174 | | "PACKET_ERROR_TIMEOUT"; 175 | 176 | export type AcknowledgementError = { 177 | message: string; 178 | code: number; 179 | }; 180 | 181 | export type PacketErrorJSON = { 182 | code: number; 183 | message: string; 184 | type: PacketErrorType; 185 | details: { 186 | acknowledgement_error: AcknowledgementError; 187 | }; 188 | }; 189 | 190 | export type PacketError = { 191 | code: number; 192 | message: string; 193 | type: PacketErrorType; 194 | details: { 195 | acknowledgementError: AcknowledgementError; 196 | }; 197 | }; 198 | 199 | export type ChainTransactionJSON = { 200 | chain_id: string; 201 | tx_hash: string; 202 | explorer_link: string; 203 | }; 204 | 205 | export type ChainTransaction = { 206 | chainID: string; 207 | txHash: string; 208 | explorerLink: string; 209 | }; 210 | 211 | export type TrackTxRequestJSON = { 212 | tx_hash: string; 213 | chain_id: string; 214 | }; 215 | 216 | export type TrackTxRequest = { 217 | txHash: string; 218 | chainID: string; 219 | }; 220 | 221 | export type TrackTxResponseJSON = { 222 | tx_hash: string; 223 | }; 224 | 225 | export type TrackTxResponse = { 226 | txHash: string; 227 | }; 228 | 229 | export type AxelarTransferType = 230 | | "AXELAR_TRANSFER_CONTRACT_CALL_WITH_TOKEN" 231 | | "AXELAR_TRANSFER_SEND_TOKEN"; 232 | 233 | export type AxelarTransferState = 234 | | "AXELAR_TRANSFER_UNKNOWN" 235 | | "AXELAR_TRANSFER_PENDING_CONFIRMATION" 236 | | "AXELAR_TRANSFER_PENDING_RECEIPT" 237 | | "AXELAR_TRANSFER_SUCCESS" 238 | | "AXELAR_TRANSFER_FAILURE"; 239 | 240 | export type AxelarTransferInfoJSON = { 241 | from_chain_id: string; 242 | to_chain_id: string; 243 | type: AxelarTransferType; 244 | state: AxelarTransferState; 245 | txs: AxelarTransferTransactionsJSON; 246 | axelar_scan_link: string; 247 | 248 | // Deprecated 249 | src_chain_id: string; 250 | dst_chain_id: string; 251 | }; 252 | 253 | export type AxelarTransferInfo = { 254 | fromChainID: string; 255 | toChainID: string; 256 | type: AxelarTransferType; 257 | state: AxelarTransferState; 258 | txs: AxelarTransferTransactions; 259 | axelarScanLink: string; 260 | 261 | // Deprecated 262 | srcChainID: string; 263 | dstChainID: string; 264 | }; 265 | 266 | export type AxelarTransferTransactionsJSON = 267 | | { 268 | contract_call_with_token_txs: ContractCallWithTokenTransactionsJSON; 269 | } 270 | | { 271 | send_token_txs: SendTokenTransactionsJSON; 272 | }; 273 | 274 | export type AxelarTransferTransactions = 275 | | { 276 | contractCallWithTokenTxs: ContractCallWithTokenTransactions; 277 | } 278 | | { 279 | sendTokenTxs: SendTokenTransactions; 280 | }; 281 | 282 | export type ContractCallWithTokenTransactionsJSON = { 283 | send_tx: ChainTransactionJSON | null; 284 | gas_paid_tx: ChainTransactionJSON | null; 285 | confirm_tx: ChainTransactionJSON | null; 286 | approve_tx: ChainTransactionJSON | null; 287 | execute_tx: ChainTransactionJSON | null; 288 | error: ContractCallWithTokenError | null; 289 | }; 290 | 291 | export type ContractCallWithTokenTransactions = { 292 | sendTx: ChainTransaction | null; 293 | gasPaidTx: ChainTransaction | null; 294 | confirmTx: ChainTransaction | null; 295 | approveTx: ChainTransaction | null; 296 | executeTx: ChainTransaction | null; 297 | error: ContractCallWithTokenError | null; 298 | }; 299 | 300 | export type ContractCallWithTokenError = { 301 | message: string; 302 | type: ContractCallWithTokenErrorType; 303 | }; 304 | 305 | export type ContractCallWithTokenErrorType = 306 | "CONTRACT_CALL_WITH_TOKEN_EXECUTION_ERROR"; 307 | 308 | export type SendTokenTransactionsJSON = { 309 | send_tx: ChainTransactionJSON | null; 310 | confirm_tx: ChainTransactionJSON | null; 311 | execute_tx: ChainTransactionJSON | null; 312 | error: SendTokenError | null; 313 | }; 314 | 315 | export type SendTokenTransactions = { 316 | sendTx: ChainTransaction | null; 317 | confirmTx: ChainTransaction | null; 318 | executeTx: ChainTransaction | null; 319 | error: SendTokenError | null; 320 | }; 321 | 322 | export type SendTokenErrorType = "SEND_TOKEN_EXECUTION_ERROR"; 323 | 324 | export type SendTokenError = { 325 | message: string; 326 | type: SendTokenErrorType; 327 | }; 328 | 329 | export type CCTPTransferState = 330 | | "CCTP_TRANSFER_UNKNOWN" 331 | | "CCTP_TRANSFER_SENT" 332 | | "CCTP_TRANSFER_PENDING_CONFIRMATION" 333 | | "CCTP_TRANSFER_CONFIRMED" 334 | | "CCTP_TRANSFER_RECEIVED"; 335 | 336 | export type CCTPTransferTransactionsJSON = { 337 | send_tx: ChainTransactionJSON | null; 338 | receive_tx: ChainTransactionJSON | null; 339 | }; 340 | 341 | export type CCTPTransferTransactions = { 342 | sendTx: ChainTransaction | null; 343 | receiveTx: ChainTransaction | null; 344 | }; 345 | 346 | export type CCTPTransferInfoJSON = { 347 | from_chain_id: string; 348 | to_chain_id: string; 349 | state: CCTPTransferState; 350 | txs: CCTPTransferTransactionsJSON; 351 | 352 | // Deprecated 353 | src_chain_id: string; 354 | dst_chain_id: string; 355 | }; 356 | 357 | export type CCTPTransferInfo = { 358 | fromChainID: string; 359 | toChainID: string; 360 | state: CCTPTransferState; 361 | txs: CCTPTransferTransactions; 362 | 363 | // Deprecated 364 | srcChainID: string; 365 | dstChainID: string; 366 | }; 367 | 368 | export type HyperlaneTransferState = 369 | | "HYPERLANE_TRANSFER_UNKNOWN" 370 | | "HYPERLANE_TRANSFER_SENT" 371 | | "HYPERLANE_TRANSFER_FAILED" 372 | | "HYPERLANE_TRANSFER_RECEIVED"; 373 | 374 | export type HyperlaneTransferTransactionsJSON = { 375 | send_tx: ChainTransactionJSON | null; 376 | receive_tx: ChainTransactionJSON | null; 377 | }; 378 | 379 | export type HyperlaneTransferTransactions = { 380 | sendTx: ChainTransaction | null; 381 | receiveTx: ChainTransaction | null; 382 | }; 383 | 384 | export type HyperlaneTransferInfoJSON = { 385 | from_chain_id: string; 386 | to_chain_id: string; 387 | state: HyperlaneTransferState; 388 | txs: HyperlaneTransferTransactionsJSON; 389 | }; 390 | 391 | export type HyperlaneTransferInfo = { 392 | fromChainID: string; 393 | toChainID: string; 394 | state: HyperlaneTransferState; 395 | txs: HyperlaneTransferTransactions; 396 | }; 397 | 398 | export type OPInitTransferState = 399 | | "OPINIT_TRANSFER_UNKNOWN" 400 | | "OPINIT_TRANSFER_SENT" 401 | | "OPINIT_TRANSFER_RECEIVED"; 402 | 403 | export type OPInitTransferTransactionsJSON = { 404 | send_tx: ChainTransactionJSON | null; 405 | receive_tx: ChainTransactionJSON | null; 406 | }; 407 | 408 | export type OPInitTransferTransactions = { 409 | sendTx: ChainTransaction | null; 410 | receiveTx: ChainTransaction | null; 411 | }; 412 | 413 | export type OPInitTransferInfoJSON = { 414 | from_chain_id: string; 415 | to_chain_id: string; 416 | state: OPInitTransferState; 417 | txs: OPInitTransferTransactionsJSON; 418 | }; 419 | 420 | export type OPInitTransferInfo = { 421 | fromChainID: string; 422 | toChainID: string; 423 | state: OPInitTransferState; 424 | txs: OPInitTransferTransactions; 425 | }; 426 | 427 | export type TransferEventJSON = 428 | | { 429 | ibc_transfer: TransferInfoJSON; 430 | } 431 | | { 432 | axelar_transfer: AxelarTransferInfoJSON; 433 | } 434 | | { cctp_transfer: CCTPTransferInfoJSON } 435 | | { hyperlane_transfer: HyperlaneTransferInfoJSON } 436 | | { op_init_transfer: OPInitTransferInfoJSON }; 437 | 438 | export type TransferEvent = 439 | | { 440 | ibcTransfer: TransferInfo; 441 | } 442 | | { axelarTransfer: AxelarTransferInfo } 443 | | { cctpTransfer: CCTPTransferInfo } 444 | | { hyperlaneTransfer: HyperlaneTransferInfo } 445 | | { opInitTransfer: OPInitTransferInfo }; 446 | -------------------------------------------------------------------------------- /packages/core/src/types/routing.ts: -------------------------------------------------------------------------------- 1 | export type ModuleSupport = { 2 | authz: boolean; 3 | feegrant: boolean; 4 | }; 5 | 6 | export type GasPriceInfo = { 7 | low: string; 8 | average: string; 9 | high: string; 10 | }; 11 | 12 | export type FeeAsset = { 13 | denom: string; 14 | gasPrice: GasPriceInfo | null; 15 | }; 16 | 17 | export type FeeAssetJSON = { 18 | denom: string; 19 | gas_price: GasPriceInfo | null; 20 | }; 21 | 22 | export type IbcCapabilities = { 23 | cosmosPfm: boolean; 24 | cosmosIbcHooks: boolean; 25 | cosmosMemo: boolean; 26 | cosmosAutopilot: boolean; 27 | }; 28 | 29 | export type IbcCapabilitiesJSON = { 30 | cosmos_pfm: boolean; 31 | cosmos_ibc_hooks: boolean; 32 | cosmos_memo: boolean; 33 | cosmos_autopilot: boolean; 34 | }; 35 | 36 | export type Chain = { 37 | chainName: string; 38 | chainID: string; 39 | pfmEnabled: boolean; 40 | cosmosSDKVersion?: string; 41 | modules?: Record; 42 | cosmosModuleSupport: ModuleSupport; 43 | supportsMemo: boolean; 44 | logoURI?: string; 45 | bech32Prefix: string; 46 | feeAssets: FeeAsset[]; 47 | chainType: string; 48 | ibcCapabilities: IbcCapabilities; 49 | isTestnet: boolean; 50 | }; 51 | 52 | export type Venue = { 53 | name: string; 54 | chainID: string; 55 | logoURI: string; 56 | }; 57 | 58 | export type ChainJSON = { 59 | chain_name: string; 60 | chain_id: string; 61 | pfm_enabled: boolean; 62 | cosmos_sdk_version?: string; 63 | modules?: Record; 64 | cosmos_module_support: ModuleSupport; 65 | supports_memo: boolean; 66 | logo_uri?: string; 67 | bech32_prefix: string; 68 | fee_assets: FeeAssetJSON[]; 69 | chain_type: string; 70 | ibc_capabilities: IbcCapabilitiesJSON; 71 | is_testnet: boolean; 72 | }; 73 | 74 | export type ModuleVersionInfo = { 75 | path: string; 76 | version: string; 77 | sum: string; 78 | }; 79 | -------------------------------------------------------------------------------- /packages/core/src/types/shared.ts: -------------------------------------------------------------------------------- 1 | import { BridgeType } from "./unified"; 2 | 3 | export type IBCAddressJSON = { 4 | address: string; 5 | chain_id: string; 6 | }; 7 | 8 | export type IBCAddress = { 9 | address: string; 10 | chainID: string; 11 | }; 12 | 13 | export type AssetJSON = { 14 | denom: string; 15 | chain_id: string; 16 | 17 | origin_denom: string; 18 | origin_chain_id: string; 19 | trace: string; 20 | is_cw20: boolean; 21 | is_evm: boolean; 22 | is_svm: boolean; 23 | 24 | symbol: string | undefined; 25 | name: string | undefined; 26 | logo_uri: string | undefined; 27 | decimals: number | undefined; 28 | token_contract: string | undefined; 29 | description: string | undefined; 30 | coingecko_id: string | undefined; 31 | recommended_symbol: string | undefined; 32 | }; 33 | 34 | export type Asset = { 35 | denom: string; 36 | chainID: string; 37 | 38 | originDenom: string; 39 | originChainID: string; 40 | trace: string; 41 | isCW20: boolean; 42 | isEVM: boolean; 43 | isSVM: boolean; 44 | 45 | symbol: string | undefined; 46 | name: string | undefined; 47 | logoURI: string | undefined; 48 | decimals: number | undefined; 49 | tokenContract: string | undefined; 50 | description: string | undefined; 51 | coingeckoID: string | undefined; 52 | recommendedSymbol: string | undefined; 53 | }; 54 | 55 | export type TransferJSON = { 56 | port: string; 57 | channel: string; 58 | from_chain_id: string; 59 | to_chain_id: string; 60 | pfm_enabled: boolean; 61 | supports_memo: boolean; 62 | 63 | denom_in: string; 64 | denom_out: string; 65 | 66 | fee_amount?: string; 67 | usd_fee_amount?: string; 68 | fee_asset?: AssetJSON; 69 | 70 | bridge_id: BridgeType; 71 | smart_relay: boolean; 72 | 73 | /** 74 | * @deprecated use `from_chain_id` and `to_chain_id` instead 75 | */ 76 | chain_id: string; 77 | 78 | /** 79 | * @deprecated use `denom_out` instead 80 | */ 81 | dest_denom: string; 82 | }; 83 | 84 | export type Transfer = { 85 | port: string; 86 | channel: string; 87 | fromChainID: string; 88 | toChainID: string; 89 | pfmEnabled: boolean; 90 | supportsMemo: boolean; 91 | 92 | denomIn: string; 93 | denomOut: string; 94 | 95 | feeAmount?: string; 96 | usdFeeAmount?: string; 97 | feeAsset?: Asset; 98 | 99 | bridgeID: BridgeType; 100 | smartRelay: boolean; 101 | 102 | /** 103 | * @deprecated use `fromChainID` and `toChainID` instead 104 | */ 105 | chainID: string; 106 | 107 | /** 108 | * @deprecated use `denomOut` instead 109 | */ 110 | destDenom: string; 111 | }; 112 | 113 | export type AxelarTransferJSON = { 114 | from_chain: string; 115 | from_chain_id: string; 116 | to_chain: string; 117 | to_chain_id: string; 118 | asset: string; 119 | should_unwrap: boolean; 120 | 121 | denom_in: string; 122 | denom_out: string; 123 | 124 | fee_amount: string; 125 | usd_fee_amount: string; 126 | fee_asset: AssetJSON; 127 | 128 | is_testnet: boolean; 129 | 130 | ibc_transfer_to_axelar?: TransferJSON; 131 | 132 | bridge_id: BridgeType; 133 | smart_relay: boolean; 134 | }; 135 | 136 | export type AxelarTransfer = { 137 | fromChain: string; 138 | fromChainID: string; 139 | toChain: string; 140 | toChainID: string; 141 | asset: string; 142 | shouldUnwrap: boolean; 143 | 144 | denomIn: string; 145 | denomOut: string; 146 | 147 | feeAmount: string; 148 | usdFeeAmount: string; 149 | feeAsset: Asset; 150 | 151 | isTestnet: boolean; 152 | 153 | ibcTransferToAxelar?: Transfer; 154 | 155 | bridgeID: BridgeType; 156 | smartRelay: boolean; 157 | }; 158 | 159 | export type BankSendJSON = { 160 | chain_id: string; 161 | denom: string; 162 | }; 163 | 164 | export type BankSend = { 165 | chainID: string; 166 | denom: string; 167 | }; 168 | 169 | export type MultiChainMsgJSON = { 170 | chain_id: string; 171 | path: string[]; 172 | msg: string; 173 | msg_type_url: string; 174 | }; 175 | 176 | export type MultiChainMsg = { 177 | chainID: string; 178 | path: string[]; 179 | msg: string; 180 | msgTypeURL: string; 181 | }; 182 | 183 | export type CosmosMsgJSON = { 184 | msg: string; 185 | msg_type_url: string; 186 | }; 187 | export type CosmosMsg = { 188 | msg: string; 189 | msgTypeURL: string; 190 | }; 191 | 192 | export type CosmosTxJSON = { 193 | chain_id: string; 194 | path: string[]; 195 | msgs: CosmosMsgJSON[]; 196 | signer_address: string; 197 | }; 198 | 199 | export type CosmosTx = { 200 | chainID: string; 201 | path: string[]; 202 | msgs: CosmosMsg[]; 203 | signerAddress: string; 204 | }; 205 | 206 | export type CCTPTransferJSON = { 207 | from_chain_id: string; 208 | to_chain_id: string; 209 | burn_token: string; 210 | bridge_id: BridgeType; 211 | denom_in: string; 212 | denom_out: string; 213 | smart_relay: boolean; 214 | }; 215 | 216 | export type CCTPTransfer = { 217 | fromChainID: string; 218 | toChainID: string; 219 | burnToken: string; 220 | bridgeID: BridgeType; 221 | denomIn: string; 222 | denomOut: string; 223 | smartRelay: boolean; 224 | }; 225 | 226 | export type HyperlaneTransferJSON = { 227 | from_chain_id: string; 228 | to_chain_id: string; 229 | denom_in: string; 230 | denom_out: string; 231 | hyperlane_contract_address: string; 232 | fee_amount: string; 233 | usd_fee_amount?: string; 234 | fee_asset: AssetJSON; 235 | bridge_id: BridgeType; 236 | smart_relay: boolean; 237 | }; 238 | 239 | export type HyperlaneTransfer = { 240 | fromChainID: string; 241 | toChainID: string; 242 | denomIn: string; 243 | denomOut: string; 244 | hyperlaneContractAddress: string; 245 | feeAmount: string; 246 | usdFeeAmount?: string; 247 | feeAsset: Asset; 248 | bridgeID: BridgeType; 249 | smartRelay: boolean; 250 | }; 251 | 252 | export type OPInitTransferJSON = { 253 | from_chain_id: string; 254 | to_chain_id: string; 255 | denom_in: string; 256 | denom_out: string; 257 | op_init_bridge_id: string; 258 | bridge_id: BridgeType; 259 | smart_relay: boolean; 260 | }; 261 | 262 | export type OPInitTransfer = { 263 | fromChainID: string; 264 | toChainID: string; 265 | denomIn: string; 266 | denomOut: string; 267 | opInitBridgeID: string; 268 | bridgeID: BridgeType; 269 | smartRelay: boolean; 270 | }; 271 | 272 | export type SwapVenueJSON = { 273 | name: string; 274 | chain_id: string; 275 | logo_uri: string; 276 | }; 277 | 278 | export type SwapVenue = { 279 | name: string; 280 | chainID: string; 281 | logoUri: string; 282 | }; 283 | 284 | export type SwapVenueRequestJSON = { 285 | name: string; 286 | chain_id: string; 287 | }; 288 | 289 | export type SwapVenueRequest = { 290 | name: string; 291 | chainID: string; 292 | }; 293 | 294 | export type SwapOperationJSON = { 295 | pool: string; 296 | denom_in: string; 297 | denom_out: string; 298 | interface?: string; 299 | }; 300 | 301 | export type SwapOperation = { 302 | pool: string; 303 | denomIn: string; 304 | denomOut: string; 305 | interface?: string; 306 | }; 307 | 308 | export type SwapExactCoinOutJSON = { 309 | swap_venue: SwapVenueJSON; 310 | swap_operations: SwapOperationJSON[]; 311 | swap_amount_out: string; 312 | price_impact_percent?: string; 313 | }; 314 | 315 | export type SwapExactCoinOut = { 316 | swapVenue: SwapVenue; 317 | swapOperations: SwapOperation[]; 318 | swapAmountOut: string; 319 | priceImpactPercent?: string; 320 | }; 321 | 322 | export type SwapExactCoinInJSON = { 323 | swap_venue: SwapVenueJSON; 324 | swap_operations: SwapOperationJSON[]; 325 | swap_amount_in?: string; 326 | price_impact_percent?: string; 327 | }; 328 | 329 | export type SwapExactCoinIn = { 330 | swapVenue: SwapVenue; 331 | swapOperations: SwapOperation[]; 332 | swapAmountIn?: string; 333 | priceImpactPercent?: string; 334 | }; 335 | 336 | export type SwapRouteJSON = { 337 | swap_amount_in: string; 338 | denom_in: string; 339 | swap_operations: SwapOperationJSON[]; 340 | }; 341 | 342 | export type SwapRoute = { 343 | swapAmountIn: string; 344 | denomIn: string; 345 | swapOperations: SwapOperation[]; 346 | }; 347 | 348 | export type SmartSwapExactCoinInJSON = { 349 | swap_venue: SwapVenueJSON; 350 | swap_routes: SwapRouteJSON[]; 351 | }; 352 | 353 | export type SmartSwapExactCoinIn = { 354 | swapVenue: SwapVenue; 355 | swapRoutes: SwapRoute[]; 356 | }; 357 | 358 | export type SwapJSON = ( 359 | | { swap_in: SwapExactCoinInJSON } 360 | | { swap_out: SwapExactCoinOutJSON } 361 | | { smart_swap_in: SmartSwapExactCoinInJSON } 362 | ) & { 363 | estimated_affiliate_fee?: string; 364 | from_chain_id: string; 365 | chain_id: string; 366 | denom_in: string; 367 | denom_out: string; 368 | swap_venues: SwapVenueJSON[]; 369 | }; 370 | 371 | export type Swap = ( 372 | | { swapIn: SwapExactCoinIn } 373 | | { swapOut: SwapExactCoinOut } 374 | | { smartSwapIn: SmartSwapExactCoinIn } 375 | ) & { 376 | estimatedAffiliateFee?: string; 377 | fromChainID: string; 378 | chainID: string; 379 | denomIn: string; 380 | denomOut: string; 381 | swapVenues: SwapVenue[]; 382 | }; 383 | 384 | export type EvmSwapJSON = { 385 | input_token: string; 386 | amount_in: string; 387 | swap_calldata: string; 388 | amount_out: string; 389 | from_chain_id: string; 390 | denom_in: string; 391 | denom_out: string; 392 | swap_venues: SwapVenueJSON[]; 393 | }; 394 | 395 | export type EvmSwap = { 396 | inputToken: string; 397 | amountIn: string; 398 | swapCalldata: string; 399 | amountOut: string; 400 | fromChainID: string; 401 | denomIn: string; 402 | denomOut: string; 403 | swapVenues: SwapVenue[]; 404 | }; 405 | 406 | export type AffiliateJSON = { 407 | basis_points_fee: string; 408 | address: string; 409 | }; 410 | 411 | export type Affiliate = { 412 | basisPointsFee: string; 413 | address: string; 414 | }; 415 | 416 | export type ChainAffiliatesJSON = { 417 | affiliates: AffiliateJSON[]; 418 | }; 419 | 420 | export type ChainAffiliates = { 421 | affiliates: Affiliate[]; 422 | }; 423 | 424 | export type Reason = "UNKNOWN" | "BASE_TOKEN" | "MOST_LIQUID" | "DIRECT"; 425 | 426 | export type CosmWasmContractMsgJSON = { 427 | contract_address: string; 428 | msg: string; 429 | }; 430 | 431 | export type CosmWasmContractMsg = { 432 | contractAddress: string; 433 | msg: string; 434 | }; 435 | 436 | export type AutopilotAction = "LIQUID_STAKE" | "CLAIM"; 437 | 438 | export type AutopilotMsg = { 439 | receiver: string; 440 | action: AutopilotAction; 441 | }; 442 | 443 | export type PostHandlerJSON = 444 | | { wasm_msg: CosmWasmContractMsgJSON } 445 | | { autopilot_msg: AutopilotMsg }; 446 | 447 | export type PostHandler = 448 | | { wasmMsg: CosmWasmContractMsg } 449 | | { autopilotMsg: AutopilotMsg }; 450 | 451 | export type ERC20ApprovalJSON = { 452 | token_contract: string; 453 | spender: string; 454 | amount: string; 455 | }; 456 | 457 | export type ERC20Approval = { 458 | tokenContract: string; 459 | spender: string; 460 | amount: string; 461 | }; 462 | 463 | export type SvmTxJSON = { 464 | chain_id: string; 465 | tx: string; 466 | signer_address: string; 467 | }; 468 | 469 | export type SvmTx = { 470 | chainID: string; 471 | tx: string; 472 | signerAddress: string; 473 | }; 474 | 475 | export type EvmTxJSON = { 476 | chain_id: string; 477 | to: string; 478 | value: string; 479 | data: string; 480 | required_erc20_approvals: ERC20ApprovalJSON[]; 481 | signer_address: string; 482 | }; 483 | 484 | export type EvmTx = { 485 | chainID: string; 486 | to: string; 487 | value: string; 488 | data: string; 489 | requiredERC20Approvals: ERC20Approval[]; 490 | signerAddress: string; 491 | }; 492 | 493 | export type DenomWithChainIDJSON = { 494 | denom: string; 495 | chain_id: string; 496 | }; 497 | 498 | export type DenomWithChainID = { 499 | denom: string; 500 | chainID: string; 501 | }; 502 | 503 | export type ApiError = { 504 | message: string; 505 | }; 506 | 507 | export type AssetOrErrorJSON = { asset: AssetJSON } | { error: ApiError }; 508 | 509 | export type AssetOrError = { asset: Asset } | { error: ApiError }; 510 | 511 | export type OriginAssetsRequestJSON = { 512 | assets: DenomWithChainIDJSON[]; 513 | }; 514 | 515 | export type OriginAssetsRequest = { 516 | assets: DenomWithChainID[]; 517 | }; 518 | 519 | export type OriginAssetsResponseJSON = { 520 | origin_assets: AssetOrErrorJSON[]; 521 | }; 522 | 523 | export type OriginAssetsResponse = { 524 | originAssets: AssetOrError[]; 525 | }; 526 | 527 | export type SmartSwapOptionsJSON = { 528 | split_routes?: boolean; 529 | evm_swaps?: boolean; 530 | evm_slippage_tolerance_percent?: string; 531 | }; 532 | 533 | export type SmartSwapOptions = { 534 | splitRoutes?: boolean; 535 | evmSwaps?: boolean; 536 | evmSlippageTolerancePercent?: string; 537 | }; 538 | -------------------------------------------------------------------------------- /packages/core/src/types/unified.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Affiliate, 3 | AffiliateJSON, 4 | ApiError, 5 | Asset, 6 | AssetJSON, 7 | AxelarTransfer, 8 | AxelarTransferJSON, 9 | BankSend, 10 | BankSendJSON, 11 | CCTPTransfer, 12 | CCTPTransferJSON, 13 | EvmTx, 14 | EvmTxJSON, 15 | HyperlaneTransfer, 16 | HyperlaneTransferJSON, 17 | OPInitTransfer, 18 | OPInitTransferJSON, 19 | MultiChainMsg, 20 | MultiChainMsgJSON, 21 | PostHandler, 22 | PostHandlerJSON, 23 | Reason, 24 | EvmSwap, 25 | EvmSwapJSON, 26 | Swap, 27 | SwapJSON, 28 | SwapVenue, 29 | SwapVenueJSON, 30 | SwapVenueRequest, 31 | SwapVenueRequestJSON, 32 | Transfer, 33 | TransferJSON, 34 | CosmosTxJSON, 35 | CosmosTx, 36 | SvmTxJSON, 37 | SvmTx, 38 | SmartSwapOptions, 39 | SmartSwapOptionsJSON, 40 | ChainAffiliatesJSON, 41 | ChainAffiliates, 42 | } from "./shared"; 43 | 44 | export type AssetsRequestJSON = { 45 | chain_ids?: string[]; 46 | native_only?: boolean; 47 | include_no_metadata_assets?: boolean; 48 | include_cw20_assets?: boolean; 49 | include_evm_assets?: boolean; 50 | include_svm_assets?: boolean; 51 | only_testnets?: boolean; 52 | /** 53 | * @deprecated Use `chain_ids` instead 54 | */ 55 | chain_id?: string; 56 | }; 57 | 58 | export type AssetsRequest = { 59 | chainIDs?: string[]; 60 | nativeOnly?: boolean; 61 | includeNoMetadataAssets?: boolean; 62 | includeCW20Assets?: boolean; 63 | includeEvmAssets?: boolean; 64 | includeSvmAssets?: boolean; 65 | onlyTestnets?: boolean; 66 | /** 67 | * @deprecated Use `chainIDs` instead 68 | */ 69 | chainID?: string; 70 | }; 71 | 72 | export type AssetsFromSourceRequestJSON = { 73 | source_asset_denom: string; 74 | source_asset_chain_id: string; 75 | allow_multi_tx?: boolean; 76 | include_cw20_assets: boolean; 77 | }; 78 | 79 | export type AssetsFromSourceRequest = { 80 | sourceAssetDenom: string; 81 | sourceAssetChainID: string; 82 | allowMultiTx?: boolean; 83 | includeCW20Assets: boolean; 84 | }; 85 | 86 | export type AssetRecommendation = { 87 | asset: Asset; 88 | reason: Reason; 89 | }; 90 | 91 | export type AssetRecommendationJSON = { 92 | asset: AssetJSON; 93 | reason: Reason; 94 | }; 95 | 96 | export type AssetRecommendationRequestJSON = { 97 | source_asset_denom: string; 98 | source_asset_chain_id: string; 99 | dest_chain_id: string; 100 | reason?: Reason; 101 | }; 102 | 103 | export type AssetRecommendationRequest = { 104 | sourceAssetDenom: string; 105 | sourceAssetChainID: string; 106 | destChainID: string; 107 | reason?: Reason; 108 | }; 109 | 110 | export type RecommendAssetsRequestJSON = { 111 | requests: AssetRecommendationRequestJSON[]; 112 | }; 113 | 114 | export type RecommendAssetsRequest = { 115 | requests: AssetRecommendationRequest[]; 116 | }; 117 | 118 | export type RecommendAssetsResponseJSON = { 119 | recommendations: AssetRecommendationJSON[]; 120 | recommendation_entries: RecommendationEntryJSON[]; 121 | }; 122 | 123 | export type RecommendAssetsResponse = { 124 | recommendations: AssetRecommendation[]; 125 | recommendationEntries: RecommendationEntry[]; 126 | }; 127 | 128 | export type RecommendationEntryJSON = { 129 | recommendations: AssetRecommendationJSON[]; 130 | error?: ApiError; 131 | }; 132 | 133 | export type RecommendationEntry = { 134 | recommendations: AssetRecommendation[]; 135 | error?: ApiError; 136 | }; 137 | 138 | export type RouteRequestBaseJSON = { 139 | source_asset_denom: string; 140 | source_asset_chain_id: string; 141 | dest_asset_denom: string; 142 | dest_asset_chain_id: string; 143 | 144 | cumulative_affiliate_fee_bps?: string; 145 | swap_venue?: SwapVenueRequestJSON; 146 | swap_venues?: SwapVenueRequestJSON[]; 147 | allow_unsafe?: boolean; 148 | experimental_features?: ExperimentalFeature[]; 149 | bridges?: BridgeType[]; 150 | allow_multi_tx?: boolean; 151 | smart_relay?: boolean; 152 | smart_swap_options?: SmartSwapOptionsJSON; 153 | allow_swaps?: boolean; 154 | }; 155 | 156 | export type RouteRequestGivenInJSON = RouteRequestBaseJSON & { 157 | amount_in: string; 158 | amount_out?: never; 159 | }; 160 | 161 | export type RouteRequestGivenOutJSON = RouteRequestBaseJSON & { 162 | amount_in?: never; 163 | amount_out: string; 164 | }; 165 | 166 | export type RouteRequestJSON = 167 | | RouteRequestGivenInJSON 168 | | RouteRequestGivenOutJSON; 169 | 170 | export type MsgsDirectResponse = { 171 | msgs: Msg[]; 172 | txs: Tx[]; 173 | route: RouteResponse; 174 | }; 175 | 176 | export type MsgsDirectResponseJSON = { 177 | msgs: MsgJSON[]; 178 | txs: TxJSON[]; 179 | route: RouteResponseJSON; 180 | }; 181 | 182 | export type RouteRequestBase = { 183 | sourceAssetDenom: string; 184 | sourceAssetChainID: string; 185 | destAssetDenom: string; 186 | destAssetChainID: string; 187 | 188 | cumulativeAffiliateFeeBPS?: string; 189 | swapVenue?: SwapVenueRequest; 190 | swapVenues?: SwapVenueRequest[]; 191 | allowUnsafe?: boolean; 192 | experimentalFeatures?: ExperimentalFeature[]; 193 | bridges?: BridgeType[]; 194 | allowMultiTx?: boolean; 195 | smartRelay?: boolean; 196 | smartSwapOptions?: SmartSwapOptions; 197 | allowSwaps?: boolean; 198 | }; 199 | 200 | export type RouteRequestGivenIn = RouteRequestBase & { 201 | amountIn: string; 202 | amountOut?: never; 203 | }; 204 | 205 | export type RouteRequestGivenOut = RouteRequestBase & { 206 | amountIn?: never; 207 | amountOut: string; 208 | }; 209 | 210 | export type RouteRequest = RouteRequestGivenIn | RouteRequestGivenOut; 211 | 212 | export type RouteWarningType = "LOW_INFO_WARNING" | "BAD_PRICE_WARNING"; 213 | 214 | export type ExperimentalFeature = "cctp" | "hyperlane"; 215 | 216 | export type RouteWarning = { 217 | type: RouteWarningType; 218 | message: string; 219 | }; 220 | 221 | export type FeeType = "SMART_RELAY"; 222 | 223 | export type EstimatedFee = { 224 | feeType: FeeType; 225 | bridgeID: BridgeType; 226 | amount: string; 227 | usdAmount: string; 228 | originAsset: Asset; 229 | chainID: string; 230 | txIndex: number; 231 | operationIndex?: number; 232 | }; 233 | 234 | export type EstimatedFeeJSON = { 235 | fee_type: FeeType; 236 | bridge_id: BridgeType; 237 | amount: string; 238 | usd_amount: string; 239 | origin_asset: AssetJSON; 240 | chain_id: string; 241 | tx_index: number; 242 | operation_index?: number; 243 | }; 244 | 245 | export type OperationJSON = 246 | | { 247 | transfer: TransferJSON; 248 | tx_index: number; 249 | amount_in: string; 250 | amount_out: string; 251 | } 252 | | { 253 | bank_send: BankSendJSON; 254 | tx_index: number; 255 | amount_in: string; 256 | amount_out: string; 257 | } 258 | | { swap: SwapJSON; tx_index: number; amount_in: string; amount_out: string } 259 | | { 260 | axelar_transfer: AxelarTransferJSON; 261 | tx_index: number; 262 | amount_in: string; 263 | amount_out: string; 264 | } 265 | | { 266 | cctp_transfer: CCTPTransferJSON; 267 | tx_index: number; 268 | amount_in: string; 269 | amount_out: string; 270 | } 271 | | { 272 | hyperlane_transfer: HyperlaneTransferJSON; 273 | tx_index: number; 274 | amount_in: string; 275 | amount_out: string; 276 | } 277 | | { 278 | evm_swap: EvmSwapJSON; 279 | tx_index: number; 280 | amount_in: string; 281 | amount_out: string; 282 | } 283 | | { 284 | op_init_transfer: OPInitTransferJSON; 285 | tx_index: number; 286 | amount_in: string; 287 | amount_out: string; 288 | }; 289 | 290 | export type Operation = 291 | | { transfer: Transfer; txIndex: number; amountIn: string; amountOut: string } 292 | | { bankSend: BankSend; txIndex: number; amountIn: string; amountOut: string } 293 | | { swap: Swap; txIndex: number; amountIn: string; amountOut: string } 294 | | { 295 | axelarTransfer: AxelarTransfer; 296 | txIndex: number; 297 | amountIn: string; 298 | amountOut: string; 299 | } 300 | | { 301 | cctpTransfer: CCTPTransfer; 302 | txIndex: number; 303 | amountIn: string; 304 | amountOut: string; 305 | } 306 | | { 307 | hyperlaneTransfer: HyperlaneTransfer; 308 | txIndex: number; 309 | amountIn: string; 310 | amountOut: string; 311 | } 312 | | { 313 | evmSwap: EvmSwap; 314 | txIndex: number; 315 | amountIn: string; 316 | amountOut: string; 317 | } 318 | | { 319 | opInitTransfer: OPInitTransfer; 320 | txIndex: number; 321 | amountIn: string; 322 | amountOut: string; 323 | }; 324 | 325 | export type RouteResponseJSON = { 326 | source_asset_denom: string; 327 | source_asset_chain_id: string; 328 | dest_asset_denom: string; 329 | dest_asset_chain_id: string; 330 | amount_in: string; 331 | amount_out: string; 332 | 333 | operations: OperationJSON[]; 334 | chain_ids: string[]; 335 | required_chain_addresses: string[]; 336 | 337 | does_swap: boolean; 338 | estimated_amount_out?: string; 339 | swap_venues?: SwapVenueJSON[]; 340 | 341 | txs_required: number; 342 | 343 | usd_amount_in?: string; 344 | usd_amount_out?: string; 345 | swap_price_impact_percent?: string; 346 | 347 | warning?: RouteWarning; 348 | estimated_fees: EstimatedFeeJSON[]; 349 | }; 350 | 351 | export type RouteResponse = { 352 | sourceAssetDenom: string; 353 | sourceAssetChainID: string; 354 | destAssetDenom: string; 355 | destAssetChainID: string; 356 | amountIn: string; 357 | amountOut: string; 358 | 359 | operations: Operation[]; 360 | chainIDs: string[]; 361 | requiredChainAddresses: string[]; 362 | 363 | doesSwap: boolean; 364 | estimatedAmountOut?: string; 365 | swapVenues?: SwapVenue[]; 366 | 367 | txsRequired: number; 368 | 369 | usdAmountIn?: string; 370 | usdAmountOut?: string; 371 | swapPriceImpactPercent?: string; 372 | 373 | warning?: RouteWarning; 374 | estimatedFees: EstimatedFee[]; 375 | }; 376 | 377 | export type MsgsRequestJSON = { 378 | source_asset_denom: string; 379 | source_asset_chain_id: string; 380 | dest_asset_denom: string; 381 | dest_asset_chain_id: string; 382 | amount_in: string; 383 | amount_out: string; 384 | address_list: string[]; 385 | operations: OperationJSON[]; 386 | 387 | estimated_amount_out?: string; 388 | slippage_tolerance_percent?: string; 389 | affiliates?: AffiliateJSON[]; 390 | chain_ids_to_affiliates?: Record; 391 | post_route_handler?: PostHandlerJSON; 392 | }; 393 | 394 | export type MsgsRequest = { 395 | sourceAssetDenom: string; 396 | sourceAssetChainID: string; 397 | destAssetDenom: string; 398 | destAssetChainID: string; 399 | amountIn: string; 400 | amountOut: string; 401 | /** 402 | * addresses should be in the same order with the `chainIDs` in the `route` 403 | */ 404 | addressList: string[]; 405 | operations: Operation[]; 406 | 407 | estimatedAmountOut?: string; 408 | slippageTolerancePercent?: string; 409 | affiliates?: Affiliate[]; 410 | chainIDsToAffiliates?: Record; 411 | 412 | postRouteHandler?: PostHandler; 413 | }; 414 | 415 | export type MsgsDirectRequestJSON = { 416 | source_asset_denom: string; 417 | source_asset_chain_id: string; 418 | dest_asset_denom: string; 419 | dest_asset_chain_id: string; 420 | amount_in: string; 421 | amount_out: string; 422 | chain_ids_to_addresses: { 423 | [key: string]: string; 424 | }; 425 | swap_venue?: SwapVenueJSON; 426 | swap_venues?: SwapVenueJSON[]; 427 | slippage_tolerance_percent?: string; 428 | timeout_seconds?: string; 429 | 430 | affiliates?: AffiliateJSON[]; 431 | chain_ids_to_affiliates?: Record; 432 | 433 | post_route_handler?: PostHandlerJSON; 434 | 435 | allow_unsafe?: boolean; 436 | experimental_features?: ExperimentalFeature[]; 437 | bridges?: BridgeType[]; 438 | allow_multi_tx?: boolean; 439 | smart_relay?: boolean; 440 | smart_swap_options?: SmartSwapOptionsJSON; 441 | allow_swaps?: boolean; 442 | }; 443 | 444 | export type MsgsDirectRequest = { 445 | sourceAssetDenom: string; 446 | sourceAssetChainID: string; 447 | destAssetDenom: string; 448 | destAssetChainID: string; 449 | amountIn: string; 450 | amountOut: string; 451 | chainIdsToAddresses: { 452 | [key: string]: string; 453 | }; 454 | swapVenue?: SwapVenue; 455 | swapVenues?: SwapVenue[]; 456 | slippageTolerancePercent?: string; 457 | timeoutSeconds?: string; 458 | affiliates?: Affiliate[]; 459 | chainIDsToAffiliates?: Record; 460 | 461 | postRouteHandler?: PostHandler; 462 | 463 | allowUnsafe?: boolean; 464 | experimentalFeatures?: ExperimentalFeature[]; 465 | bridges?: BridgeType[]; 466 | allowMultiTx?: boolean; 467 | smartRelay?: boolean; 468 | smartSwapOptions?: SmartSwapOptions; 469 | allowSwaps?: boolean; 470 | }; 471 | 472 | export type MsgJSON = 473 | | { multi_chain_msg: MultiChainMsgJSON } 474 | | { evm_tx: EvmTxJSON } 475 | | { svm_tx: SvmTxJSON }; 476 | 477 | export type Msg = 478 | | { multiChainMsg: MultiChainMsg } 479 | | { evmTx: EvmTx } 480 | | { svmTx: SvmTx }; 481 | 482 | export type TxJSON = 483 | | { cosmos_tx: CosmosTxJSON; operations_indices: number[] } 484 | | { evm_tx: EvmTxJSON; operations_indices: number[] } 485 | | { svm_tx: SvmTxJSON; operations_indices: number[] }; 486 | 487 | export type Tx = 488 | | { cosmosTx: CosmosTx; operationsIndices: number[] } 489 | | { evmTx: EvmTx; operationsIndices: number[] } 490 | | { svmTx: SvmTx; operationsIndices: number[] }; 491 | 492 | export type MsgsResponseJSON = { 493 | msgs: MsgJSON[]; 494 | estimated_fees: EstimatedFeeJSON[]; 495 | txs: TxJSON[]; 496 | }; 497 | 498 | export type MsgsResponse = { 499 | /** 500 | * @deprecated Use `txs` instead 501 | */ 502 | msgs: Msg[]; 503 | estimatedFees: EstimatedFee[]; 504 | txs: Tx[]; 505 | }; 506 | 507 | export type BridgeType = "IBC" | "AXELAR" | "CCTP" | "HYPERLANE"; 508 | 509 | export type AssetBetweenChainsJSON = { 510 | asset_on_source: AssetJSON; 511 | asset_on_dest: AssetJSON; 512 | txs_required: number; 513 | bridges: BridgeType[]; 514 | }; 515 | 516 | export type AssetBetweenChains = { 517 | assetOnSource: Asset; 518 | assetOnDest: Asset; 519 | txsRequired: number; 520 | bridges: BridgeType[]; 521 | }; 522 | 523 | export type AssetsBetweenChainsRequestJSON = { 524 | source_chain_id: string; 525 | dest_chain_id: string; 526 | 527 | include_no_metadata_assets?: boolean; 528 | include_cw20_assets?: boolean; 529 | include_evm_assets?: boolean; 530 | 531 | allow_multi_tx?: boolean; 532 | }; 533 | 534 | export type AssetsBetweenChainsRequest = { 535 | sourceChainID: string; 536 | destChainID: string; 537 | 538 | includeNoMetadataAssets?: boolean; 539 | includeCW20Assets?: boolean; 540 | includeEvmAssets?: boolean; 541 | 542 | allowMultiTx?: boolean; 543 | }; 544 | 545 | export type AssetsBetweenChainsResponseJSON = { 546 | assets_between_chains: AssetBetweenChainsJSON[]; 547 | }; 548 | 549 | export type AssetsBetweenChainsResponse = { 550 | assetsBetweenChains: AssetBetweenChains[]; 551 | }; 552 | 553 | export type BridgesResponseJSON = { 554 | bridges: BridgeJSON[]; 555 | }; 556 | 557 | export type BridgesResponse = { 558 | bridges: Bridge[]; 559 | }; 560 | 561 | export type BridgeJSON = { 562 | id: BridgeType; 563 | name: string; 564 | logo_uri: string; 565 | }; 566 | 567 | export type Bridge = { 568 | id: BridgeType; 569 | name: string; 570 | logoURI: string; 571 | }; 572 | -------------------------------------------------------------------------------- /packages/core/starship/ci.yaml: -------------------------------------------------------------------------------- 1 | chains: 2 | - name: osmosis-1 3 | type: osmosis 4 | numValidators: 1 5 | faucet: 6 | enabled: true 7 | ports: 8 | rest: 1313 9 | rpc: 26653 10 | faucet: 8082 11 | resources: 12 | cpu: "0.2" 13 | memory: "200M" 14 | 15 | - name: gaia-1 16 | type: cosmos 17 | numValidators: 1 18 | faucet: 19 | enabled: true 20 | ports: 21 | rest: 1317 22 | rpc: 26657 23 | faucet: 8083 24 | resources: 25 | cpu: "0.2" 26 | memory: "200M" 27 | 28 | - name: evmos_9000-1 29 | type: evmos 30 | numValidators: 1 31 | faucet: 32 | enabled: false 33 | ports: 34 | rest: 1318 35 | rpc: 26658 36 | resources: 37 | cpu: "0.2" 38 | memory: "200M" 39 | 40 | - name: injective-1 41 | type: injective 42 | numValidators: 1 43 | faucet: 44 | enabled: false 45 | ports: 46 | rest: 1319 47 | rpc: 26659 48 | resources: 49 | cpu: "0.2" 50 | memory: "200M" 51 | 52 | relayers: 53 | - name: osmos-gaia 54 | type: hermes 55 | replicas: 1 56 | chains: 57 | - osmosis-1 58 | - gaia-1 59 | resources: 60 | cpu: "0.1" 61 | memory: "100M" 62 | 63 | - name: injective-osmos 64 | type: hermes 65 | replicas: 1 66 | chains: 67 | - injective-1 68 | - osmosis-1 69 | resources: 70 | cpu: "0.1" 71 | memory: "100M" 72 | 73 | - name: evmos-osmos 74 | type: hermes 75 | replicas: 1 76 | chains: 77 | - evmos_9000-1 78 | - osmosis-1 79 | resources: 80 | cpu: "0.1" 81 | memory: "100M" 82 | 83 | explorer: 84 | enabled: false 85 | 86 | registry: 87 | enabled: true 88 | ports: 89 | rest: 8081 90 | grpc: 9091 91 | resources: 92 | cpu: "0.1" 93 | memory: "100M" 94 | 95 | exposer: 96 | resources: 97 | cpu: "0.1" 98 | memory: "100M" 99 | 100 | faucet: 101 | resources: 102 | cpu: "0.1" 103 | memory: "100M" 104 | -------------------------------------------------------------------------------- /packages/core/starship/local.yaml: -------------------------------------------------------------------------------- 1 | chains: 2 | - name: osmosis-1 3 | type: osmosis 4 | numValidators: 1 5 | faucet: 6 | enabled: true 7 | ports: 8 | rest: 1313 9 | rpc: 26653 10 | faucet: 8082 11 | 12 | - name: gaia-1 13 | type: cosmos 14 | numValidators: 1 15 | faucet: 16 | enabled: true 17 | ports: 18 | rest: 1317 19 | rpc: 26657 20 | faucet: 8083 21 | 22 | - name: evmos_9000-1 23 | type: evmos 24 | numValidators: 1 25 | faucet: 26 | enabled: false 27 | ports: 28 | rest: 1318 29 | rpc: 26658 30 | 31 | - name: injective-1 32 | type: injective 33 | numValidators: 1 34 | faucet: 35 | enabled: false 36 | ports: 37 | rest: 1319 38 | rpc: 26659 39 | 40 | 41 | relayers: 42 | - name: osmos-gaia 43 | type: hermes 44 | replicas: 1 45 | chains: 46 | - osmosis-1 47 | - gaia-1 48 | - name: injective-osmos 49 | type: hermes 50 | replicas: 1 51 | chains: 52 | - injective-1 53 | - osmosis-1 54 | - name: evmos-osmos 55 | type: hermes 56 | replicas: 1 57 | chains: 58 | - evmos_9000-1 59 | - osmosis-1 60 | 61 | explorer: 62 | enabled: false 63 | 64 | registry: 65 | enabled: true 66 | ports: 67 | rest: 8081 68 | grpc: 9091 69 | -------------------------------------------------------------------------------- /packages/core/transactions.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./dist/transactions"; 2 | -------------------------------------------------------------------------------- /packages/core/transactions.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./dist/transactions"); 2 | -------------------------------------------------------------------------------- /packages/core/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "src/**/*.test.ts", "src/**/*.test.js"], 4 | "include": ["src/**/*.ts", "src/**/*.js"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "baseUrl": ".", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "isolatedModules": true, 8 | "jsx": "preserve", 9 | "lib": ["dom", "dom.iterable", "esnext"], 10 | "module": "es6", 11 | "moduleResolution": "node", 12 | "noEmit": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "noUncheckedIndexedAccess": true, 15 | "resolveJsonModule": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "strictNullChecks": true, 19 | "target": "es6" 20 | }, 21 | "exclude": ["node_modules", "src/codegen/**/*.ts"], 22 | "include": ["**/*.ts", "**/*.js"] 23 | } 24 | -------------------------------------------------------------------------------- /packages/core/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { Options } from "tsup"; 2 | import { defineConfig } from "tsup"; 3 | 4 | const defaultOptions: Options = { 5 | cjsInterop: true, 6 | clean: true, 7 | dts: true, 8 | format: ["cjs"], 9 | minify: false, 10 | shims: true, 11 | splitting: true, 12 | treeshake: true, 13 | tsconfig: "./tsconfig.build.json", 14 | }; 15 | 16 | export default defineConfig(async ({ watch }) => { 17 | return [ 18 | { 19 | ...defaultOptions, 20 | clean: !watch, 21 | entry: { 22 | index: "src/index.ts", 23 | parser: "src/parser.ts", 24 | transactions: "src/transactions.ts", 25 | types: "src/types/index.ts", 26 | }, 27 | external: [ 28 | /^@cosmjs\/.*/, 29 | /^@injectivelabs\/.*/, 30 | /^@protobufjs\/.*/, 31 | "long", 32 | "protobufjs", 33 | // 34 | ], 35 | }, 36 | ]; 37 | }); 38 | -------------------------------------------------------------------------------- /packages/core/types.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./dist/types"; 2 | -------------------------------------------------------------------------------- /packages/core/types.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./dist/types"); 2 | -------------------------------------------------------------------------------- /packages/core/vitest.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | deps: { 6 | optimizer: { 7 | web: { 8 | enabled: true, 9 | }, 10 | ssr: { 11 | enabled: true, 12 | }, 13 | }, 14 | }, 15 | globals: true, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/core/vitest.e2e.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | import config from "./vitest.config.mjs"; 4 | 5 | export default defineConfig({ 6 | ...config, 7 | test: { 8 | ...config.test, 9 | include: ["**/e2e/*.test.ts"], 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/core/vitest.unit.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | import config from "./vitest.config.mjs"; 4 | 5 | export default defineConfig({ 6 | ...config, 7 | test: { 8 | ...config.test, 9 | exclude: ["**/e2e/**"], 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/examples/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | const eslintConfig = { 3 | env: { 4 | node: true, 5 | }, 6 | extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"], 7 | parser: "@typescript-eslint/parser", 8 | parserOptions: { 9 | ecmaVersion: "latest", 10 | sourceType: "module", 11 | }, 12 | plugins: ["@typescript-eslint", "simple-import-sort"], 13 | root: true, 14 | }; 15 | 16 | module.exports = eslintConfig; 17 | -------------------------------------------------------------------------------- /packages/examples/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # examples 2 | 3 | ## 1.0.32 4 | 5 | ### Patch Changes 6 | 7 | - Updated dependencies [11c529f] 8 | - @skip-router/core@5.2.1 9 | 10 | ## 1.0.31 11 | 12 | ### Patch Changes 13 | 14 | - Updated dependencies [d06a1e4] 15 | - Updated dependencies [7ab600d] 16 | - Updated dependencies [dc5c8f9] 17 | - @skip-router/core@5.2.0 18 | 19 | ## 1.0.30 20 | 21 | ### Patch Changes 22 | 23 | - Updated dependencies [f0c663d] 24 | - @skip-router/core@5.1.1 25 | 26 | ## 1.0.29 27 | 28 | ### Patch Changes 29 | 30 | - Updated dependencies [05630c1] 31 | - @skip-router/core@5.1.0 32 | 33 | ## 1.0.28 34 | 35 | ### Patch Changes 36 | 37 | - Updated dependencies [3c47bf1] 38 | - @skip-router/core@5.0.5 39 | 40 | ## 1.0.27 41 | 42 | ### Patch Changes 43 | 44 | - Updated dependencies [a91e0e0] 45 | - @skip-router/core@5.0.4 46 | 47 | ## 1.0.26 48 | 49 | ### Patch Changes 50 | 51 | - Updated dependencies [d1d0161] 52 | - @skip-router/core@5.0.3 53 | 54 | ## 1.0.25 55 | 56 | ### Patch Changes 57 | 58 | - Updated dependencies [f17d415] 59 | - @skip-router/core@5.0.2 60 | 61 | ## 1.0.24 62 | 63 | ### Patch Changes 64 | 65 | - Updated dependencies [d226070] 66 | - @skip-router/core@5.0.1 67 | 68 | ## 1.0.23 69 | 70 | ### Patch Changes 71 | 72 | - Updated dependencies [26652d3] 73 | - @skip-router/core@5.0.0 74 | 75 | ## 1.0.22 76 | 77 | ### Patch Changes 78 | 79 | - Updated dependencies [c3a1a02] 80 | - Updated dependencies [484387a] 81 | - @skip-router/core@4.2.0 82 | 83 | ## 1.0.21 84 | 85 | ### Patch Changes 86 | 87 | - Updated dependencies [a88619c] 88 | - @skip-router/core@4.1.1 89 | 90 | ## 1.0.20 91 | 92 | ### Patch Changes 93 | 94 | - Updated dependencies [48d998b] 95 | - @skip-router/core@4.1.0 96 | 97 | ## 1.0.19 98 | 99 | ### Patch Changes 100 | 101 | - Updated dependencies [f558aa4] 102 | - @skip-router/core@4.0.1 103 | 104 | ## 1.0.18 105 | 106 | ### Patch Changes 107 | 108 | - Updated dependencies [3c91d03] 109 | - @skip-router/core@4.0.0 110 | 111 | ## 1.0.17 112 | 113 | ### Patch Changes 114 | 115 | - Updated dependencies [2af8ccd] 116 | - @skip-router/core@3.0.2 117 | 118 | ## 1.0.16 119 | 120 | ### Patch Changes 121 | 122 | - Updated dependencies [ccdb6ef] 123 | - @skip-router/core@3.0.1 124 | 125 | ## 1.0.15 126 | 127 | ### Patch Changes 128 | 129 | - Updated dependencies [8846e1a] 130 | - @skip-router/core@3.0.0 131 | 132 | ## 1.0.14 133 | 134 | ### Patch Changes 135 | 136 | - Updated dependencies [b4fd9ed] 137 | - @skip-router/core@2.4.4 138 | 139 | ## 1.0.13 140 | 141 | ### Patch Changes 142 | 143 | - Updated dependencies [59364ac] 144 | - @skip-router/core@2.4.3 145 | 146 | ## 1.0.12 147 | 148 | ### Patch Changes 149 | 150 | - Updated dependencies [52f94b7] 151 | - @skip-router/core@2.4.2 152 | 153 | ## 1.0.11 154 | 155 | ### Patch Changes 156 | 157 | - Updated dependencies [6af35dc] 158 | - @skip-router/core@2.4.1 159 | 160 | ## 1.0.10 161 | 162 | ### Patch Changes 163 | 164 | - Updated dependencies [9922837] 165 | - @skip-router/core@2.4.0 166 | 167 | ## 1.0.9 168 | 169 | ### Patch Changes 170 | 171 | - Updated dependencies [9ab81a5] 172 | - @skip-router/core@2.3.0 173 | 174 | ## 1.0.8 175 | 176 | ### Patch Changes 177 | 178 | - Updated dependencies [8b93aa7] 179 | - @skip-router/core@2.2.0 180 | 181 | ## 1.0.7 182 | 183 | ### Patch Changes 184 | 185 | - Updated dependencies [a2f7ffa] 186 | - @skip-router/core@2.1.0 187 | 188 | ## 1.0.6 189 | 190 | ### Patch Changes 191 | 192 | - Updated dependencies [8c4cafb] 193 | - @skip-router/core@2.0.5 194 | 195 | ## 1.0.5 196 | 197 | ### Patch Changes 198 | 199 | - Updated dependencies [8e0de72] 200 | - @skip-router/core@2.0.4 201 | 202 | ## 1.0.4 203 | 204 | ### Patch Changes 205 | 206 | - Updated dependencies [4903d27] 207 | - @skip-router/core@2.0.3 208 | 209 | ## 1.0.3 210 | 211 | ### Patch Changes 212 | 213 | - Updated dependencies [d162e7d] 214 | - @skip-router/core@2.0.2 215 | 216 | ## 1.0.2 217 | 218 | ### Patch Changes 219 | 220 | - Updated dependencies [2203797] 221 | - @skip-router/core@2.0.1 222 | 223 | ## 1.0.1 224 | 225 | ### Patch Changes 226 | 227 | - Updated dependencies [519b34f] 228 | - Updated dependencies [519b34f] 229 | - Updated dependencies [519b34f] 230 | - Updated dependencies [519b34f] 231 | - Updated dependencies [519b34f] 232 | - Updated dependencies [519b34f] 233 | - Updated dependencies [519b34f] 234 | - Updated dependencies [519b34f] 235 | - Updated dependencies [519b34f] 236 | - @skip-router/core@2.0.0 237 | 238 | ## 1.0.1-rc.8 239 | 240 | ### Patch Changes 241 | 242 | - Updated dependencies 243 | - @skip-router/core@2.0.0-rc.8 244 | 245 | ## 1.0.1-rc.7 246 | 247 | ### Patch Changes 248 | 249 | - Updated dependencies 250 | - @skip-router/core@2.0.0-rc.7 251 | 252 | ## 1.0.1-rc.6 253 | 254 | ### Patch Changes 255 | 256 | - Updated dependencies 257 | - @skip-router/core@2.0.0-rc.6 258 | 259 | ## 1.0.1-rc.5 260 | 261 | ### Patch Changes 262 | 263 | - Updated dependencies 264 | - @skip-router/core@2.0.0-rc.5 265 | 266 | ## 1.0.1-rc.4 267 | 268 | ### Patch Changes 269 | 270 | - Updated dependencies 271 | - @skip-router/core@2.0.0-rc.4 272 | 273 | ## 1.0.1-rc.3 274 | 275 | ### Patch Changes 276 | 277 | - Updated dependencies 278 | - @skip-router/core@2.0.0-rc.3 279 | 280 | ## 1.0.1-rc.2 281 | 282 | ### Patch Changes 283 | 284 | - Updated dependencies 285 | - @skip-router/core@2.0.0-rc.2 286 | 287 | ## 1.0.1-rc.1 288 | 289 | ### Patch Changes 290 | 291 | - Updated dependencies 292 | - @skip-router/core@2.0.0-rc.1 293 | 294 | ## 1.0.1-rc.0 295 | 296 | ### Patch Changes 297 | 298 | - Updated dependencies [b9b139d] 299 | - @skip-router/core@2.0.0-rc.0 300 | 301 | ## 1.0.1-2.0.0-rc.0.0 302 | 303 | ### Patch Changes 304 | 305 | - Updated dependencies 306 | - @skip-router/core@2.0.0-2.0.0-rc.0.0 307 | -------------------------------------------------------------------------------- /packages/examples/README.md: -------------------------------------------------------------------------------- 1 | # Skip Router SDK Examples 2 | 3 | This directory contains examples of how to use the `@skip-router/core` package. 4 | 5 | ## Basic example 6 | 7 | This example showcases how to swap from Cosmos Hub ATOM to Osmosis OSMO using the SDK. 8 | 9 | [Source](https://github.com/skip-mev/skip-router/blob/main/packages/examples/src/index.ts) 10 | 11 | ## Advanced example 12 | 13 | TODO 14 | -------------------------------------------------------------------------------- /packages/examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "examples", 3 | "type": "module", 4 | "version": "1.0.32", 5 | "scripts": { 6 | "start": "node src/skip-api-quickstart-example.js" 7 | }, 8 | "dependencies": { 9 | "@skip-router/core": "5.2.1" 10 | }, 11 | "private": true 12 | } 13 | -------------------------------------------------------------------------------- /packages/examples/src/skip-api-quickstart-example.js: -------------------------------------------------------------------------------- 1 | import { SkipRouter } from "@skip-router/core"; 2 | import * as chainRegistry from "chain-registry"; 3 | import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; 4 | import { stringToPath } from "@cosmjs/crypto"; 5 | 6 | // Generates a Cosmos signer for a given chainID, 7 | // loading the mnemonic from the environment 8 | async function getCosmosSigner(chainID) { 9 | // load mnemonic from environment 10 | const mnemonic = process.env.MNEMONIC; 11 | if (!mnemonic) { 12 | throw new Error("Mnemonic not set") 13 | } 14 | // find chain in chain registry to get bech32 prefix and cointype 15 | const chain = chainRegistry.chains.find(chain => chain.chain_id==chainID) 16 | if (!chain.bech32_prefix) { 17 | throw new Error(`Chain Registry missing prefix for {chainID}`) 18 | } 19 | if (!chain.slip44) { 20 | throw new Error(`Chain Registry missing cointype for {chainID}`) 21 | } 22 | // create wallet 23 | const hdPath = await stringToPath(`m/44'/${chain.slip44}'/0'/0/0`) 24 | const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { 25 | prefix: chain.bech32_prefix, 26 | hdPath: hdPath 27 | }) 28 | return wallet 29 | } 30 | 31 | async function getCosmosAddress(chainID) { 32 | const signer = await getCosmosSigner(chainID) 33 | const accounts = await signer.getAccounts() 34 | return accounts[0].address 35 | } 36 | 37 | (async () => { 38 | const skipClient = new SkipRouter({ 39 | getCosmosSigner, 40 | }) 41 | const route = await skipClient.route({ 42 | sourceAssetDenom: "uusdc", 43 | sourceAssetChainID: "noble-1", 44 | destAssetDenom: "utia", 45 | destAssetChainID: "celestia", 46 | amountIn: "500000", // .5 uusdc 47 | smartSwapOptions: { 48 | splitRoutes: true, 49 | }, 50 | cumulativeAffiliateFeeBPS: "0" 51 | }) 52 | console.log(route.requiredChainAddresses) 53 | console.log(route) 54 | // get user addresses for each requiredChainAddress 55 | const userAddresses = await Promise.all(route.requiredChainAddresses.map(async (chainID) => { 56 | return { 57 | chainID: chainID, 58 | address: await getCosmosAddress(chainID) 59 | } 60 | })) 61 | await skipClient.executeRoute({ 62 | route, 63 | userAddresses, 64 | onTransactionCompleted: (chainID, txHash, status) => { 65 | console.log(`Route completed with tx hash: ${txHash} & status: ${status.state}`) 66 | } 67 | }) 68 | } 69 | )() 70 | 71 | -------------------------------------------------------------------------------- /packages/examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "baseUrl": ".", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "isolatedModules": true, 8 | "jsx": "preserve", 9 | "lib": ["dom", "dom.iterable", "esnext"], 10 | "module": "es6", 11 | "moduleResolution": "node", 12 | "noEmit": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "noUncheckedIndexedAccess": true, 15 | "resolveJsonModule": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "strictNullChecks": true, 19 | "target": "es6", 20 | }, 21 | "exclude": ["node_modules"], 22 | "include": ["**/*.ts", "**/*.js"], 23 | } 24 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | const { devDependencies } = require("./package.json"); 4 | 5 | /** 6 | * @type {import("prettier").Config} 7 | * @see https://prettier.io/docs/en/configuration 8 | */ 9 | const prettierConfig = { 10 | endOfLine: "auto", 11 | plugins: Object.keys(devDependencies).filter((dep) => { 12 | return dep.startsWith("prettier-plugin-"); 13 | }), 14 | semi: true, 15 | singleAttributePerLine: true, 16 | singleQuote: false, 17 | trailingComma: "all", 18 | }; 19 | 20 | module.exports = prettierConfig; 21 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "pipeline": { 4 | "build": { 5 | "dependsOn": ["codegen"], 6 | "outputs": ["dist/**"] 7 | }, 8 | "codegen": { 9 | "dependsOn": [], 10 | "outputs": ["src/codegen/**"] 11 | }, 12 | "dev": { 13 | "cache": false, 14 | "persistent": true 15 | }, 16 | "lint": { 17 | "dependsOn": ["build"] 18 | }, 19 | "test": { 20 | "dependsOn": ["build"] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /vendor/index.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | const path = require("path"); 4 | 5 | const protoDirs = [ 6 | path.resolve(__dirname, "../node_modules/@protobufs/"), 7 | path.resolve(__dirname, "cosmos-proto/proto"), 8 | path.resolve(__dirname, "cosmos-sdk/proto"), 9 | path.resolve(__dirname, "evmos/proto"), 10 | path.resolve(__dirname, "noble-cctp/proto"), 11 | path.resolve(__dirname, "wasmd/proto"), 12 | path.resolve(__dirname, "../local_vendor/initia/proto"), 13 | path.resolve(__dirname, "../local_vendor/OPinit/proto"), 14 | path.resolve(__dirname, "../local_vendor/cosmos"), 15 | path.resolve(__dirname, "../local_vendor/cosmos_proto") 16 | ]; 17 | 18 | module.exports = protoDirs; 19 | -------------------------------------------------------------------------------- /vendor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vendor", 3 | "main": "index.js", 4 | "version": "1.0.0", 5 | "private": true 6 | } 7 | --------------------------------------------------------------------------------