Giter Club home page Giter Club logo

micro-stacks's Introduction

micro-stacks

micro-stacks is an all-in-one TypeScript SDK for interacting with the Stacks ecosystem. With micro-stacks you can build software that can: interact with Clarity, the smart contract langauge on Stacks, build apps that interact with Stacks based wallets, construct transactions, post conditions, and more!

Documentation

Overview ยท Get Started ยท Guides

Features

  • Core has only 2 dependencies (and those have 0)
  • Modular: take what you need, leave what you don't
  • ESM based, works with all modern bundlers
  • Un-opinionated core
  • Robust framework integrations
    • React
    • Svelte (coming soon)
    • Vue (coming soon)
    • React Jotai
  • Built from the ground up to work with Wallet-based authentication
  • Highly typed -- written in typescript
  • Well tested
  • Audited

Monorepo overview

This project is a pnpm monorepo that uses Turbo.

Apps

This is where non-library packages live, such as the docs that live at https://micro-stacks.dev

Packages

All libraries are contained within the packages directory.

Core

This is the main micro-stacks library that contains all the lower level primitives for things like working with Clarity or constructing transactions.

Client

This is another lower level package that any framework specific packages will implement. The client module handles things like interacting with Stacks wallets, subscribing to state changes, etc.

React

This library is the official micro-stacks React bindings. If you're building a React app, you should be using @micro-stacks/react.

Jotai

This library exposes all the functionality and same API as our other framework bindings, but as atoms.

Svelte

This library is the official micro-stacks Svelte bindings. If you're building a Svelte app, you should be using @micro-stacks/svelte.

Vue

This library is the official micro-stacks Vue bindings. If you're building a Vue app, you should be using @micro-stacks/vue.

Solid.js

This library is the official micro-stacks Solid.js bindings. If you're building a Solid.js app, you should be using @micro-stacks/solidjs.

Community

stars downloads license

micro-stacks is created and maintained by Fungible Systems, a web3-focused design and engineering studio.

Follow @FungibleSystems on Twitter for updates and memes :~)

micro-stacks's People

Contributors

aslemammad avatar aulneau avatar aviculturist avatar dependabot[bot] avatar github-actions[bot] avatar hstove avatar pradel avatar whoabuddy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

micro-stacks's Issues

buildMicroStacksAtoms not bootstrapping provider pattern in 0.0.36?

Since the upgrade to "micro-stacks": "0.0.36", the authentication pattern previously used in bird-count fails with the error Uncaught (in promise) Error: [useAuthenticate] No authOptions provided. when the user attempts to connect wallet.

There was a naming convention change in micro-stacks from appProviderAtomBuilder to buildMicroStacksAtoms. However, simply making that change isn't enough to get authentication working.

On discord you mentioned the error may mean that it's being used outside of a micro-stacks provider pattern and that it has to be a child of the provider. I thought that the buildMicroStacksAtoms would be how that provider wrapped everything, but perhaps I'm misunderstanding how the new pattern is supposed to work.

What works in earlier versions of micro-stacks for static generation:

// enable SSG
export const getStaticProps = getStaticQueryProps(getQueries)(async _ctx => {
  return { props: {}, revalidate: 60 };
});

...

export default withInitialQueryData(
  Index,
  buildMicroStacksAtoms({
    network: initialNetwork,
    authOptions: {
      appDetails: {
        name: 'BirdCount',
        icon: './stx-favicon.png',
      },
    },
  })
);

https://github.com/aviculturist/bird-count/blob/e81cfe39b74ad418c1e5df22e912d39b9589f430/src/pages/index.tsx#L82

Add hook to hold profile

UserData contains the profile url, however, it would be nice to have a hook that contains the actual profile fetched from the profile url.

how to make an authenticate button?

I'm trying to build a simple auth button, similar to this
https://github.com/hirosystems/nft-nyc-exclusive-app/blob/master/components/auth.js

however getting this error below.

I log the values passed to the hook before calling it and they are there...

image

on further details it seems I can't pass params into the function, I have to stash them in a jotai atom.
I couldn't quite figure out how to do this, is there an example?
Or is there another component I can use to just pass the params directly?

I saw other docs to wrap everything in MicroStacksProvider, but that doesn't exist now?

// import { MicroStacksProvider } from '@micro-stacks/react'; // does not exist

import { Text, Center, VStack, Button, Link } from '@chakra-ui/react';
import { useAuth } from '@micro-stacks/react';

// import  { MicroStacksProvider } from '@micro-stacks/react';  // does not exist
interface AuthOptions {
  // onFinish?: (payload: StacksSessionState) => void;
  onFinish?: any
  onCancel?: (error?: Error) => void;
  onSignOut?: () => void;
  // scopes?: AuthScope[];
  appDetails: AppDetails;
}

interface AppDetails {
  name: string;
  icon: string;
}

export const AuthenticateButton = () => {
  const { handleSignIn, isLoading } = useAuth();

  const appDetails: AppDetails = {
    name: 'Minter',
    icon: '/assets/astro/zodiac-200.png',
  }

  const authOptions: AuthOptions = {
    appDetails,
    onFinish: (payload: any) => {
      console.log('onFinish', payload);
    }
  }

  const doSignIn = () => {
    console.log('doSignIn.authOptions', authOptions);
    // @ts-ignore
    handleSignIn(authOptions)
  }

  return (
    <Center>
      <VStack>

        <Button
          size='lg'
          p={10}
          onClick={doSignIn}
        >
          <Text>Sign in</Text>
        </Button>
      </VStack>
    </Center>
  )
}


export default AuthenticateButton;

de-serialization?

you have some docs on
https://docs.micro-stacks.dev/modules/core/clarity/serialization

do you have examples of how to decode the data coming back from the APIs?
eg i sent a buffer in and returns

{
  type: '(optional (buff 64))',
  value: {
    type: '(buff 64)',
    value: '0x36333562663261376537333436376636333363313931353738613938383137313663383633306235373164613034643634303334356331646232333231636537'
  }
}

any docs on how to convert that to a useful value?

Open contract call and web wallet not aligned on network

Versions:
"micro-stacks": "^1.1.1",
"@micro-stacks/svelte": "^1.0.3",

Configure the network to be 'testnet' with the hiro web wallet connected to mainnet.

    const config = {
      appName: 'Ecosystem DAO',
      appIconUrl: origin + '/img/logo.png',
      network: 'testnet'
    };
    mountClient(config)

On openContractCall, the wallet opens connected to 'testnet' but looks up the contract on mainnet leading to screen shot;

Screenshot 2022-08-24 at 15 01 54

If I repeat but change the network in the web wallet I get the correct behaviour - i.e. the web wallet looks up the contract on correct network.

The contract is deployed here https://explorer.stacks.co/txid/1f5c4ce7187fa1949be5911aa5dfc2c0b7d4c9a012f75307820c075c9a3b351e?chain=testnet

Onboarding API Improvements

When a user arrives on the page, they might try to do something that requires signing into the wallet, even if they don't have the wallet installed. Or they might have the wallet installed but not connected to the site. Or the wallet might be installed and connected, in which case they can proceed.

At the moment, one needs to check isSignedIn, if the user isn't signed in, wrap handleSignIn in a try{}catch{}, but that doesn't actually return anything, so thereafter, one needs to check the session as returned from useAuth and if it's null, prompt the user to install the wallet.

I've got a mockup implementation that I believe covers all these onboarding scenarios but it would be cleaner if it were handled directly in the API

https://github.com/aviculturist/bird-count/blob/e54272466f3444d65cf3e0798df3568dc21eb008/src/components/bird-count-buttongroup.tsx#L64

isLoading state not accessible to outside components

This might be me not understanding the rules.

Background: if you've got a wallet button component useAuth returns a boolean in isLoading that will correctly change button state like this:

{isLoading ? "Loading..." : isSignedIn ? "Sign out" : "Connect Stacks Wallet"}

Problem: isLoading won't provide its state to another component.

Here's an example. If one sets open to true within the LoadingBackdrop component, the backdrop will display, but when one opens the wallet (which means isLoading=true it doesn't display. If one moves the Loading inside the same component as the button, it works.

LoadingBackdrop component:
https://github.com/aviculturist/bird-count/blob/e54272466f3444d65cf3e0798df3568dc21eb008/src/components/loading-backdrop.tsx#L18

WalletConnectButton:
https://github.com/aviculturist/bird-count/blob/e54272466f3444d65cf3e0798df3568dc21eb008/src/components/wallet-connect-button.tsx#L30

Where LoadingBackdrop is placed on the page:
https://github.com/aviculturist/bird-count/blob/e54272466f3444d65cf3e0798df3568dc21eb008/src/components/bird-count-app.tsx#L115

micro-stacks.store value always has Mainnet address

micro-stacks.store local storage value always has Mainnet address, even if there's both network="testnet" supplied to ClientProvider and Hiro Wallet signs in to Testnet. Same for ClientProvider onPersistState dehydratedState, so it seems impossible to SSR correctly on Testnet becauseuseAccount stxAddress is always the Mainnet one (even though useNetwork isMainnet is correctly false).

getPublicKeyFromSignature should allow compressed=true to be passed.

Using:
"micro-stacks": "^1.1.4",
"@noble/secp256k1": "^1.7.1"

Comparing getPublicKeyFromSignature from "micro-stacks/connect" to recoverPublicKey from '@noble/secp256k1'

The latter allows the flag compressed=true to be passed whereas the former hard codes it to false.

The recoverPublicKey recovers the correct pubkey / stxAddress from a signature signed with getOpenSignMessage from '@micro-stacks/svelte whereas incorrect pubkey returned from getPublicKeyFromSignature .

[BUG] useAccount hook only returns mainnet stxAddress

Description: When logging in using testnet the useAccount hook will only return the mainnet stxAddress.

Steps to reproduce:

  1. Initialize a new microstacks template project
  2. Login using a test net account
  3. Observe account address

Im attaching some images from the microstacks template app:

Screenshot 2022-09-08 at 19 47 58

Screenshot 2022-09-08 at 19 48 35

Devnet (Clarinet Integrate) not supported by $contractCall.openContractCall

Regardless of how I set the network in my svelte application the web wallet ignores the fact that I should be connected to devnet / localhost.

Versions:

    "@micro-stacks/svelte": "^1.0.3",
    "micro-stacks": "^1.1.1",

E.g.

Screenshot 2022-08-24 at 14 09 42

In following config I've tried not passing network and passing various other values; 'local', 'mocknet', 'devnet' etc also a new StacksMocknet() from micro-stacks/network

    const config = {
      appName: 'Ecosystem DAO',
      appIconUrl: origin + '/img/logo.png',
      //network: ChainUtils.network()
    };
    mountClient(config)

in all cases the following

await $contractCall.openContractCall({
    postConditions: [],
    postConditionMode: PostConditionMode.Deny,
    contractAddress: deployer,
    contractName: 'executor-dao',
    functionName: 'construct',
    functionArgs: [bootstrap],
    onFinish: data => {
      console.log('finished contract call!', data);
      txId = data.txId;
    },
    onCancel: () => {
      console.log('popup closed!');
    },
  });

opens with the web wallet connected to the Hiro testnet (as opposed to local devnet)..

Screenshot 2022-08-24 at 14 13 00

`createSTXPostCondition` and `createFungiblePostCondition` allows to create invalid post conditions.

Both createSTXPostCondition and createFungiblePostCondition accepts values higher than 18446744073709551615 (max value of u64) and as a result they produce invalid post-conditions.

From https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md

A STX post condition body is encoded as follows:

...
An 8-byte value encoding the literal number of microSTX

A Fungible token post-condition body is encoded as follows:

...
An 8-byte value encoding the literal number of token units

8-byte value (u64) not 16-byte value (u128)

hexToBytes should accept and trim strings with leading `0x`

This started with testing a simple Clarity contract that can stack its own STX through pool delegation.

The Short Story

Would there be an issue if the hexToBytes function were to check if the string starts with 0x, and remove it before processing the string?

Happy to submit a PR! ๐Ÿš€

The Long Story

There were two function parameters that needed to be (buff 1) and (buff 20) to represent the pox address in delegate-stx.

The hex values were each stored in a constant:
(incorrect code below for illustration)

const poxVer = "0x01";
const poxHash = "0x13effebe0ea4bb45e35694f5a15bb5b96e851afb";

My first instinct was to use bufferCVFromString() on these two values, but the buffers were not the correct length as they were literally processing the string and returning (buff 3) and (buff 40). This made makeContractCall() fail with the tx options.

Next step was @friedger's suggestion to use bufferCV() and hexToBytes(), and after passing the string the contract call would be created but the broadcastTransaction() step would fail due to BadFunctionArguments.

After updating the constant to remove the leading 0x everything worked as expected, but it was quite the fight to get there and identify each problem.
(correct code below)

const poxVer = "01";
const poxHash = "13effebe0ea4bb45e35694f5a15bb5b96e851afb";

Relevant TX:
https://explorer.stacks.co/txid/0xdbbecf8113b530bd12ca67c425cc1c27a0bf7916ded65e106cf0ecc8fb28c75a?chain=mainnet

Create a bettter "create stacks app" builder

I created a basic create ustx cli based off vite-create, but in talking with @hstove it would be better to have some kind of CLI that would let folks scaffold out a more complete starter where you take different features. Initially, this is what I was thinking:

  • pick a framework
    • react
      • next.js
      • remix
      • SPA
    • vue
      • nuxt
      • SPA
    • svelte
      • sveltekit
      • SPA
    • solid
  • pick a language
    • JS
    • TS
  • include sponsored tx api?
  • clarinet wrapper

Basically, we need a CLI tool that can merge multiple different types of projects together.

HowTo: Save data to DB

I'd love a guide on how to save data; both to decentralized storage such as Gaia as well as centralized storage through an ORM such as Prisma.

Wallet connect integration

Now that xverse supports wallet connect on mobile, would love to see it integrated in micro-stacks to let our users connect easily.

lookupProfile throwing an error but working in stacks.js

Hey found an issue that started to pop in the last weeks but didn't see it was related to micro-stacks at first. For information the same code is working fine with stacks.js. Not sure if it could be related to an API change for stacks 2.1?
We are using micro-stacks in Sigle server-side and found this issue which makes us unable to resolve some usernames to the gaia config.

Error: TypeError: Failed to parse URL from https://.

Reproducing example

https://codesandbox.io/p/sandbox/quiet-frog-rb4gqp?file=%2Findex.js&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A13%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A13%7D%5D

const { lookupProfile: stacksLookupProfile } = require("@stacks/auth");
const { lookupProfile: microLookupProfile } = require("micro-stacks/storage");

const run = async () => {
  const data = await stacksLookupProfile({ username: "sigle.btc" });
 // Working fine
  console.log(data);

  const data2 = await microLookupProfile({ username: "sigle.btc" });
// throwing an error but should work fine
  console.log(data2);
};

run();

Support new Connect flows

I think @kyranjamie could provide more details, but there have been some recent changes to @stacks/connect to support signing in using a ledger device. This relates to signing the JWT used in transactionRequest and similar calls to the web wallet, and the app doesn't have appPrivateKey in that instance.

Relevant commit in Connect: hirosystems/connect@e7aae49

I'm not super familiar with the latest on this, I just wanted to post this as a placeholder and FYI. More details in this thread: leather-wallet/extension#951 (comment)

fetchContractDataMapEntry fails with JSON error

  const lookup_key = { "key": cvToHex(uintCV(asset_id)) }
  
  const mapEntry = await fetchContractDataMapEntry({
    url: network.getCoreApiUrl(),
    contract_name,
    contract_address,
    map_name,
    lookup_key
  });

fails with SyntaxError: Unexpected end of JSON input at line 0, col 0

Not sure if this is my lookup_key, but it appears that the body being sent to the api is not being set as application/json.

const body = lookup_key;
const path = generateUrl(
`${v2Endpoint(url)}/map_entry/${contract_address}/${contract_name}/${map_name}`,
{ proof: proof, tip: tip }
);
return fetchJsonPost<MapEntryResponse>(path, { body });

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.