{"id":36437805,"url":"https://github.com/ThalaLabs/surf","last_synced_at":"2026-01-18T13:00:31.065Z","repository":{"id":169224370,"uuid":"645114608","full_name":"ThalaLabs/surf","owner":"ThalaLabs","description":"Type-Safe TypeScript Interfaces \u0026 React Hooks for Aptos.","archived":false,"fork":false,"pushed_at":"2025-05-12T01:00:27.000Z","size":7018,"stargazers_count":50,"open_issues_count":17,"forks_count":12,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-08T23:16:14.476Z","etag":null,"topics":["aptos","blockchain"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ThalaLabs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-05-25T00:45:30.000Z","updated_at":"2025-07-14T13:31:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"c93dae3b-2683-4413-ac73-431a7f9088cc","html_url":"https://github.com/ThalaLabs/surf","commit_stats":null,"previous_names":["thalalabs/move-ts","thalalabs/surf"],"tags_count":40,"template":false,"template_full_name":null,"purl":"pkg:github/ThalaLabs/surf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThalaLabs%2Fsurf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThalaLabs%2Fsurf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThalaLabs%2Fsurf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThalaLabs%2Fsurf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ThalaLabs","download_url":"https://codeload.github.com/ThalaLabs/surf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThalaLabs%2Fsurf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28536686,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T10:13:46.436Z","status":"ssl_error","status_checked_at":"2026-01-18T10:13:11.045Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aptos","blockchain"],"created_at":"2026-01-11T20:00:22.343Z","updated_at":"2026-01-18T13:00:30.989Z","avatar_url":"https://github.com/ThalaLabs.png","language":"TypeScript","funding_links":[],"categories":["**6\\. Detailed Data Tables of Financial Projects**"],"sub_categories":["**Table 2: Aptos Ecosystem Financial Projects**"],"readme":"\u003cbr/\u003e\n\n\u003ch1 align=\"center\"\u003e\n  Surf\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  Type-Safe TypeScript Interfaces \u0026 React Hooks for Aptos.\n\u003cp\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@thalalabs/surf\"\u003e\n      \u003cimg src=\"https://img.shields.io/npm/v/@thalalabs/surf?colorA=2c8af7\u0026colorB=2c8af7\u0026style=flat\" alt=\"Version\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/ThalaLabs/surf/blob/main/LICENSE\"\u003e\n      \u003cimg src=\"https://img.shields.io/npm/l/@thalalabs/surf?colorA=2c8af7\u0026colorB=2c8af7\u0026style=flat\" alt=\"MIT License\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://bundlephobia.com/package/@thalalabs/surf\"\u003e\n      \u003cimg src=\"https://img.shields.io/bundlephobia/minzip/@thalalabs/surf?colorA=2c8af7\u0026colorB=2c8af7\u0026style=flat\" alt=\"MIT License\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n## Features\n\n- **No code-generation**: Interact with smart contracts using fully typed APIs based on static type inference. Inspired by [Viem](https://viem.sh/).\n- **Get rid of encoding/decoding**: Surf takes care of the complexities within the APIs, so you don't have to.\n- **Linting and Auto-Completion**: Enjoy a better development experience with type safety. No more guesswork for input and output.\n- **Both TypeScript Interfaces \u0026 React Hooks**: Easy to use, whether working with wallets or private keys.\n- **Low runtime cost \u0026 small bundle size**: [minzipped size: \u003c 2 kB](https://bundlephobia.com/package/@thalalabs/surf).\n\n## Overview\n\n```TypeScript\nconst client = createSurfClient(new Aptos());\n\nconst result = await client.useABI(COIN_ABI).entry.transfer({\n  functionArguments: ['0x1', 1],\n  typeArguments: ['0x1::aptos_coin::AptosCoin'],\n  account: Account.fromPrivateKey(...),\n});\n\nconst [balance] = await client.useABI(COIN_ABI).view.balance({\n  functionArguments: ['0x1'],\n  typeArguments: ['0x1::aptos_coin::AptosCoin'],\n});\n```\n\nWhen you input `client.useABI(COIN_ABI).view.` into your IDE, the auto-completion show as below. You could also see the input and output types for the function, all of which are statically inferred from the ABI.\n\n![demo image](./images/surf-hero.gif)\n\n## Quick Start\n\n### Installation\n\n```shell\nnpm i @thalalabs/surf @aptos-labs/ts-sdk\n```\n\nIf you want to use the React Hooks, install the `@aptos-labs/wallet-adapter-react` additionally. Those React Hooks will be moved to a separate package in near future.\n\n### Start\n\nCreate the client:\n\n```TypeScript\nimport { createSurfClient } from '@thalalabs/surf';\nimport { Aptos, Network, AptosConfig } from '@aptos-labs/ts-sdk';\n\nconst client = createSurfClient(new Aptos(\n  new AptosConfig({ network: Network.TESTNET })\n));\n```\n\nSurf infers types from ABI to give you the end-to-end type-safety from your Move contract to your frontend. So firstly, you need to prepare the ABI json object of your contract in TypeScript (You can get ABI from Aptos Explorer, for example: [0x1::coin](https://explorer.aptoslabs.com/account/0x1/modules/code/coin?network=testnet)):\n\n```TypeScript\nconst abi = {…} as const;\n```\n\nIf type inference isn't working, it's likely you forgot to add the const assertion for the object. And make sure that you set `strict` to `true` in your `tsconfig.json` compiler options.\n\n### Call View functions\n\nThere are two ways to call a view function with the client:\n\n```typescript\n// Option 1. Use the `useABI` interface\nconst [balance] = await client.useABI(COIN_ABI).view.balance({\n  functionArguments: ['0x1'],\n  typeArguments: ['0x1::aptos_coin::AptosCoin'],\n  ledgerVersion: '562606728', // ledger_version is optional\n});\n\n// Option 2. Create payload and use the `view` interface\nimport { createViewPayload } from '@thalalabs/surf';\nconst payload = createViewPayload(COIN_ABI, {\n  function: 'balance',\n  functionArguments: ['0x1'],\n  typeArguments: ['0x1::aptos_coin::AptosCoin'],\n  // (optional) you can also override the address in ABI\n  // address: \"0x123\"\n});\nconst [balance] = await client.view({\n  payload,\n  options: { ledgerVersion: '562606728' }, // ledger_version is optional\n});\n```\n\nBoth of the interfaces can provide type safety.\n\nCalling `useABI` returns an object without any ABI parsing, so that the runtime cost is low.\n\n### Submit Transaction\n\nSimilar to the `view` function, there are also two ways to submit transactions.\n\n```typescript\n// prepare your AptosAccount\nconst account = /* your AptosAccount */;\n\n// Option 1. Use the `useABI` interface\nconst { hash } = await client.useABI(COIN_ABI).entry.transfer({\n    functionArguments: ['0x1', 1],\n    typeArguments: ['0x1::aptos_coin::AptosCoin'],\n    account,\n});\n\n// Option 2. Create payload and use the `submitTransaction` interface\nimport { createEntryPayload } from \"@thalalabs/surf\";\nconst payload = createEntryPayload(COIN_ABI, {\n  function: 'transfer',\n  functionArguments: ['0x1', 1],\n  typeArguments: ['0x1::aptos_coin::AptosCoin'],\n  // (optional) you can also override the address in ABI\n  // address: \"0x123\"\n});\nconst result = await client.submitTransaction({\n  payload,\n  signer: account,\n});\n```\n\nYou can also simulate a transaction:\n\n```typescript\n// prepare your AptosAccount\nconst account = /* your AptosAccount */;\n\n// Option 1. Use the `useABI` interface\nconst { hash } = await client.useABI(COIN_ABI).entry.transfer({\n    arguments: ['0x1', 1],\n    type_arguments: ['0x1::aptos_coin::AptosCoin'],\n    account,\n    isSimulation: true,\n});\n\n// Option 2. Create payload and use the `simulateTransaction` interface\nimport { createEntryPayload } from \"@thalalabs/surf\";\nconst entryPayload = createEntryPayload(COIN_ABI, {\n    function: 'transfer',\n    arguments: ['0x1', 1],\n    type_arguments: ['0x1::aptos_coin::AptosCoin'],\n});\n\nconst { hash } = await client.simulateTransaction({\n  payload,\n  sender: account.accountAddress,\n  publicKey: account.publicKey,\n});\n```\n\n### Get account resource\n\nTo get account resource with type safety:\n\n```typescript\nconst { data } = await client.useABI(COIN_ABI).resource.CoinStore({\n  typeArguments: ['0x1::aptos_coin::AptosCoin'],\n  account: '0x1',\n});\n\n// Get property in the struct with type safety\nconsole.log(data.frozen);\n\n// It also works for nested struct type.\n// The `coin` property's type is 0x1::coin::Coin\u003cT0\u003e\nconsole.log(data.coin.value);\n```\n\nSome fields of a stuct may reference external modules.To inference the type of a nested struct, it needs the ABI of the external module. Surf currently only built-in some of the ABIs from 0x1, so that it can inference types like `0x1::coin::Coin`. The type of an unidentifiable field would be `object`. Developer can provide additional modules to Surf like this:\n\n```TypeScript\nimport { DefaultABITable } from \"@thalalabs/surf\";\nimport { createSurfClient } from '@thalalabs/surf';\nimport { Aptos } from '@aptos-labs/ts-sdk';\n\ntype ABITAble = [\n  ...DefaultABITable,\n  ...[\n    typeof FIXED_POINT64_ABI\n  ]\n];\n\nconst client = createSurfClient\u003cABITAble\u003e(new Aptos());\n```\n\nWith this customized `ABITAble`, Surf can inference the struct from `0x4dcae85fc5559071906cd5c76b7420fcbb4b0a92f00ab40ffc394aadbbff5ee9::fixed_point64`.\n\nConsidering the `ABITable` is only been used as a type, it would be stripped out after compiling. So it won't increase the bundle size. You can put the `ABITable` in a separate file and `import type { ABITable } from \"./ABITable.ts\"` to ensure that.\n\n### React Hooks\n\nSurf currently offers two React Hooks: `useWalletClient` and `useSubmitTransaction`. Both require the `@aptos-labs/wallet-adapter-react`. Check out the [example NextJS package](https://github.com/ThalaLabs/surf/blob/main/example/app/page.tsx) for more information.\n\n### Special types\n\nSurf support some special types like `0x1::object::Object`, `0x1::option::Option`. Aptos has specific rule for these types. For example, Aptos accepts hex strings as input for `0x1::object::Object` argument type.\n\n## Design details\n\nLearning more backgrounds and design details from this [blog post](https://thalalabs.medium.com/introducing-surf-type-safe-typescript-interfaces-react-hooks-for-aptos-39527f41bc39).\n\n## TODOs\n\nCompared to [Viem](https://viem.sh/), Surf is still in its infancy. Any contribution is welcome and appreciated. Here are some TODOs:\n\n- [ ] Deploy a dedicated smart contract on the testnet for Surf to run tests that cover all data types. Currently, Surf has some tests running in CI, but they do not cover all types.\n- [ ] Support `struct` types for return values for `view` function.\n- [ ] Accept `Uint8Array` and `string` for `vector\u003cu8\u003e` input. Currently users can pass these values to `createEntryPayload`, and Surf will correctly encode it. But the type system will complain. So users need to use `as any` to pass `Uint8Array` or `string` for `vector\u003cu8\u003e`. The type system only accept `number[]` for `vector\u003cu8\u003e` now.\n- [ ] Add the functionality available in AptosClient to Surf, such as `estimateGasPrice`.\n\n## Showcase\n\n![demo image](./images/surf-hero.gif)\n\n## License\n\nReleased under [MIT](/LICENSE) by [@ThalaLabs](https://github.com/ThalaLabs).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FThalaLabs%2Fsurf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FThalaLabs%2Fsurf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FThalaLabs%2Fsurf/lists"}