synthpunks 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0c5233aa985d25b010831dca85d14e481489665af2e69f428959d4db3a56228
4
- data.tar.gz: 6f1e5ee50bb527fcdc4baa1e82673885a1883d3dc06b982d3c9f018f58045899
3
+ metadata.gz: c0238c880c91ece2f04aaa0f63efd9709c796f135a10b83619a664bd7655fac9
4
+ data.tar.gz: b4ce29e7fcb469c83f6a642f26e5090a35c6e760e504ff87b0ba471452185e98
5
5
  SHA512:
6
- metadata.gz: 90b18b54a84d472b62c0694389ca633b948f0ac45e5f63219f08e7ce63f0994542930e29ad86c6d1a97ae1483d10995c9603aa1fc7c8212d158c139fad5d823d
7
- data.tar.gz: b0e77cb3d73d74a124628ea7da1af8f63c9ed5f5e595dbdffbf1a126e4bc29971236f3a7443006b081a2fbac7efeddbecbb2be49047a6abdf61f1706670f16fd
6
+ metadata.gz: bcc2e2999185747150907e51993ba03b8e55564bcf18d601dbd2f6d8c41b370f2189871ac28e74d0836313d9cc86d0630b4e96f78bc355d2f48f03cfc32f70d6
7
+ data.tar.gz: de49e479e2104a7695854d47617c1796867e4cadd18b4bedca25fb0d77032a9cab9730d647c042bb7501b38dbb483bf9913f5735caa73399e42ea8ec52a4ba8e
data/README.md CHANGED
@@ -11,9 +11,285 @@ synthpunks - (free unlimited) 24×24 pixel punks for everyone - yes, you can - g
11
11
 
12
12
 
13
13
 
14
- ## Usage
14
+ ## What are Synthetic (Crypto) Punks V1?
15
15
 
16
- ...
16
+ > Fully on-chain (crypto) punks for every ethereum address. Check yours out for free!
17
+ >
18
+ > -- [**syntheticpunks.com**](https://syntheticpunks.com)
19
+
20
+
21
+ [Stephan Cilliers](https://github.com/stephancill) (from South Africa)
22
+ has put together an open-source blockchain service ( - see [**stephancill/synthetic-punks**](https://github.com/stephancill/synthetic-punks) - )
23
+ to generate for free¹ 24×24 punk pixel heads for every ethereum address (account).
24
+
25
+ ¹: and optionally clain / mint a (non-fungible) token for a 0.02 ether fee.
26
+
27
+
28
+ The F.A.Q. reads:
29
+
30
+ > Q: What are Synthetic Punks?
31
+ >
32
+ > A: Synthetic Punks is inspired by the historical
33
+ > collection of 10 000 Matt & John's® Punks [Anno 2017]
34
+ > by Larva Labs and Synthetic Loot by Dom Hofmann.
35
+ > It generates a unique, fully on-blockchain punk for each Ethereum address.
36
+ >
37
+ > They are free to view for any address, but can be claimed [minted]
38
+ > as an ERC-721 non-fungible token (NFT)
39
+ > for a price of 0.02 ether.
40
+ >
41
+ > Features - Each Synthetic Punk
42
+ > - Is generated from assets stored fully on-blockchain
43
+ > - Is uniquely associated with an ethereum wallet address
44
+ > - Supports Ethereum Name Service (ENS) in its metadata
45
+
46
+
47
+
48
+
49
+ ## "Off-Chain" Usage In Your Script
50
+
51
+
52
+ Anyways, the synthpunks gem / library is inspired by Synthetic Punks V1
53
+ by Stephan Cilliers (see above)
54
+ and lets you generate punks using the "original"
55
+ Synthetic Punks V1 pseudo-random number and image generation formula
56
+ "off-blockchain"¹
57
+ using the "original" Synthetic Punks V1 spritesheet
58
+
59
+ ![](config/spritesheet.png)
60
+
61
+ and attribute categories (ranges) and names.
62
+
63
+
64
+ Let's try
65
+ the (ethereum) address 0x054f3b6eadc9631ccd60246054fdb0fcfe99b322:
66
+
67
+
68
+ ``` ruby
69
+ require 'synthpunks'
70
+
71
+ punk = Synthpunks::Image.generate('0x054f3b6eadc9631ccd60246054fdb0fcfe99b322' )
72
+ punk.save( 'punk1.png' )
73
+ punk.zoom(8).save( 'punk1@8x.png' )
74
+ ```
75
+
76
+ resulting in:
77
+
78
+ ![](i/punk1.png) 8x
79
+ ![](i/punk1@8x.png)
80
+
81
+
82
+ Tip: Use `Synthpunks.getTokenID( addr )`
83
+ to get the "official" token id
84
+ from the address (that really is only a "convenience" helper that converts the 40-digit / 20-byte hexstring to a decimal (big) integer number). Example:
85
+
86
+ ``` ruby
87
+ Synthpunks.getTokenID('0x054f3b6eadc9631ccd60246054fdb0fcfe99b322' )
88
+ #=> 30311890011735557186986086868537068337617285922
89
+
90
+ # note: yes, Synthpunks.getTokenID same as String#to_i(16)
91
+ '0x054f3b6eadc9631ccd60246054fdb0fcfe99b322'.to_i( 16 )
92
+ #=> 30311890011735557186986086868537068337617285922
93
+ ```
94
+
95
+ And use the new exclusive "off-chain" only `Synthpunks.getAssetNames( id )`
96
+ helper
97
+ to get all (random) punk attributes by name.
98
+
99
+ ``` ruby
100
+ Synthpunks.getAttributeNames( 30311890011735557186986086868537068337617285922 )
101
+ #=> ["Alien", "Clown Nose", "Frown", "Vape", "Eyebrows"]
102
+ ```
103
+
104
+
105
+ Now lookup the minted
106
+ Synthetic (Crypto) Punks V1 on the open sea (secondary)
107
+ market:
108
+
109
+ [Minted Synthetic Punk for 0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf
110
+ with Token ID #30311890011735557186986086868537068337617285922 @ Open Sea](https://opensea.io/assets/ethereum/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf/30311890011735557186986086868537068337617285922)
111
+
112
+ Or see
113
+ [Synthetic Punk for 0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf](https://syntheticpunks.com/#/address/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf)
114
+
115
+
116
+ And spot the differencence - hint: none other
117
+ than the "dark / black-ish" background is missing.
118
+
119
+
120
+ Let's retry and let's add the "dark / black-ish" background
121
+ that is, #1A1A1A, using the rgb hex color code:
122
+
123
+ ``` ruby
124
+ punk = Synthpunks::Image.generate('0x054f3b6eadc9631ccd60246054fdb0fcfe99b322' )
125
+ punk = punk.background( '#1A1A1A' )
126
+ punk.save( 'punk1b.png' )
127
+ punk.zoom(8).save( 'punk1b@8x.png' )
128
+ ```
129
+
130
+ resulting in:
131
+
132
+ ![](i/punk1b.png) 8x
133
+ ![](i/punk1b@8x.png)
134
+
135
+
136
+ Or for fun let's try some more new "custom" backgrounds.
137
+ Example: Stand with Ukraine / Ukraine Flag:
138
+
139
+ ``` ruby
140
+ punk = Synthpunks::Image.generate('0x054f3b6eadc9631ccd60246054fdb0fcfe99b322' )
141
+ punk = punk.background( 'ukraine' )
142
+ punk.save( 'punk1c.png' )
143
+ punk.zoom(8).save( 'punk1c@8x.png' )
144
+ ```
145
+
146
+ resulting in:
147
+
148
+ ![](i/punk1c.png) 8x
149
+ ![](i/punk1c@8x.png)
150
+
151
+
152
+ or
153
+
154
+ ``` ruby
155
+ punk = punk.background( 'rainbow' )
156
+ ```
157
+
158
+ resulting in:
159
+
160
+ ![](i/punk1d.png) 8x
161
+ ![](i/punk1d@8x.png)
162
+
163
+ and so on.
164
+
165
+ Tip: Looking for left-looking phunks? Try `Image#mirror`.
166
+ Example:
167
+
168
+ ``` ruby
169
+ punk = Synthpunks::Image.generate('0x054f3b6eadc9631ccd60246054fdb0fcfe99b322' )
170
+ phunk = punk.mirror
171
+ phunk.save( 'phunk1.png' )
172
+ phunk.zoom(8).save( 'phunk1@8x.png' )
173
+ ```
174
+
175
+ resulting in:
176
+
177
+ ![](i/phunk1.png) 8x
178
+ ![](i/phunk1@8x.png)
179
+
180
+
181
+ Bonus Tip: Derive your own custom default profile pictures
182
+ using `Image#silhouette`. Example:
183
+
184
+
185
+ ``` ruby
186
+ punk = Synthpunks::Image.generate('0x054f3b6eadc9631ccd60246054fdb0fcfe99b322' )
187
+ punk = punk.silhouette( '0x647785' ).background( '0xCCD5DE' )
188
+ punk.save( 'punk1-default1.png' )
189
+ punk.zoom(8).save( 'punk1-default1@8x.png' )
190
+ ```
191
+
192
+ resulting in:
193
+
194
+ ![](i/punk1-default1.png) 8x
195
+ ![](i/punk1-default1@8x.png)
196
+
197
+ or is blue the new gray?
198
+
199
+ ``` ruby
200
+ punk = punk.silhouette( '0x4474E0' ).background( '0xA0C2FF' )
201
+ ```
202
+
203
+ resulting in:
204
+
205
+ ![](i/punk1-default2.png) 8x
206
+ ![](i/punk1-default2@8x.png)
207
+
208
+ and so on.
209
+
210
+
211
+
212
+
213
+ Yes, you can.
214
+ Let's try some more
215
+ the (ethereum) addresses.
216
+
217
+ ``` ruby
218
+ punk = Synthpunks::Image.generate( '0x7a80ee32044f496a7bfef65af738fdda3a02cf02' )
219
+ punk.save( "punk2.png" )
220
+ punk.zoom(8).save( "punk2@8x.png" )
221
+ ```
222
+
223
+ resulting in:
224
+
225
+ ![](i/punk2.png) 8x
226
+ ![](i/punk2@8x.png)
227
+
228
+
229
+ and the attributes
230
+
231
+ ``` ruby
232
+ tokenID = Synthpunks.getTokenID( '0x7a80ee32044f496a7bfef65af738fdda3a02cf02' )
233
+ #=> 699372119169819039191610289391678040975564001026
234
+ Synthpunks.getAttributeNames( tokenID )
235
+ #=> ["Human 1", "Rosy Cheeks", "Shadow Beard", "Wild Hair", "VR"]
236
+ ```
237
+
238
+ and compare with the "original" with the attributes:
239
+ - Human 1
240
+ - Rosy Cheeks
241
+ - Wild Hair
242
+ - VR
243
+ - Shadow Beard
244
+
245
+
246
+ [Minted Synthetic Punk for 0x7a80Ee32044F496A7bFeF65Af738FddA3a02CF02
247
+ with Token ID #699372119169819039191610289391678040975564001026 @ Open Sea](https://opensea.io/assets/ethereum/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf/699372119169819039191610289391678040975564001026)
248
+
249
+ Or see [Synthetic Punk for 0x7a80Ee32044F496A7bFeF65Af738FddA3a02CF02](https://syntheticpunks.com/#/address/0x7a80Ee32044F496A7bFeF65Af738FddA3a02CF02)
250
+
251
+ and so on.
252
+
253
+
254
+
255
+
256
+
257
+
258
+ ¹: Yes, the (on-chain) solidity contract code
259
+ got translated "by-hand" to (off-chain) ruby script.
260
+
261
+ Example - the entropy pseudo-random number generator source:
262
+
263
+ ``` solidity
264
+ function randomUint(uint256 seed, uint256 offset) public view returns (uint256)
265
+ {
266
+ require(offset < 32, "Offset out of bounds");
267
+ bytes32 entropy = keccak256(abi.encodePacked(address(this), seed));
268
+ bytes32 mask = bytes32(0xff << (offset * 8));
269
+ uint256 out = uint256((entropy & mask) >> (offset * 8));
270
+ return out;
271
+ }
272
+ ```
273
+
274
+ and the matching ruby version:
275
+
276
+ ``` ruby
277
+ ADDRESS = '0xaf9CE4B327A3b690ABEA6F78eCCBfeFFfbEa9FDf'
278
+
279
+ ## note:
280
+ ## returns a random unit number between 0-255 (0-ff)
281
+ ## use offset (0-31),that is, byte out of byte32 entropy buffer/hash
282
+
283
+ def randomUint( seed, offset )
284
+ # assert( offset < 32, "Offset out of bounds")
285
+ entropy = keccak256( hex_to_bin( ADDRESS ) +
286
+ hex_to_bin( uint256_to_hex(seed)) )
287
+
288
+ ## note: pick a uint/byte (shorter version)
289
+ bytes = entropy.bytes.reverse
290
+ bytes[offset]
291
+ end
292
+ ```
17
293
 
18
294
 
19
295
 
data/Rakefile CHANGED
@@ -27,6 +27,7 @@ Hoe.spec 'synthpunks' do
27
27
 
28
28
  self.extra_deps = [
29
29
  ['pixelart', '>= 1.3.6'],
30
+ ['backgrounds'],
30
31
  ['etherlite', '>= 0.3.1'],
31
32
  ]
32
33
 
@@ -4,8 +4,8 @@ module Module
4
4
  module Synthpunks
5
5
 
6
6
  MAJOR = 0
7
- MINOR = 0
8
- PATCH = 1
7
+ MINOR = 1
8
+ PATCH = 0
9
9
  VERSION = [MAJOR,MINOR,PATCH].join('.')
10
10
 
11
11
  def self.version
data/lib/synthpunks.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'pixelart'
2
+ require 'backgrounds'
2
3
  require 'ethlite' ## needed for Digest::Keccak (otherwise no dep for now)
3
4
 
4
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synthpunks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.3.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: backgrounds
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: etherlite
29
43
  requirement: !ruby/object:Gem::Requirement